diff options
Diffstat (limited to 'src/include')
788 files changed, 148166 insertions, 0 deletions
diff --git a/src/include/.gitignore b/src/include/.gitignore new file mode 100644 index 0000000..51819fb --- /dev/null +++ b/src/include/.gitignore @@ -0,0 +1,5 @@ +/stamp-h +/stamp-ext-h +/pg_config.h +/pg_config_ext.h +/pg_config_os.h diff --git a/src/include/Makefile b/src/include/Makefile new file mode 100644 index 0000000..5f257a9 --- /dev/null +++ b/src/include/Makefile @@ -0,0 +1,86 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/include +# +# 'make install' installs whole contents of src/include. +# +# src/include/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/include +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global + + +all: pg_config.h pg_config_ext.h pg_config_os.h + + +# Subdirectories containing installable headers +SUBDIRS = access bootstrap catalog commands common datatype \ + executor fe_utils foreign jit \ + lib libpq mb nodes optimizer parser partitioning postmaster \ + regex replication rewrite \ + statistics storage tcop snowball snowball/libstemmer tsearch \ + tsearch/dicts utils port port/atomics port/win32 port/win32_msvc \ + port/win32_msvc/sys port/win32/arpa port/win32/netinet \ + port/win32/sys portability + +# Install all headers +install: all installdirs +# These headers are needed by the public headers of the interfaces. + $(INSTALL_DATA) $(srcdir)/postgres_ext.h '$(DESTDIR)$(includedir)' + $(INSTALL_DATA) $(srcdir)/libpq/libpq-fs.h '$(DESTDIR)$(includedir)/libpq' + $(INSTALL_DATA) pg_config.h '$(DESTDIR)$(includedir)' + $(INSTALL_DATA) pg_config_ext.h '$(DESTDIR)$(includedir)' + $(INSTALL_DATA) pg_config_os.h '$(DESTDIR)$(includedir)' + $(INSTALL_DATA) $(srcdir)/pg_config_manual.h '$(DESTDIR)$(includedir)' +# These headers are needed by the not-so-public headers of the interfaces. + $(INSTALL_DATA) $(srcdir)/c.h '$(DESTDIR)$(includedir_internal)' + $(INSTALL_DATA) $(srcdir)/port.h '$(DESTDIR)$(includedir_internal)' + $(INSTALL_DATA) $(srcdir)/postgres_fe.h '$(DESTDIR)$(includedir_internal)' + $(INSTALL_DATA) $(srcdir)/libpq/pqcomm.h '$(DESTDIR)$(includedir_internal)/libpq' +# These headers are needed for server-side development + $(INSTALL_DATA) pg_config.h '$(DESTDIR)$(includedir_server)' + $(INSTALL_DATA) pg_config_ext.h '$(DESTDIR)$(includedir_server)' + $(INSTALL_DATA) pg_config_os.h '$(DESTDIR)$(includedir_server)' + $(INSTALL_DATA) utils/errcodes.h '$(DESTDIR)$(includedir_server)/utils' + $(INSTALL_DATA) utils/fmgroids.h '$(DESTDIR)$(includedir_server)/utils' + $(INSTALL_DATA) utils/fmgrprotos.h '$(DESTDIR)$(includedir_server)/utils' +# We don't use INSTALL_DATA for performance reasons --- there are a lot of files +# (in fact, we have to take some pains to avoid overlength shell commands here) + cp $(srcdir)/*.h '$(DESTDIR)$(includedir_server)'/ + for dir in $(SUBDIRS); do \ + cp $(srcdir)/$$dir/*.h '$(DESTDIR)$(includedir_server)'/$$dir/ || exit; \ + done +ifeq ($(vpath_build),yes) + for file in catalog/schemapg.h catalog/system_fk_info.h catalog/pg_*_d.h parser/gram.h storage/lwlocknames.h utils/probes.h; do \ + cp $$file '$(DESTDIR)$(includedir_server)'/$$file || exit; \ + done +endif + cd '$(DESTDIR)$(includedir_server)' && chmod $(INSTALL_DATA_MODE) *.h + for dir in $(SUBDIRS); do \ + cd '$(DESTDIR)$(includedir_server)'/$$dir || exit; \ + chmod $(INSTALL_DATA_MODE) *.h || exit; \ + done + +installdirs: + $(MKDIR_P) '$(DESTDIR)$(includedir)/libpq' '$(DESTDIR)$(includedir_internal)/libpq' + $(MKDIR_P) $(addprefix '$(DESTDIR)$(includedir_server)'/, $(SUBDIRS)) + + +uninstall: + rm -f $(addprefix '$(DESTDIR)$(includedir)'/, pg_config.h pg_config_ext.h pg_config_os.h pg_config_manual.h postgres_ext.h libpq/libpq-fs.h) + rm -f $(addprefix '$(DESTDIR)$(includedir_internal)'/, c.h port.h postgres_fe.h libpq/pqcomm.h) +# heuristic... + rm -rf $(addprefix '$(DESTDIR)$(includedir_server)'/, $(SUBDIRS) *.h) + + +clean: + rm -f utils/fmgroids.h utils/fmgrprotos.h utils/errcodes.h utils/header-stamp + rm -f parser/gram.h storage/lwlocknames.h utils/probes.h + rm -f catalog/schemapg.h catalog/system_fk_info.h + rm -f catalog/pg_*_d.h catalog/header-stamp + +distclean maintainer-clean: clean + rm -f pg_config.h pg_config_ext.h pg_config_os.h stamp-h stamp-ext-h diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h new file mode 100644 index 0000000..1dc674d --- /dev/null +++ b/src/include/access/amapi.h @@ -0,0 +1,290 @@ +/*------------------------------------------------------------------------- + * + * amapi.h + * API for Postgres index access methods. + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * src/include/access/amapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef AMAPI_H +#define AMAPI_H + +#include "access/genam.h" + +/* + * We don't wish to include planner header files here, since most of an index + * AM's implementation isn't concerned with those data structures. To allow + * declaring amcostestimate_function here, use forward struct references. + */ +struct PlannerInfo; +struct IndexPath; + +/* Likewise, this file shouldn't depend on execnodes.h. */ +struct IndexInfo; + + +/* + * Properties for amproperty API. This list covers properties known to the + * core code, but an index AM can define its own properties, by matching the + * string property name. + */ +typedef enum IndexAMProperty +{ + AMPROP_UNKNOWN = 0, /* anything not known to core code */ + AMPROP_ASC, /* column properties */ + AMPROP_DESC, + AMPROP_NULLS_FIRST, + AMPROP_NULLS_LAST, + AMPROP_ORDERABLE, + AMPROP_DISTANCE_ORDERABLE, + AMPROP_RETURNABLE, + AMPROP_SEARCH_ARRAY, + AMPROP_SEARCH_NULLS, + AMPROP_CLUSTERABLE, /* index properties */ + AMPROP_INDEX_SCAN, + AMPROP_BITMAP_SCAN, + AMPROP_BACKWARD_SCAN, + AMPROP_CAN_ORDER, /* AM properties */ + AMPROP_CAN_UNIQUE, + AMPROP_CAN_MULTI_COL, + AMPROP_CAN_EXCLUDE, + AMPROP_CAN_INCLUDE +} IndexAMProperty; + +/* + * We use lists of this struct type to keep track of both operators and + * support functions while building or adding to an opclass or opfamily. + * amadjustmembers functions receive lists of these structs, and are allowed + * to alter their "ref" fields. + * + * The "ref" fields define how the pg_amop or pg_amproc entry should depend + * on the associated objects (that is, which dependency type to use, and + * which opclass or opfamily it should depend on). + * + * If ref_is_hard is true, the entry will have a NORMAL dependency on the + * operator or support func, and an INTERNAL dependency on the opclass or + * opfamily. This forces the opclass or opfamily to be dropped if the + * operator or support func is dropped, and requires the CASCADE option + * to do so. Nor will ALTER OPERATOR FAMILY DROP be allowed. This is + * the right behavior for objects that are essential to an opclass. + * + * If ref_is_hard is false, the entry will have an AUTO dependency on the + * operator or support func, and also an AUTO dependency on the opclass or + * opfamily. This allows ALTER OPERATOR FAMILY DROP, and causes that to + * happen automatically if the operator or support func is dropped. This + * is the right behavior for inessential ("loose") objects. + */ +typedef struct OpFamilyMember +{ + bool is_func; /* is this an operator, or support func? */ + Oid object; /* operator or support func's OID */ + int number; /* strategy or support func number */ + Oid lefttype; /* lefttype */ + Oid righttype; /* righttype */ + Oid sortfamily; /* ordering operator's sort opfamily, or 0 */ + bool ref_is_hard; /* hard or soft dependency? */ + bool ref_is_family; /* is dependency on opclass or opfamily? */ + Oid refobjid; /* OID of opclass or opfamily */ +} OpFamilyMember; + + +/* + * Callback function signatures --- see indexam.sgml for more info. + */ + +/* build new index */ +typedef IndexBuildResult *(*ambuild_function) (Relation heapRelation, + Relation indexRelation, + struct IndexInfo *indexInfo); + +/* build empty index */ +typedef void (*ambuildempty_function) (Relation indexRelation); + +/* insert this tuple */ +typedef bool (*aminsert_function) (Relation indexRelation, + Datum *values, + bool *isnull, + ItemPointer heap_tid, + Relation heapRelation, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); + +/* bulk delete */ +typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); + +/* post-VACUUM cleanup */ +typedef IndexBulkDeleteResult *(*amvacuumcleanup_function) (IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); + +/* can indexscan return IndexTuples? */ +typedef bool (*amcanreturn_function) (Relation indexRelation, int attno); + +/* estimate cost of an indexscan */ +typedef void (*amcostestimate_function) (struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); + +/* parse index reloptions */ +typedef bytea *(*amoptions_function) (Datum reloptions, + bool validate); + +/* report AM, index, or index column property */ +typedef bool (*amproperty_function) (Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull); + +/* name of phase as used in progress reporting */ +typedef char *(*ambuildphasename_function) (int64 phasenum); + +/* validate definition of an opclass for this AM */ +typedef bool (*amvalidate_function) (Oid opclassoid); + +/* validate operators and support functions to be added to an opclass/family */ +typedef void (*amadjustmembers_function) (Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +/* prepare for index scan */ +typedef IndexScanDesc (*ambeginscan_function) (Relation indexRelation, + int nkeys, + int norderbys); + +/* (re)start index scan */ +typedef void (*amrescan_function) (IndexScanDesc scan, + ScanKey keys, + int nkeys, + ScanKey orderbys, + int norderbys); + +/* next valid tuple */ +typedef bool (*amgettuple_function) (IndexScanDesc scan, + ScanDirection direction); + +/* fetch all valid tuples */ +typedef int64 (*amgetbitmap_function) (IndexScanDesc scan, + TIDBitmap *tbm); + +/* end index scan */ +typedef void (*amendscan_function) (IndexScanDesc scan); + +/* mark current scan position */ +typedef void (*ammarkpos_function) (IndexScanDesc scan); + +/* restore marked scan position */ +typedef void (*amrestrpos_function) (IndexScanDesc scan); + +/* + * Callback function signatures - for parallel index scans. + */ + +/* estimate size of parallel scan descriptor */ +typedef Size (*amestimateparallelscan_function) (void); + +/* prepare for parallel index scan */ +typedef void (*aminitparallelscan_function) (void *target); + +/* (re)start parallel index scan */ +typedef void (*amparallelrescan_function) (IndexScanDesc scan); + +/* + * API struct for an index AM. Note this must be stored in a single palloc'd + * chunk of memory. + */ +typedef struct IndexAmRoutine +{ + NodeTag type; + + /* + * Total number of strategies (operators) by which we can traverse/search + * this AM. Zero if AM does not have a fixed set of strategy assignments. + */ + uint16 amstrategies; + /* total number of support functions that this AM uses */ + uint16 amsupport; + /* opclass options support function number or 0 */ + uint16 amoptsprocnum; + /* does AM support ORDER BY indexed column's value? */ + bool amcanorder; + /* does AM support ORDER BY result of an operator on indexed column? */ + bool amcanorderbyop; + /* does AM support backward scanning? */ + bool amcanbackward; + /* does AM support UNIQUE indexes? */ + bool amcanunique; + /* does AM support multi-column indexes? */ + bool amcanmulticol; + /* does AM require scans to have a constraint on the first index column? */ + bool amoptionalkey; + /* does AM handle ScalarArrayOpExpr quals? */ + bool amsearcharray; + /* does AM handle IS NULL/IS NOT NULL quals? */ + bool amsearchnulls; + /* can index storage data type differ from column data type? */ + bool amstorage; + /* can an index of this type be clustered on? */ + bool amclusterable; + /* does AM handle predicate locks? */ + bool ampredlocks; + /* does AM support parallel scan? */ + bool amcanparallel; + /* does AM support columns included with clause INCLUDE? */ + bool amcaninclude; + /* does AM use maintenance_work_mem? */ + bool amusemaintenanceworkmem; + /* OR of parallel vacuum flags. See vacuum.h for flags. */ + uint8 amparallelvacuumoptions; + /* type of data stored in index, or InvalidOid if variable */ + Oid amkeytype; + + /* + * If you add new properties to either the above or the below lists, then + * they should also (usually) be exposed via the property API (see + * IndexAMProperty at the top of the file, and utils/adt/amutils.c). + */ + + /* interface functions */ + ambuild_function ambuild; + ambuildempty_function ambuildempty; + aminsert_function aminsert; + ambulkdelete_function ambulkdelete; + amvacuumcleanup_function amvacuumcleanup; + amcanreturn_function amcanreturn; /* can be NULL */ + amcostestimate_function amcostestimate; + amoptions_function amoptions; + amproperty_function amproperty; /* can be NULL */ + ambuildphasename_function ambuildphasename; /* can be NULL */ + amvalidate_function amvalidate; + amadjustmembers_function amadjustmembers; /* can be NULL */ + ambeginscan_function ambeginscan; + amrescan_function amrescan; + amgettuple_function amgettuple; /* can be NULL */ + amgetbitmap_function amgetbitmap; /* can be NULL */ + amendscan_function amendscan; + ammarkpos_function ammarkpos; /* can be NULL */ + amrestrpos_function amrestrpos; /* can be NULL */ + + /* interface functions to support parallel index scans */ + amestimateparallelscan_function amestimateparallelscan; /* can be NULL */ + aminitparallelscan_function aminitparallelscan; /* can be NULL */ + amparallelrescan_function amparallelrescan; /* can be NULL */ +} IndexAmRoutine; + + +/* Functions in access/index/amapi.c */ +extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler); +extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror); + +#endif /* AMAPI_H */ diff --git a/src/include/access/amvalidate.h b/src/include/access/amvalidate.h new file mode 100644 index 0000000..6af5bfb --- /dev/null +++ b/src/include/access/amvalidate.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * amvalidate.h + * Support routines for index access methods' amvalidate and + * amadjustmembers functions. + * + * Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/access/amvalidate.h + * + *------------------------------------------------------------------------- + */ +#ifndef AMVALIDATE_H +#define AMVALIDATE_H + +#include "utils/catcache.h" + + +/* Struct returned (in a list) by identify_opfamily_groups() */ +typedef struct OpFamilyOpFuncGroup +{ + Oid lefttype; /* amoplefttype/amproclefttype */ + Oid righttype; /* amoprighttype/amprocrighttype */ + uint64 operatorset; /* bitmask of operators with these types */ + uint64 functionset; /* bitmask of support funcs with these types */ +} OpFamilyOpFuncGroup; + + +/* Functions in access/index/amvalidate.c */ +extern List *identify_opfamily_groups(CatCList *oprlist, CatCList *proclist); +extern bool check_amproc_signature(Oid funcid, Oid restype, bool exact, + int minargs, int maxargs,...); +extern bool check_amoptsproc_signature(Oid funcid); +extern bool check_amop_signature(Oid opno, Oid restype, + Oid lefttype, Oid righttype); +extern Oid opclass_for_family_datatype(Oid amoid, Oid opfamilyoid, + Oid datatypeoid); +extern bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid); + +#endif /* AMVALIDATE_H */ diff --git a/src/include/access/attmap.h b/src/include/access/attmap.h new file mode 100644 index 0000000..3ae40ca --- /dev/null +++ b/src/include/access/attmap.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * attmap.h + * Definitions for PostgreSQL attribute mappings + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/attmap.h + * + *------------------------------------------------------------------------- + */ +#ifndef ATTMAP_H +#define ATTMAP_H + +#include "access/attnum.h" +#include "access/tupdesc.h" + +/* + * Attribute mapping structure + * + * This maps attribute numbers between a pair of relations, designated + * 'input' and 'output' (most typically inheritance parent and child + * relations), whose common columns may have different attribute numbers. + * Such difference may arise due to the columns being ordered differently + * in the two relations or the two relations having dropped columns at + * different positions. + * + * 'maplen' is set to the number of attributes of the 'output' relation, + * taking into account any of its dropped attributes, with the corresponding + * elements of the 'attnums' array set to 0. + */ +typedef struct AttrMap +{ + AttrNumber *attnums; + int maplen; +} AttrMap; + +extern AttrMap *make_attrmap(int maplen); +extern void free_attrmap(AttrMap *map); + +/* Conversion routines to build mappings */ +extern AttrMap *build_attrmap_by_name(TupleDesc indesc, + TupleDesc outdesc); +extern AttrMap *build_attrmap_by_name_if_req(TupleDesc indesc, + TupleDesc outdesc); +extern AttrMap *build_attrmap_by_position(TupleDesc indesc, + TupleDesc outdesc, + const char *msg); + +#endif /* ATTMAP_H */ diff --git a/src/include/access/attnum.h b/src/include/access/attnum.h new file mode 100644 index 0000000..508c583 --- /dev/null +++ b/src/include/access/attnum.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * attnum.h + * POSTGRES attribute number definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/attnum.h + * + *------------------------------------------------------------------------- + */ +#ifndef ATTNUM_H +#define ATTNUM_H + + +/* + * user defined attribute numbers start at 1. -ay 2/95 + */ +typedef int16 AttrNumber; + +#define InvalidAttrNumber 0 +#define MaxAttrNumber 32767 + +/* ---------------- + * support macros + * ---------------- + */ +/* + * AttributeNumberIsValid + * True iff the attribute number is valid. + */ +#define AttributeNumberIsValid(attributeNumber) \ + ((bool) ((attributeNumber) != InvalidAttrNumber)) + +/* + * AttrNumberIsForUserDefinedAttr + * True iff the attribute number corresponds to a user defined attribute. + */ +#define AttrNumberIsForUserDefinedAttr(attributeNumber) \ + ((bool) ((attributeNumber) > 0)) + +/* + * AttrNumberGetAttrOffset + * Returns the attribute offset for an attribute number. + * + * Note: + * Assumes the attribute number is for a user defined attribute. + */ +#define AttrNumberGetAttrOffset(attNum) \ +( \ + AssertMacro(AttrNumberIsForUserDefinedAttr(attNum)), \ + ((attNum) - 1) \ +) + +/* + * AttrOffsetGetAttrNumber + * Returns the attribute number for an attribute offset. + */ +#define AttrOffsetGetAttrNumber(attributeOffset) \ + ((AttrNumber) (1 + (attributeOffset))) + +#endif /* ATTNUM_H */ diff --git a/src/include/access/brin.h b/src/include/access/brin.h new file mode 100644 index 0000000..887fb0a --- /dev/null +++ b/src/include/access/brin.h @@ -0,0 +1,55 @@ +/* + * AM-callable functions for BRIN indexes + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin.h + */ +#ifndef BRIN_H +#define BRIN_H + +#include "nodes/execnodes.h" +#include "utils/relcache.h" + + +/* + * Storage type for BRIN's reloptions + */ +typedef struct BrinOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + BlockNumber pagesPerRange; + bool autosummarize; +} BrinOptions; + + +/* + * BrinStatsData represents stats data for planner use + */ +typedef struct BrinStatsData +{ + BlockNumber pagesPerRange; + BlockNumber revmapNumPages; +} BrinStatsData; + + +#define BRIN_DEFAULT_PAGES_PER_RANGE 128 +#define BrinGetPagesPerRange(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == BRIN_AM_OID), \ + (relation)->rd_options ? \ + ((BrinOptions *) (relation)->rd_options)->pagesPerRange : \ + BRIN_DEFAULT_PAGES_PER_RANGE) +#define BrinGetAutoSummarize(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == BRIN_AM_OID), \ + (relation)->rd_options ? \ + ((BrinOptions *) (relation)->rd_options)->autosummarize : \ + false) + + +extern void brinGetStats(Relation index, BrinStatsData *stats); + +#endif /* BRIN_H */ diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h new file mode 100644 index 0000000..2518660 --- /dev/null +++ b/src/include/access/brin_internal.h @@ -0,0 +1,115 @@ +/* + * brin_internal.h + * internal declarations for BRIN indexes + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin_internal.h + */ +#ifndef BRIN_INTERNAL_H +#define BRIN_INTERNAL_H + +#include "access/amapi.h" +#include "storage/bufpage.h" +#include "utils/typcache.h" + + +/* + * A BrinDesc is a struct designed to enable decoding a BRIN tuple from the + * on-disk format to an in-memory tuple and vice-versa. + */ + +/* struct returned by "OpcInfo" amproc */ +typedef struct BrinOpcInfo +{ + /* Number of columns stored in an index column of this opclass */ + uint16 oi_nstored; + + /* Regular processing of NULLs in BrinValues? */ + bool oi_regular_nulls; + + /* Opaque pointer for the opclass' private use */ + void *oi_opaque; + + /* Type cache entries of the stored columns */ + TypeCacheEntry *oi_typcache[FLEXIBLE_ARRAY_MEMBER]; +} BrinOpcInfo; + +/* the size of a BrinOpcInfo for the given number of columns */ +#define SizeofBrinOpcInfo(ncols) \ + (offsetof(BrinOpcInfo, oi_typcache) + sizeof(TypeCacheEntry *) * ncols) + +typedef struct BrinDesc +{ + /* Containing memory context */ + MemoryContext bd_context; + + /* the index relation itself */ + Relation bd_index; + + /* tuple descriptor of the index relation */ + TupleDesc bd_tupdesc; + + /* cached copy for on-disk tuples; generated at first use */ + TupleDesc bd_disktdesc; + + /* total number of Datum entries that are stored on-disk for all columns */ + int bd_totalstored; + + /* per-column info; bd_tupdesc->natts entries long */ + BrinOpcInfo *bd_info[FLEXIBLE_ARRAY_MEMBER]; +} BrinDesc; + +/* + * Globally-known function support numbers for BRIN indexes. Individual + * opclasses can define more function support numbers, which must fall into + * BRIN_FIRST_OPTIONAL_PROCNUM .. BRIN_LAST_OPTIONAL_PROCNUM. + */ +#define BRIN_PROCNUM_OPCINFO 1 +#define BRIN_PROCNUM_ADDVALUE 2 +#define BRIN_PROCNUM_CONSISTENT 3 +#define BRIN_PROCNUM_UNION 4 +#define BRIN_MANDATORY_NPROCS 4 +#define BRIN_PROCNUM_OPTIONS 5 /* optional */ +/* procedure numbers up to 10 are reserved for BRIN future expansion */ +#define BRIN_FIRST_OPTIONAL_PROCNUM 11 +#define BRIN_LAST_OPTIONAL_PROCNUM 15 + +#undef BRIN_DEBUG + +#ifdef BRIN_DEBUG +#define BRIN_elog(args) elog args +#else +#define BRIN_elog(args) ((void) 0) +#endif + +/* brin.c */ +extern BrinDesc *brin_build_desc(Relation rel); +extern void brin_free_desc(BrinDesc *bdesc); +extern IndexBuildResult *brinbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void brinbuildempty(Relation index); +extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, + ItemPointer heaptid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); +extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys); +extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void brinendscan(IndexScanDesc scan); +extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bytea *brinoptions(Datum reloptions, bool validate); + +/* brin_validate.c */ +extern bool brinvalidate(Oid opclassoid); + +#endif /* BRIN_INTERNAL_H */ diff --git a/src/include/access/brin_page.h b/src/include/access/brin_page.h new file mode 100644 index 0000000..9b9a39d --- /dev/null +++ b/src/include/access/brin_page.h @@ -0,0 +1,96 @@ +/* + * brin_page.h + * Prototypes and definitions for BRIN page layouts + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin_page.h + * + * NOTES + * + * These structs should really be private to specific BRIN files, but it's + * useful to have them here so that they can be used by pageinspect and similar + * tools. + */ +#ifndef BRIN_PAGE_H +#define BRIN_PAGE_H + +#include "storage/block.h" +#include "storage/itemptr.h" + +/* + * Special area of BRIN pages. + * + * We define it in this odd way so that it always occupies the last + * MAXALIGN-sized element of each page. + */ +typedef struct BrinSpecialSpace +{ + uint16 vector[MAXALIGN(1) / sizeof(uint16)]; +} BrinSpecialSpace; + +/* + * Make the page type be the last half-word in the page, for consumption by + * pg_filedump and similar utilities. We don't really care much about the + * position of the "flags" half-word, but it's simpler to apply a consistent + * rule to both. + * + * See comments above GinPageOpaqueData. + */ +#define BrinPageType(page) \ + (((BrinSpecialSpace *) \ + PageGetSpecialPointer(page))->vector[MAXALIGN(1) / sizeof(uint16) - 1]) + +#define BrinPageFlags(page) \ + (((BrinSpecialSpace *) \ + PageGetSpecialPointer(page))->vector[MAXALIGN(1) / sizeof(uint16) - 2]) + +/* special space on all BRIN pages stores a "type" identifier */ +#define BRIN_PAGETYPE_META 0xF091 +#define BRIN_PAGETYPE_REVMAP 0xF092 +#define BRIN_PAGETYPE_REGULAR 0xF093 + +#define BRIN_IS_META_PAGE(page) (BrinPageType(page) == BRIN_PAGETYPE_META) +#define BRIN_IS_REVMAP_PAGE(page) (BrinPageType(page) == BRIN_PAGETYPE_REVMAP) +#define BRIN_IS_REGULAR_PAGE(page) (BrinPageType(page) == BRIN_PAGETYPE_REGULAR) + +/* flags for BrinSpecialSpace */ +#define BRIN_EVACUATE_PAGE (1 << 0) + + +/* Metapage definitions */ +typedef struct BrinMetaPageData +{ + uint32 brinMagic; + uint32 brinVersion; + BlockNumber pagesPerRange; + BlockNumber lastRevmapPage; +} BrinMetaPageData; + +#define BRIN_CURRENT_VERSION 1 +#define BRIN_META_MAGIC 0xA8109CFA + +#define BRIN_METAPAGE_BLKNO 0 + +/* Definitions for revmap pages */ +typedef struct RevmapContents +{ + /* + * This array will fill all available space on the page. It should be + * declared [FLEXIBLE_ARRAY_MEMBER], but for some reason you can't do that + * in an otherwise-empty struct. + */ + ItemPointerData rm_tids[1]; +} RevmapContents; + +#define REVMAP_CONTENT_SIZE \ + (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \ + offsetof(RevmapContents, rm_tids) - \ + MAXALIGN(sizeof(BrinSpecialSpace))) +/* max num of items in the array */ +#define REVMAP_PAGE_MAXITEMS \ + (REVMAP_CONTENT_SIZE / sizeof(ItemPointerData)) + +#endif /* BRIN_PAGE_H */ diff --git a/src/include/access/brin_pageops.h b/src/include/access/brin_pageops.h new file mode 100644 index 0000000..704de0c --- /dev/null +++ b/src/include/access/brin_pageops.h @@ -0,0 +1,38 @@ +/* + * brin_pageops.h + * Prototypes for operating on BRIN pages. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin_pageops.h + */ +#ifndef BRIN_PAGEOPS_H +#define BRIN_PAGEOPS_H + +#include "access/brin_revmap.h" + +extern bool brin_doupdate(Relation idxrel, BlockNumber pagesPerRange, + BrinRevmap *revmap, BlockNumber heapBlk, + Buffer oldbuf, OffsetNumber oldoff, + const BrinTuple *origtup, Size origsz, + const BrinTuple *newtup, Size newsz, + bool samepage); +extern bool brin_can_do_samepage_update(Buffer buffer, Size origsz, + Size newsz); +extern OffsetNumber brin_doinsert(Relation idxrel, BlockNumber pagesPerRange, + BrinRevmap *revmap, Buffer *buffer, BlockNumber heapBlk, + BrinTuple *tup, Size itemsz); + +extern void brin_page_init(Page page, uint16 type); +extern void brin_metapage_init(Page page, BlockNumber pagesPerRange, + uint16 version); + +extern bool brin_start_evacuating_page(Relation idxRel, Buffer buf); +extern void brin_evacuate_page(Relation idxRel, BlockNumber pagesPerRange, + BrinRevmap *revmap, Buffer buf); + +extern void brin_page_cleanup(Relation idxrel, Buffer buf); + +#endif /* BRIN_PAGEOPS_H */ diff --git a/src/include/access/brin_revmap.h b/src/include/access/brin_revmap.h new file mode 100644 index 0000000..c88a897 --- /dev/null +++ b/src/include/access/brin_revmap.h @@ -0,0 +1,41 @@ +/* + * brin_revmap.h + * Prototypes for BRIN reverse range maps + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin_revmap.h + */ + +#ifndef BRIN_REVMAP_H +#define BRIN_REVMAP_H + +#include "access/brin_tuple.h" +#include "storage/block.h" +#include "storage/buf.h" +#include "storage/itemptr.h" +#include "storage/off.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + +/* struct definition lives in brin_revmap.c */ +typedef struct BrinRevmap BrinRevmap; + +extern BrinRevmap *brinRevmapInitialize(Relation idxrel, + BlockNumber *pagesPerRange, Snapshot snapshot); +extern void brinRevmapTerminate(BrinRevmap *revmap); + +extern void brinRevmapExtend(BrinRevmap *revmap, + BlockNumber heapBlk); +extern Buffer brinLockRevmapPageForUpdate(BrinRevmap *revmap, + BlockNumber heapBlk); +extern void brinSetHeapBlockItemptr(Buffer buf, BlockNumber pagesPerRange, + BlockNumber heapBlk, ItemPointerData tid); +extern BrinTuple *brinGetTupleForHeapBlock(BrinRevmap *revmap, + BlockNumber heapBlk, Buffer *buf, OffsetNumber *off, + Size *size, int mode, Snapshot snapshot); +extern bool brinRevmapDesummarizeRange(Relation idxrel, BlockNumber heapBlk); + +#endif /* BRIN_REVMAP_H */ diff --git a/src/include/access/brin_tuple.h b/src/include/access/brin_tuple.h new file mode 100644 index 0000000..634aa4b --- /dev/null +++ b/src/include/access/brin_tuple.h @@ -0,0 +1,112 @@ +/* + * brin_tuple.h + * Declarations for dealing with BRIN-specific tuples. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/brin_tuple.h + */ +#ifndef BRIN_TUPLE_H +#define BRIN_TUPLE_H + +#include "access/brin_internal.h" +#include "access/tupdesc.h" + +/* + * The BRIN opclasses may register serialization callback, in case the on-disk + * and in-memory representations differ (e.g. for performance reasons). + */ +typedef void (*brin_serialize_callback_type) (BrinDesc *bdesc, Datum src, Datum *dst); + +/* + * A BRIN index stores one index tuple per page range. Each index tuple + * has one BrinValues struct for each indexed column; in turn, each BrinValues + * has (besides the null flags) an array of Datum whose size is determined by + * the opclass. + */ +typedef struct BrinValues +{ + AttrNumber bv_attno; /* index attribute number */ + bool bv_hasnulls; /* are there any nulls in the page range? */ + bool bv_allnulls; /* are all values nulls in the page range? */ + Datum *bv_values; /* current accumulated values */ + Datum bv_mem_value; /* expanded accumulated values */ + MemoryContext bv_context; + brin_serialize_callback_type bv_serialize; +} BrinValues; + +/* + * This struct is used to represent an in-memory index tuple. The values can + * only be meaningfully decoded with an appropriate BrinDesc. + */ +typedef struct BrinMemTuple +{ + bool bt_placeholder; /* this is a placeholder tuple */ + bool bt_empty_range; /* range represents no tuples */ + BlockNumber bt_blkno; /* heap blkno that the tuple is for */ + MemoryContext bt_context; /* memcxt holding the bt_columns values */ + /* output arrays for brin_deform_tuple: */ + Datum *bt_values; /* values array */ + bool *bt_allnulls; /* allnulls array */ + bool *bt_hasnulls; /* hasnulls array */ + /* not an output array, but must be last */ + BrinValues bt_columns[FLEXIBLE_ARRAY_MEMBER]; +} BrinMemTuple; + +/* + * An on-disk BRIN tuple. This is possibly followed by a nulls bitmask, with + * room for 2 null bits (two bits for each indexed column); an opclass-defined + * number of Datum values for each column follow. + */ +typedef struct BrinTuple +{ + /* heap block number that the tuple is for */ + BlockNumber bt_blkno; + + /* --------------- + * bt_info is laid out in the following fashion: + * + * 7th (high) bit: has nulls + * 6th bit: is placeholder tuple + * 5th bit: range is empty + * 4-0 bit: offset of data + * --------------- + */ + uint8 bt_info; +} BrinTuple; + +#define SizeOfBrinTuple (offsetof(BrinTuple, bt_info) + sizeof(uint8)) + +/* + * bt_info manipulation macros + */ +#define BRIN_OFFSET_MASK 0x1F +#define BRIN_EMPTY_RANGE_MASK 0x20 +#define BRIN_PLACEHOLDER_MASK 0x40 +#define BRIN_NULLS_MASK 0x80 + +#define BrinTupleDataOffset(tup) ((Size) (((BrinTuple *) (tup))->bt_info & BRIN_OFFSET_MASK)) +#define BrinTupleHasNulls(tup) (((((BrinTuple *) (tup))->bt_info & BRIN_NULLS_MASK)) != 0) +#define BrinTupleIsPlaceholder(tup) (((((BrinTuple *) (tup))->bt_info & BRIN_PLACEHOLDER_MASK)) != 0) +#define BrinTupleIsEmptyRange(tup) (((((BrinTuple *) (tup))->bt_info & BRIN_EMPTY_RANGE_MASK)) != 0) + + +extern BrinTuple *brin_form_tuple(BrinDesc *brdesc, BlockNumber blkno, + BrinMemTuple *tuple, Size *size); +extern BrinTuple *brin_form_placeholder_tuple(BrinDesc *brdesc, + BlockNumber blkno, Size *size); +extern void brin_free_tuple(BrinTuple *tuple); +extern BrinTuple *brin_copy_tuple(BrinTuple *tuple, Size len, + BrinTuple *dest, Size *destsz); +extern bool brin_tuples_equal(const BrinTuple *a, Size alen, + const BrinTuple *b, Size blen); + +extern BrinMemTuple *brin_new_memtuple(BrinDesc *brdesc); +extern BrinMemTuple *brin_memtuple_initialize(BrinMemTuple *dtuple, + BrinDesc *brdesc); +extern BrinMemTuple *brin_deform_tuple(BrinDesc *brdesc, + BrinTuple *tuple, BrinMemTuple *dMemtuple); + +#endif /* BRIN_TUPLE_H */ diff --git a/src/include/access/brin_xlog.h b/src/include/access/brin_xlog.h new file mode 100644 index 0000000..95bfc7e --- /dev/null +++ b/src/include/access/brin_xlog.h @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * brin_xlog.h + * POSTGRES BRIN access XLOG definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/brin_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef BRIN_XLOG_H +#define BRIN_XLOG_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/bufpage.h" +#include "storage/itemptr.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + + +/* + * WAL record definitions for BRIN's WAL operations + * + * XLOG allows to store some information in high 4 bits of log + * record xl_info field. + */ +#define XLOG_BRIN_CREATE_INDEX 0x00 +#define XLOG_BRIN_INSERT 0x10 +#define XLOG_BRIN_UPDATE 0x20 +#define XLOG_BRIN_SAMEPAGE_UPDATE 0x30 +#define XLOG_BRIN_REVMAP_EXTEND 0x40 +#define XLOG_BRIN_DESUMMARIZE 0x50 + +#define XLOG_BRIN_OPMASK 0x70 +/* + * When we insert the first item on a new page, we restore the entire page in + * redo. + */ +#define XLOG_BRIN_INIT_PAGE 0x80 + +/* + * This is what we need to know about a BRIN index create. + * + * Backup block 0: metapage + */ +typedef struct xl_brin_createidx +{ + BlockNumber pagesPerRange; + uint16 version; +} xl_brin_createidx; +#define SizeOfBrinCreateIdx (offsetof(xl_brin_createidx, version) + sizeof(uint16)) + +/* + * This is what we need to know about a BRIN tuple insert + * + * Backup block 0: main page, block data is the new BrinTuple. + * Backup block 1: revmap page + */ +typedef struct xl_brin_insert +{ + BlockNumber heapBlk; + + /* extra information needed to update the revmap */ + BlockNumber pagesPerRange; + + /* offset number in the main page to insert the tuple to. */ + OffsetNumber offnum; +} xl_brin_insert; + +#define SizeOfBrinInsert (offsetof(xl_brin_insert, offnum) + sizeof(OffsetNumber)) + +/* + * A cross-page update is the same as an insert, but also stores information + * about the old tuple. + * + * Like in xl_brin_insert: + * Backup block 0: new page, block data includes the new BrinTuple. + * Backup block 1: revmap page + * + * And in addition: + * Backup block 2: old page + */ +typedef struct xl_brin_update +{ + /* offset number of old tuple on old page */ + OffsetNumber oldOffnum; + + xl_brin_insert insert; +} xl_brin_update; + +#define SizeOfBrinUpdate (offsetof(xl_brin_update, insert) + SizeOfBrinInsert) + +/* + * This is what we need to know about a BRIN tuple samepage update + * + * Backup block 0: updated page, with new BrinTuple as block data + */ +typedef struct xl_brin_samepage_update +{ + OffsetNumber offnum; +} xl_brin_samepage_update; + +#define SizeOfBrinSamepageUpdate (sizeof(OffsetNumber)) + +/* + * This is what we need to know about a revmap extension + * + * Backup block 0: metapage + * Backup block 1: new revmap page + */ +typedef struct xl_brin_revmap_extend +{ + /* + * XXX: This is actually redundant - the block number is stored as part of + * backup block 1. + */ + BlockNumber targetBlk; +} xl_brin_revmap_extend; + +#define SizeOfBrinRevmapExtend (offsetof(xl_brin_revmap_extend, targetBlk) + \ + sizeof(BlockNumber)) + +/* + * This is what we need to know about a range de-summarization + * + * Backup block 0: revmap page + * Backup block 1: regular page + */ +typedef struct xl_brin_desummarize +{ + BlockNumber pagesPerRange; + /* page number location to set to invalid */ + BlockNumber heapBlk; + /* offset of item to delete in regular index page */ + OffsetNumber regOffset; +} xl_brin_desummarize; + +#define SizeOfBrinDesummarize (offsetof(xl_brin_desummarize, regOffset) + \ + sizeof(OffsetNumber)) + + +extern void brin_redo(XLogReaderState *record); +extern void brin_desc(StringInfo buf, XLogReaderState *record); +extern const char *brin_identify(uint8 info); +extern void brin_mask(char *pagedata, BlockNumber blkno); + +#endif /* BRIN_XLOG_H */ diff --git a/src/include/access/bufmask.h b/src/include/access/bufmask.h new file mode 100644 index 0000000..7ce9f67 --- /dev/null +++ b/src/include/access/bufmask.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * bufmask.h + * Definitions for buffer masking routines, used to mask certain bits + * in a page which can be different when the WAL is generated + * and when the WAL is applied. This is really the job of each + * individual rmgr, but we make things easier by providing some + * common routines to handle cases which occur in multiple rmgrs. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/access/bufmask.h + * + *------------------------------------------------------------------------- + */ + +#ifndef BUFMASK_H +#define BUFMASK_H + +#include "storage/block.h" +#include "storage/bufmgr.h" + +/* Marker used to mask pages consistently */ +#define MASK_MARKER 0 + +extern void mask_page_lsn_and_checksum(Page page); +extern void mask_page_hint_bits(Page page); +extern void mask_unused_space(Page page); +extern void mask_lp_flags(Page page); +extern void mask_page_content(Page page); + +#endif diff --git a/src/include/access/clog.h b/src/include/access/clog.h new file mode 100644 index 0000000..543f2e2 --- /dev/null +++ b/src/include/access/clog.h @@ -0,0 +1,63 @@ +/* + * clog.h + * + * PostgreSQL transaction-commit-log manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/clog.h + */ +#ifndef CLOG_H +#define CLOG_H + +#include "access/xlogreader.h" +#include "storage/sync.h" +#include "lib/stringinfo.h" + +/* + * Possible transaction statuses --- note that all-zeroes is the initial + * state. + * + * A "subcommitted" transaction is a committed subtransaction whose parent + * hasn't committed or aborted yet. + */ +typedef int XidStatus; + +#define TRANSACTION_STATUS_IN_PROGRESS 0x00 +#define TRANSACTION_STATUS_COMMITTED 0x01 +#define TRANSACTION_STATUS_ABORTED 0x02 +#define TRANSACTION_STATUS_SUB_COMMITTED 0x03 + +typedef struct xl_clog_truncate +{ + int pageno; + TransactionId oldestXact; + Oid oldestXactDb; +} xl_clog_truncate; + +extern void TransactionIdSetTreeStatus(TransactionId xid, int nsubxids, + TransactionId *subxids, XidStatus status, XLogRecPtr lsn); +extern XidStatus TransactionIdGetStatus(TransactionId xid, XLogRecPtr *lsn); + +extern Size CLOGShmemBuffers(void); +extern Size CLOGShmemSize(void); +extern void CLOGShmemInit(void); +extern void BootStrapCLOG(void); +extern void StartupCLOG(void); +extern void TrimCLOG(void); +extern void CheckPointCLOG(void); +extern void ExtendCLOG(TransactionId newestXact); +extern void TruncateCLOG(TransactionId oldestXact, Oid oldestxid_datoid); + +extern int clogsyncfiletag(const FileTag *ftag, char *path); + +/* XLOG stuff */ +#define CLOG_ZEROPAGE 0x00 +#define CLOG_TRUNCATE 0x10 + +extern void clog_redo(XLogReaderState *record); +extern void clog_desc(StringInfo buf, XLogReaderState *record); +extern const char *clog_identify(uint8 info); + +#endif /* CLOG_H */ diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h new file mode 100644 index 0000000..7662f8e --- /dev/null +++ b/src/include/access/commit_ts.h @@ -0,0 +1,74 @@ +/* + * commit_ts.h + * + * PostgreSQL commit timestamp manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/commit_ts.h + */ +#ifndef COMMIT_TS_H +#define COMMIT_TS_H + +#include "access/xlog.h" +#include "datatype/timestamp.h" +#include "replication/origin.h" +#include "storage/sync.h" + + +extern PGDLLIMPORT bool track_commit_timestamp; + +extern void TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids, + TransactionId *subxids, TimestampTz timestamp, + RepOriginId nodeid); +extern bool TransactionIdGetCommitTsData(TransactionId xid, + TimestampTz *ts, RepOriginId *nodeid); +extern TransactionId GetLatestCommitTsData(TimestampTz *ts, + RepOriginId *nodeid); + +extern Size CommitTsShmemBuffers(void); +extern Size CommitTsShmemSize(void); +extern void CommitTsShmemInit(void); +extern void BootStrapCommitTs(void); +extern void StartupCommitTs(void); +extern void CommitTsParameterChange(bool newvalue, bool oldvalue); +extern void CompleteCommitTsInitialization(void); +extern void CheckPointCommitTs(void); +extern void ExtendCommitTs(TransactionId newestXact); +extern void TruncateCommitTs(TransactionId oldestXact); +extern void SetCommitTsLimit(TransactionId oldestXact, + TransactionId newestXact); +extern void AdvanceOldestCommitTsXid(TransactionId oldestXact); + +extern int committssyncfiletag(const FileTag *ftag, char *path); + +/* XLOG stuff */ +#define COMMIT_TS_ZEROPAGE 0x00 +#define COMMIT_TS_TRUNCATE 0x10 + +typedef struct xl_commit_ts_set +{ + TimestampTz timestamp; + RepOriginId nodeid; + TransactionId mainxid; + /* subxact Xids follow */ +} xl_commit_ts_set; + +#define SizeOfCommitTsSet (offsetof(xl_commit_ts_set, mainxid) + \ + sizeof(TransactionId)) + +typedef struct xl_commit_ts_truncate +{ + int pageno; + TransactionId oldestXid; +} xl_commit_ts_truncate; + +#define SizeOfCommitTsTruncate (offsetof(xl_commit_ts_truncate, oldestXid) + \ + sizeof(TransactionId)) + +extern void commit_ts_redo(XLogReaderState *record); +extern void commit_ts_desc(StringInfo buf, XLogReaderState *record); +extern const char *commit_ts_identify(uint8 info); + +#endif /* COMMIT_TS_H */ diff --git a/src/include/access/detoast.h b/src/include/access/detoast.h new file mode 100644 index 0000000..b1d8ea0 --- /dev/null +++ b/src/include/access/detoast.h @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------- + * + * detoast.h + * Access to compressed and external varlena values. + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/access/detoast.h + * + *------------------------------------------------------------------------- + */ +#ifndef DETOAST_H +#define DETOAST_H + +/* + * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum + * into a local "struct varatt_external" toast pointer. This should be + * just a memcpy, but some versions of gcc seem to produce broken code + * that assumes the datum contents are aligned. Introducing an explicit + * intermediate "varattrib_1b_e *" variable seems to fix it. + */ +#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \ +do { \ + varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \ + Assert(VARATT_IS_EXTERNAL(attre)); \ + Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \ + memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \ +} while (0) + +/* Size of an EXTERNAL datum that contains a standard TOAST pointer */ +#define TOAST_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_external)) + +/* Size of an EXTERNAL datum that contains an indirection pointer */ +#define INDIRECT_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_indirect)) + +/* ---------- + * detoast_external_attr() - + * + * Fetches an external stored attribute from the toast + * relation. Does NOT decompress it, if stored external + * in compressed format. + * ---------- + */ +extern struct varlena *detoast_external_attr(struct varlena *attr); + +/* ---------- + * detoast_attr() - + * + * Fully detoasts one attribute, fetching and/or decompressing + * it as needed. + * ---------- + */ +extern struct varlena *detoast_attr(struct varlena *attr); + +/* ---------- + * detoast_attr_slice() - + * + * Fetches only the specified portion of an attribute. + * (Handles all cases for attribute storage) + * ---------- + */ +extern struct varlena *detoast_attr_slice(struct varlena *attr, + int32 sliceoffset, + int32 slicelength); + +/* ---------- + * toast_raw_datum_size - + * + * Return the raw (detoasted) size of a varlena datum + * ---------- + */ +extern Size toast_raw_datum_size(Datum value); + +/* ---------- + * toast_datum_size - + * + * Return the storage size of a varlena datum + * ---------- + */ +extern Size toast_datum_size(Datum value); + +#endif /* DETOAST_H */ diff --git a/src/include/access/genam.h b/src/include/access/genam.h new file mode 100644 index 0000000..134b20f --- /dev/null +++ b/src/include/access/genam.h @@ -0,0 +1,231 @@ +/*------------------------------------------------------------------------- + * + * genam.h + * POSTGRES generalized index access method definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/genam.h + * + *------------------------------------------------------------------------- + */ +#ifndef GENAM_H +#define GENAM_H + +#include "access/sdir.h" +#include "access/skey.h" +#include "nodes/tidbitmap.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + +/* We don't want this file to depend on execnodes.h. */ +struct IndexInfo; + +/* + * Struct for statistics returned by ambuild + */ +typedef struct IndexBuildResult +{ + double heap_tuples; /* # of tuples seen in parent table */ + double index_tuples; /* # of tuples inserted into index */ +} IndexBuildResult; + +/* + * Struct for input arguments passed to ambulkdelete and amvacuumcleanup + * + * num_heap_tuples is accurate only when estimated_count is false; + * otherwise it's just an estimate (currently, the estimate is the + * prior value of the relation's pg_class.reltuples field, so it could + * even be -1). It will always just be an estimate during ambulkdelete. + */ +typedef struct IndexVacuumInfo +{ + Relation index; /* the index being vacuumed */ + bool analyze_only; /* ANALYZE (without any actual vacuum) */ + bool report_progress; /* emit progress.h status reports */ + bool estimated_count; /* num_heap_tuples is an estimate */ + int message_level; /* ereport level for progress messages */ + double num_heap_tuples; /* tuples remaining in heap */ + BufferAccessStrategy strategy; /* access strategy for reads */ +} IndexVacuumInfo; + +/* + * Struct for statistics returned by ambulkdelete and amvacuumcleanup + * + * This struct is normally allocated by the first ambulkdelete call and then + * passed along through subsequent ones until amvacuumcleanup; however, + * amvacuumcleanup must be prepared to allocate it in the case where no + * ambulkdelete calls were made (because no tuples needed deletion). + * Note that an index AM could choose to return a larger struct + * of which this is just the first field; this provides a way for ambulkdelete + * to communicate additional private data to amvacuumcleanup. + * + * Note: pages_newly_deleted is the number of pages in the index that were + * deleted by the current vacuum operation. pages_deleted and pages_free + * refer to free space within the index file. + * + * Note: Some index AMs may compute num_index_tuples by reference to + * num_heap_tuples, in which case they should copy the estimated_count field + * from IndexVacuumInfo. + */ +typedef struct IndexBulkDeleteResult +{ + BlockNumber num_pages; /* pages remaining in index */ + bool estimated_count; /* num_index_tuples is an estimate */ + double num_index_tuples; /* tuples remaining */ + double tuples_removed; /* # removed during vacuum operation */ + BlockNumber pages_newly_deleted; /* # pages marked deleted by us */ + BlockNumber pages_deleted; /* # pages marked deleted (could be by us) */ + BlockNumber pages_free; /* # pages available for reuse */ +} IndexBulkDeleteResult; + +/* Typedef for callback function to determine if a tuple is bulk-deletable */ +typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state); + +/* struct definitions appear in relscan.h */ +typedef struct IndexScanDescData *IndexScanDesc; +typedef struct SysScanDescData *SysScanDesc; + +typedef struct ParallelIndexScanDescData *ParallelIndexScanDesc; + +/* + * Enumeration specifying the type of uniqueness check to perform in + * index_insert(). + * + * UNIQUE_CHECK_YES is the traditional Postgres immediate check, possibly + * blocking to see if a conflicting transaction commits. + * + * For deferrable unique constraints, UNIQUE_CHECK_PARTIAL is specified at + * insertion time. The index AM should test if the tuple is unique, but + * should not throw error, block, or prevent the insertion if the tuple + * appears not to be unique. We'll recheck later when it is time for the + * constraint to be enforced. The AM must return true if the tuple is + * known unique, false if it is possibly non-unique. In the "true" case + * it is safe to omit the later recheck. + * + * When it is time to recheck the deferred constraint, a pseudo-insertion + * call is made with UNIQUE_CHECK_EXISTING. The tuple is already in the + * index in this case, so it should not be inserted again. Rather, just + * check for conflicting live tuples (possibly blocking). + */ +typedef enum IndexUniqueCheck +{ + UNIQUE_CHECK_NO, /* Don't do any uniqueness checking */ + UNIQUE_CHECK_YES, /* Enforce uniqueness at insertion time */ + UNIQUE_CHECK_PARTIAL, /* Test uniqueness, but no error */ + UNIQUE_CHECK_EXISTING /* Check if existing tuple is unique */ +} IndexUniqueCheck; + + +/* Nullable "ORDER BY col op const" distance */ +typedef struct IndexOrderByDistance +{ + double value; + bool isnull; +} IndexOrderByDistance; + +/* + * generalized index_ interface routines (in indexam.c) + */ + +/* + * IndexScanIsValid + * True iff the index scan is valid. + */ +#define IndexScanIsValid(scan) PointerIsValid(scan) + +extern Relation index_open(Oid relationId, LOCKMODE lockmode); +extern void index_close(Relation relation, LOCKMODE lockmode); + +extern bool index_insert(Relation indexRelation, + Datum *values, bool *isnull, + ItemPointer heap_t_ctid, + Relation heapRelation, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); + +extern IndexScanDesc index_beginscan(Relation heapRelation, + Relation indexRelation, + Snapshot snapshot, + int nkeys, int norderbys); +extern IndexScanDesc index_beginscan_bitmap(Relation indexRelation, + Snapshot snapshot, + int nkeys); +extern void index_rescan(IndexScanDesc scan, + ScanKey keys, int nkeys, + ScanKey orderbys, int norderbys); +extern void index_endscan(IndexScanDesc scan); +extern void index_markpos(IndexScanDesc scan); +extern void index_restrpos(IndexScanDesc scan); +extern Size index_parallelscan_estimate(Relation indexrel, Snapshot snapshot); +extern void index_parallelscan_initialize(Relation heaprel, Relation indexrel, + Snapshot snapshot, ParallelIndexScanDesc target); +extern void index_parallelrescan(IndexScanDesc scan); +extern IndexScanDesc index_beginscan_parallel(Relation heaprel, + Relation indexrel, int nkeys, int norderbys, + ParallelIndexScanDesc pscan); +extern ItemPointer index_getnext_tid(IndexScanDesc scan, + ScanDirection direction); +struct TupleTableSlot; +extern bool index_fetch_heap(IndexScanDesc scan, struct TupleTableSlot *slot); +extern bool index_getnext_slot(IndexScanDesc scan, ScanDirection direction, + struct TupleTableSlot *slot); +extern int64 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap); + +extern IndexBulkDeleteResult *index_bulk_delete(IndexVacuumInfo *info, + IndexBulkDeleteResult *istat, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *index_vacuum_cleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *istat); +extern bool index_can_return(Relation indexRelation, int attno); +extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, + uint16 procnum); +extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum, + uint16 procnum); +extern void index_store_float8_orderby_distances(IndexScanDesc scan, + Oid *orderByTypes, + IndexOrderByDistance *distances, + bool recheckOrderBy); +extern bytea *index_opclass_options(Relation relation, AttrNumber attnum, + Datum attoptions, bool validate); + + +/* + * index access method support routines (in genam.c) + */ +extern IndexScanDesc RelationGetIndexScan(Relation indexRelation, + int nkeys, int norderbys); +extern void IndexScanEnd(IndexScanDesc scan); +extern char *BuildIndexValueDescription(Relation indexRelation, + Datum *values, bool *isnull); +extern TransactionId index_compute_xid_horizon_for_tuples(Relation irel, + Relation hrel, + Buffer ibuf, + OffsetNumber *itemnos, + int nitems); + +/* + * heap-or-index access to system catalogs (in genam.c) + */ +extern SysScanDesc systable_beginscan(Relation heapRelation, + Oid indexId, + bool indexOK, + Snapshot snapshot, + int nkeys, ScanKey key); +extern HeapTuple systable_getnext(SysScanDesc sysscan); +extern bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup); +extern void systable_endscan(SysScanDesc sysscan); +extern SysScanDesc systable_beginscan_ordered(Relation heapRelation, + Relation indexRelation, + Snapshot snapshot, + int nkeys, ScanKey key); +extern HeapTuple systable_getnext_ordered(SysScanDesc sysscan, + ScanDirection direction); +extern void systable_endscan_ordered(SysScanDesc sysscan); + +#endif /* GENAM_H */ diff --git a/src/include/access/generic_xlog.h b/src/include/access/generic_xlog.h new file mode 100644 index 0000000..c8363a4 --- /dev/null +++ b/src/include/access/generic_xlog.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * generic_xlog.h + * Generic xlog API definition. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/generic_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef GENERIC_XLOG_H +#define GENERIC_XLOG_H + +#include "access/xlog.h" +#include "access/xlog_internal.h" +#include "access/xloginsert.h" +#include "storage/bufpage.h" +#include "utils/rel.h" + +#define MAX_GENERIC_XLOG_PAGES XLR_NORMAL_MAX_BLOCK_ID + +/* Flag bits for GenericXLogRegisterBuffer */ +#define GENERIC_XLOG_FULL_IMAGE 0x0001 /* write full-page image */ + +/* state of generic xlog record construction */ +struct GenericXLogState; +typedef struct GenericXLogState GenericXLogState; + +/* API for construction of generic xlog records */ +extern GenericXLogState *GenericXLogStart(Relation relation); +extern Page GenericXLogRegisterBuffer(GenericXLogState *state, Buffer buffer, + int flags); +extern XLogRecPtr GenericXLogFinish(GenericXLogState *state); +extern void GenericXLogAbort(GenericXLogState *state); + +/* functions defined for rmgr */ +extern void generic_redo(XLogReaderState *record); +extern const char *generic_identify(uint8 info); +extern void generic_desc(StringInfo buf, XLogReaderState *record); +extern void generic_mask(char *pagedata, BlockNumber blkno); + +#endif /* GENERIC_XLOG_H */ diff --git a/src/include/access/gin.h b/src/include/access/gin.h new file mode 100644 index 0000000..aacc665 --- /dev/null +++ b/src/include/access/gin.h @@ -0,0 +1,78 @@ +/*-------------------------------------------------------------------------- + * gin.h + * Public header file for Generalized Inverted Index access method. + * + * Copyright (c) 2006-2022, PostgreSQL Global Development Group + * + * src/include/access/gin.h + *-------------------------------------------------------------------------- + */ +#ifndef GIN_H +#define GIN_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/block.h" +#include "utils/relcache.h" + + +/* + * amproc indexes for inverted indexes. + */ +#define GIN_COMPARE_PROC 1 +#define GIN_EXTRACTVALUE_PROC 2 +#define GIN_EXTRACTQUERY_PROC 3 +#define GIN_CONSISTENT_PROC 4 +#define GIN_COMPARE_PARTIAL_PROC 5 +#define GIN_TRICONSISTENT_PROC 6 +#define GIN_OPTIONS_PROC 7 +#define GINNProcs 7 + +/* + * searchMode settings for extractQueryFn. + */ +#define GIN_SEARCH_MODE_DEFAULT 0 +#define GIN_SEARCH_MODE_INCLUDE_EMPTY 1 +#define GIN_SEARCH_MODE_ALL 2 +#define GIN_SEARCH_MODE_EVERYTHING 3 /* for internal use only */ + +/* + * GinStatsData represents stats data for planner use + */ +typedef struct GinStatsData +{ + BlockNumber nPendingPages; + BlockNumber nTotalPages; + BlockNumber nEntryPages; + BlockNumber nDataPages; + int64 nEntries; + int32 ginVersion; +} GinStatsData; + +/* + * A ternary value used by tri-consistent functions. + * + * This must be of the same size as a bool because some code will cast a + * pointer to a bool to a pointer to a GinTernaryValue. + */ +typedef char GinTernaryValue; + +#define GIN_FALSE 0 /* item is not present / does not match */ +#define GIN_TRUE 1 /* item is present / matches */ +#define GIN_MAYBE 2 /* don't know if item is present / don't know + * if matches */ + +#define DatumGetGinTernaryValue(X) ((GinTernaryValue)(X)) +#define GinTernaryValueGetDatum(X) ((Datum)(X)) +#define PG_RETURN_GIN_TERNARY_VALUE(x) return GinTernaryValueGetDatum(x) + +/* GUC parameters */ +extern PGDLLIMPORT int GinFuzzySearchLimit; +extern PGDLLIMPORT int gin_pending_list_limit; + +/* ginutil.c */ +extern void ginGetStats(Relation index, GinStatsData *stats); +extern void ginUpdateStats(Relation index, const GinStatsData *stats, + bool is_build); + +#endif /* GIN_H */ diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h new file mode 100644 index 0000000..2935d2f --- /dev/null +++ b/src/include/access/gin_private.h @@ -0,0 +1,500 @@ +/*-------------------------------------------------------------------------- + * gin_private.h + * header file for postgres inverted index access method implementation. + * + * Copyright (c) 2006-2022, PostgreSQL Global Development Group + * + * src/include/access/gin_private.h + *-------------------------------------------------------------------------- + */ +#ifndef GIN_PRIVATE_H +#define GIN_PRIVATE_H + +#include "access/amapi.h" +#include "access/gin.h" +#include "access/ginblock.h" +#include "access/itup.h" +#include "catalog/pg_am_d.h" +#include "fmgr.h" +#include "lib/rbtree.h" +#include "storage/bufmgr.h" + +/* + * Storage type for GIN's reloptions + */ +typedef struct GinOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + bool useFastUpdate; /* use fast updates? */ + int pendingListCleanupSize; /* maximum size of pending list */ +} GinOptions; + +#define GIN_DEFAULT_USE_FASTUPDATE true +#define GinGetUseFastUpdate(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == GIN_AM_OID), \ + (relation)->rd_options ? \ + ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE) +#define GinGetPendingListCleanupSize(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == GIN_AM_OID), \ + (relation)->rd_options && \ + ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \ + ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \ + gin_pending_list_limit) + + +/* Macros for buffer lock/unlock operations */ +#define GIN_UNLOCK BUFFER_LOCK_UNLOCK +#define GIN_SHARE BUFFER_LOCK_SHARE +#define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE + + +/* + * GinState: working data structure describing the index being worked on + */ +typedef struct GinState +{ + Relation index; + bool oneCol; /* true if single-column index */ + + /* + * origTupdesc is the nominal tuple descriptor of the index, ie, the i'th + * attribute shows the key type (not the input data type!) of the i'th + * index column. In a single-column index this describes the actual leaf + * index tuples. In a multi-column index, the actual leaf tuples contain + * a smallint column number followed by a key datum of the appropriate + * type for that column. We set up tupdesc[i] to describe the actual + * rowtype of the index tuples for the i'th column, ie, (int2, keytype). + * Note that in any case, leaf tuples contain more data than is known to + * the TupleDesc; see access/gin/README for details. + */ + TupleDesc origTupdesc; + TupleDesc tupdesc[INDEX_MAX_KEYS]; + + /* + * Per-index-column opclass support functions + */ + FmgrInfo compareFn[INDEX_MAX_KEYS]; + FmgrInfo extractValueFn[INDEX_MAX_KEYS]; + FmgrInfo extractQueryFn[INDEX_MAX_KEYS]; + FmgrInfo consistentFn[INDEX_MAX_KEYS]; + FmgrInfo triConsistentFn[INDEX_MAX_KEYS]; + FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */ + /* canPartialMatch[i] is true if comparePartialFn[i] is valid */ + bool canPartialMatch[INDEX_MAX_KEYS]; + /* Collations to pass to the support functions */ + Oid supportCollation[INDEX_MAX_KEYS]; +} GinState; + + +/* ginutil.c */ +extern bytea *ginoptions(Datum reloptions, bool validate); +extern void initGinState(GinState *state, Relation index); +extern Buffer GinNewBuffer(Relation index); +extern void GinInitBuffer(Buffer b, uint32 f); +extern void GinInitPage(Page page, uint32 f, Size pageSize); +extern void GinInitMetabuffer(Buffer b); +extern int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, + Datum a, GinNullCategory categorya, + Datum b, GinNullCategory categoryb); +extern int ginCompareAttEntries(GinState *ginstate, + OffsetNumber attnuma, Datum a, GinNullCategory categorya, + OffsetNumber attnumb, Datum b, GinNullCategory categoryb); +extern Datum *ginExtractEntries(GinState *ginstate, OffsetNumber attnum, + Datum value, bool isNull, + int32 *nentries, GinNullCategory **categories); + +extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple); +extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, + GinNullCategory *category); + +/* gininsert.c */ +extern IndexBuildResult *ginbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void ginbuildempty(Relation index); +extern bool gininsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); +extern void ginEntryInsert(GinState *ginstate, + OffsetNumber attnum, Datum key, GinNullCategory category, + ItemPointerData *items, uint32 nitem, + GinStatsData *buildStats); + +/* ginbtree.c */ + +typedef struct GinBtreeStack +{ + BlockNumber blkno; + Buffer buffer; + OffsetNumber off; + ItemPointerData iptr; + /* predictNumber contains predicted number of pages on current level */ + uint32 predictNumber; + struct GinBtreeStack *parent; +} GinBtreeStack; + +typedef struct GinBtreeData *GinBtree; + +/* Return codes for GinBtreeData.beginPlaceToPage method */ +typedef enum +{ + GPTP_NO_WORK, + GPTP_INSERT, + GPTP_SPLIT +} GinPlaceToPageRC; + +typedef struct GinBtreeData +{ + /* search methods */ + BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *); + BlockNumber (*getLeftMostChild) (GinBtree, Page); + bool (*isMoveRight) (GinBtree, Page); + bool (*findItem) (GinBtree, GinBtreeStack *); + + /* insert methods */ + OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber); + GinPlaceToPageRC (*beginPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *); + void (*execPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *); + void *(*prepareDownlink) (GinBtree, Buffer); + void (*fillRoot) (GinBtree, Page, BlockNumber, Page, BlockNumber, Page); + + bool isData; + + Relation index; + BlockNumber rootBlkno; + GinState *ginstate; /* not valid in a data scan */ + bool fullScan; + bool isBuild; + + /* Search key for Entry tree */ + OffsetNumber entryAttnum; + Datum entryKey; + GinNullCategory entryCategory; + + /* Search key for data tree (posting tree) */ + ItemPointerData itemptr; +} GinBtreeData; + +/* This represents a tuple to be inserted to entry tree. */ +typedef struct +{ + IndexTuple entry; /* tuple to insert */ + bool isDelete; /* delete old tuple at same offset? */ +} GinBtreeEntryInsertData; + +/* + * This represents an itempointer, or many itempointers, to be inserted to + * a data (posting tree) leaf page + */ +typedef struct +{ + ItemPointerData *items; + uint32 nitem; + uint32 curitem; +} GinBtreeDataLeafInsertData; + +/* + * For internal data (posting tree) pages, the insertion payload is a + * PostingItem + */ + +extern GinBtreeStack *ginFindLeafPage(GinBtree btree, bool searchMode, + bool rootConflictCheck, Snapshot snapshot); +extern Buffer ginStepRight(Buffer buffer, Relation index, int lockmode); +extern void freeGinBtreeStack(GinBtreeStack *stack); +extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack, + void *insertdata, GinStatsData *buildStats); + +/* ginentrypage.c */ +extern IndexTuple GinFormTuple(GinState *ginstate, + OffsetNumber attnum, Datum key, GinNullCategory category, + Pointer data, Size dataSize, int nipd, bool errorTooBig); +extern void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, + Datum key, GinNullCategory category, + GinState *ginstate); +extern void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage); +extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum, + IndexTuple itup, int *nitems); + +/* gindatapage.c */ +extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast); +extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm); +extern BlockNumber createPostingTree(Relation index, + ItemPointerData *items, uint32 nitems, + GinStatsData *buildStats, Buffer entrybuffer); +extern void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset); +extern void GinPageDeletePostingItem(Page page, OffsetNumber offset); +extern void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, + ItemPointerData *items, uint32 nitem, + GinStatsData *buildStats); +extern GinBtreeStack *ginScanBeginPostingTree(GinBtree btree, Relation index, BlockNumber rootBlkno, Snapshot snapshot); +extern void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage); + +/* + * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers + * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward + * declaration for it. + */ +typedef struct GinVacuumState GinVacuumState; + +extern void ginVacuumPostingTreeLeaf(Relation rel, Buffer buf, GinVacuumState *gvs); + +/* ginscan.c */ + +/* + * GinScanKeyData describes a single GIN index qualifier expression. + * + * From each qual expression, we extract one or more specific index search + * conditions, which are represented by GinScanEntryData. It's quite + * possible for identical search conditions to be requested by more than + * one qual expression, in which case we merge such conditions to have just + * one unique GinScanEntry --- this is particularly important for efficiency + * when dealing with full-index-scan entries. So there can be multiple + * GinScanKeyData.scanEntry pointers to the same GinScanEntryData. + * + * In each GinScanKeyData, nentries is the true number of entries, while + * nuserentries is the number that extractQueryFn returned (which is what + * we report to consistentFn). The "user" entries must come first. + */ +typedef struct GinScanKeyData *GinScanKey; + +typedef struct GinScanEntryData *GinScanEntry; + +typedef struct GinScanKeyData +{ + /* Real number of entries in scanEntry[] (always > 0) */ + uint32 nentries; + /* Number of entries that extractQueryFn and consistentFn know about */ + uint32 nuserentries; + + /* array of GinScanEntry pointers, one per extracted search condition */ + GinScanEntry *scanEntry; + + /* + * At least one of the entries in requiredEntries must be present for a + * tuple to match the overall qual. + * + * additionalEntries contains entries that are needed by the consistent + * function to decide if an item matches, but are not sufficient to + * satisfy the qual without entries from requiredEntries. + */ + GinScanEntry *requiredEntries; + int nrequired; + GinScanEntry *additionalEntries; + int nadditional; + + /* array of check flags, reported to consistentFn */ + GinTernaryValue *entryRes; + bool (*boolConsistentFn) (GinScanKey key); + GinTernaryValue (*triConsistentFn) (GinScanKey key); + FmgrInfo *consistentFmgrInfo; + FmgrInfo *triConsistentFmgrInfo; + Oid collation; + + /* other data needed for calling consistentFn */ + Datum query; + /* NB: these three arrays have only nuserentries elements! */ + Datum *queryValues; + GinNullCategory *queryCategories; + Pointer *extra_data; + StrategyNumber strategy; + int32 searchMode; + OffsetNumber attnum; + + /* + * An excludeOnly scan key is not able to enumerate all matching tuples. + * That is, to be semantically correct on its own, it would need to have a + * GIN_CAT_EMPTY_QUERY scanEntry, but it doesn't. Such a key can still be + * used to filter tuples returned by other scan keys, so we will get the + * right answers as long as there's at least one non-excludeOnly scan key + * for each index attribute considered by the search. For efficiency + * reasons we don't want to have unnecessary GIN_CAT_EMPTY_QUERY entries, + * so we will convert an excludeOnly scan key to non-excludeOnly (by + * adding a GIN_CAT_EMPTY_QUERY scanEntry) only if there are no other + * non-excludeOnly scan keys. + */ + bool excludeOnly; + + /* + * Match status data. curItem is the TID most recently tested (could be a + * lossy-page pointer). curItemMatches is true if it passes the + * consistentFn test; if so, recheckCurItem is the recheck flag. + * isFinished means that all the input entry streams are finished, so this + * key cannot succeed for any later TIDs. + */ + ItemPointerData curItem; + bool curItemMatches; + bool recheckCurItem; + bool isFinished; +} GinScanKeyData; + +typedef struct GinScanEntryData +{ + /* query key and other information from extractQueryFn */ + Datum queryKey; + GinNullCategory queryCategory; + bool isPartialMatch; + Pointer extra_data; + StrategyNumber strategy; + int32 searchMode; + OffsetNumber attnum; + + /* Current page in posting tree */ + Buffer buffer; + + /* current ItemPointer to heap */ + ItemPointerData curItem; + + /* for a partial-match or full-scan query, we accumulate all TIDs here */ + TIDBitmap *matchBitmap; + TBMIterator *matchIterator; + TBMIterateResult *matchResult; + + /* used for Posting list and one page in Posting tree */ + ItemPointerData *list; + int nlist; + OffsetNumber offset; + + bool isFinished; + bool reduceResult; + uint32 predictNumberResult; + GinBtreeData btree; +} GinScanEntryData; + +typedef struct GinScanOpaqueData +{ + MemoryContext tempCtx; + GinState ginstate; + + GinScanKey keys; /* one per scan qualifier expr */ + uint32 nkeys; + + GinScanEntry *entries; /* one per index search condition */ + uint32 totalentries; + uint32 allocentries; /* allocated length of entries[] */ + + MemoryContext keyCtx; /* used to hold key and entry data */ + + bool isVoidRes; /* true if query is unsatisfiable */ +} GinScanOpaqueData; + +typedef GinScanOpaqueData *GinScanOpaque; + +extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys); +extern void ginendscan(IndexScanDesc scan); +extern void ginrescan(IndexScanDesc scan, ScanKey key, int nscankeys, + ScanKey orderbys, int norderbys); +extern void ginNewScanKey(IndexScanDesc scan); +extern void ginFreeScanKeys(GinScanOpaque so); + +/* ginget.c */ +extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm); + +/* ginlogic.c */ +extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key); + +/* ginvacuum.c */ +extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, + ItemPointerData *items, int nitem, int *nremaining); + +/* ginvalidate.c */ +extern bool ginvalidate(Oid opclassoid); +extern void ginadjustmembers(Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +/* ginbulk.c */ +typedef struct GinEntryAccumulator +{ + RBTNode rbtnode; + Datum key; + GinNullCategory category; + OffsetNumber attnum; + bool shouldSort; + ItemPointerData *list; + uint32 maxcount; /* allocated size of list[] */ + uint32 count; /* current number of list[] entries */ +} GinEntryAccumulator; + +typedef struct +{ + GinState *ginstate; + Size allocatedMemory; + GinEntryAccumulator *entryallocator; + uint32 eas_used; + RBTree *tree; + RBTreeIterator tree_walk; +} BuildAccumulator; + +extern void ginInitBA(BuildAccumulator *accum); +extern void ginInsertBAEntries(BuildAccumulator *accum, + ItemPointer heapptr, OffsetNumber attnum, + Datum *entries, GinNullCategory *categories, + int32 nentries); +extern void ginBeginBAScan(BuildAccumulator *accum); +extern ItemPointerData *ginGetBAEntry(BuildAccumulator *accum, + OffsetNumber *attnum, Datum *key, GinNullCategory *category, + uint32 *n); + +/* ginfast.c */ + +typedef struct GinTupleCollector +{ + IndexTuple *tuples; + uint32 ntuples; + uint32 lentuples; + uint32 sumsize; +} GinTupleCollector; + +extern void ginHeapTupleFastInsert(GinState *ginstate, + GinTupleCollector *collector); +extern void ginHeapTupleFastCollect(GinState *ginstate, + GinTupleCollector *collector, + OffsetNumber attnum, Datum value, bool isNull, + ItemPointer ht_ctid); +extern void ginInsertCleanup(GinState *ginstate, bool full_clean, + bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats); + +/* ginpostinglist.c */ + +extern GinPostingList *ginCompressPostingList(const ItemPointer ipd, int nipd, + int maxsize, int *nwritten); +extern int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int totalsize, TIDBitmap *tbm); + +extern ItemPointer ginPostingListDecodeAllSegments(GinPostingList *ptr, int len, int *ndecoded); +extern ItemPointer ginPostingListDecode(GinPostingList *ptr, int *ndecoded); +extern ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, + ItemPointerData *b, uint32 nb, + int *nmerged); + +/* + * Merging the results of several gin scans compares item pointers a lot, + * so we want this to be inlined. + */ +static inline int +ginCompareItemPointers(ItemPointer a, ItemPointer b) +{ + uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a); + uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b); + + if (ia == ib) + return 0; + else if (ia > ib) + return 1; + else + return -1; +} + +extern int ginTraverseLock(Buffer buffer, bool searchMode); + +#endif /* GIN_PRIVATE_H */ diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h new file mode 100644 index 0000000..9347f46 --- /dev/null +++ b/src/include/access/ginblock.h @@ -0,0 +1,346 @@ +/*-------------------------------------------------------------------------- + * ginblock.h + * details of structures stored in GIN index blocks + * + * Copyright (c) 2006-2022, PostgreSQL Global Development Group + * + * src/include/access/ginblock.h + *-------------------------------------------------------------------------- + */ +#ifndef GINBLOCK_H +#define GINBLOCK_H + +#include "access/transam.h" +#include "storage/block.h" +#include "storage/bufpage.h" +#include "storage/itemptr.h" +#include "storage/off.h" + +/* + * Page opaque data in an inverted index page. + * + * Note: GIN does not include a page ID word as do the other index types. + * This is OK because the opaque data is only 8 bytes and so can be reliably + * distinguished by size. Revisit this if the size ever increases. + * Further note: as of 9.2, SP-GiST also uses 8-byte special space, as does + * BRIN as of 9.5. This is still OK, as long as GIN isn't using all of the + * high-order bits in its flags word, because that way the flags word cannot + * match the page IDs used by SP-GiST and BRIN. + */ +typedef struct GinPageOpaqueData +{ + BlockNumber rightlink; /* next page if any */ + OffsetNumber maxoff; /* number of PostingItems on GIN_DATA & + * ~GIN_LEAF page. On GIN_LIST page, number of + * heap tuples. */ + uint16 flags; /* see bit definitions below */ +} GinPageOpaqueData; + +typedef GinPageOpaqueData *GinPageOpaque; + +#define GIN_DATA (1 << 0) +#define GIN_LEAF (1 << 1) +#define GIN_DELETED (1 << 2) +#define GIN_META (1 << 3) +#define GIN_LIST (1 << 4) +#define GIN_LIST_FULLROW (1 << 5) /* makes sense only on GIN_LIST page */ +#define GIN_INCOMPLETE_SPLIT (1 << 6) /* page was split, but parent not + * updated */ +#define GIN_COMPRESSED (1 << 7) + +/* Page numbers of fixed-location pages */ +#define GIN_METAPAGE_BLKNO (0) +#define GIN_ROOT_BLKNO (1) + +typedef struct GinMetaPageData +{ + /* + * Pointers to head and tail of pending list, which consists of GIN_LIST + * pages. These store fast-inserted entries that haven't yet been moved + * into the regular GIN structure. + */ + BlockNumber head; + BlockNumber tail; + + /* + * Free space in bytes in the pending list's tail page. + */ + uint32 tailFreeSize; + + /* + * We store both number of pages and number of heap tuples that are in the + * pending list. + */ + BlockNumber nPendingPages; + int64 nPendingHeapTuples; + + /* + * Statistics for planner use (accurate as of last VACUUM) + */ + BlockNumber nTotalPages; + BlockNumber nEntryPages; + BlockNumber nDataPages; + int64 nEntries; + + /* + * GIN version number (ideally this should have been at the front, but too + * late now. Don't move it!) + * + * Currently 2 (for indexes initialized in 9.4 or later) + * + * Version 1 (indexes initialized in version 9.1, 9.2 or 9.3), is + * compatible, but may contain uncompressed posting tree (leaf) pages and + * posting lists. They will be converted to compressed format when + * modified. + * + * Version 0 (indexes initialized in 9.0 or before) is compatible but may + * be missing null entries, including both null keys and placeholders. + * Reject full-index-scan attempts on such indexes. + */ + int32 ginVersion; +} GinMetaPageData; + +#define GIN_CURRENT_VERSION 2 + +#define GinPageGetMeta(p) \ + ((GinMetaPageData *) PageGetContents(p)) + +/* + * Macros for accessing a GIN index page's opaque data + */ +#define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) ) + +#define GinPageIsLeaf(page) ( (GinPageGetOpaque(page)->flags & GIN_LEAF) != 0 ) +#define GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF ) +#define GinPageSetNonLeaf(page) ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF ) +#define GinPageIsData(page) ( (GinPageGetOpaque(page)->flags & GIN_DATA) != 0 ) +#define GinPageSetData(page) ( GinPageGetOpaque(page)->flags |= GIN_DATA ) +#define GinPageIsList(page) ( (GinPageGetOpaque(page)->flags & GIN_LIST) != 0 ) +#define GinPageSetList(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST ) +#define GinPageHasFullRow(page) ( (GinPageGetOpaque(page)->flags & GIN_LIST_FULLROW) != 0 ) +#define GinPageSetFullRow(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST_FULLROW ) +#define GinPageIsCompressed(page) ( (GinPageGetOpaque(page)->flags & GIN_COMPRESSED) != 0 ) +#define GinPageSetCompressed(page) ( GinPageGetOpaque(page)->flags |= GIN_COMPRESSED ) + +#define GinPageIsDeleted(page) ( (GinPageGetOpaque(page)->flags & GIN_DELETED) != 0 ) +#define GinPageSetDeleted(page) ( GinPageGetOpaque(page)->flags |= GIN_DELETED) +#define GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED) +#define GinPageIsIncompleteSplit(page) ( (GinPageGetOpaque(page)->flags & GIN_INCOMPLETE_SPLIT) != 0 ) + +#define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber) + +/* + * We should reclaim deleted page only once every transaction started before + * its deletion is over. + */ +#define GinPageGetDeleteXid(page) ( ((PageHeader) (page))->pd_prune_xid ) +#define GinPageSetDeleteXid(page, xid) ( ((PageHeader) (page))->pd_prune_xid = xid) +extern bool GinPageIsRecyclable(Page page); + +/* + * We use our own ItemPointerGet(BlockNumber|OffsetNumber) + * to avoid Asserts, since sometimes the ip_posid isn't "valid" + */ +#define GinItemPointerGetBlockNumber(pointer) \ + (ItemPointerGetBlockNumberNoCheck(pointer)) + +#define GinItemPointerGetOffsetNumber(pointer) \ + (ItemPointerGetOffsetNumberNoCheck(pointer)) + +#define GinItemPointerSetBlockNumber(pointer, blkno) \ + (ItemPointerSetBlockNumber((pointer), (blkno))) + +#define GinItemPointerSetOffsetNumber(pointer, offnum) \ + (ItemPointerSetOffsetNumber((pointer), (offnum))) + + +/* + * Special-case item pointer values needed by the GIN search logic. + * MIN: sorts less than any valid item pointer + * MAX: sorts greater than any valid item pointer + * LOSSY PAGE: indicates a whole heap page, sorts after normal item + * pointers for that page + * Note that these are all distinguishable from an "invalid" item pointer + * (which is InvalidBlockNumber/0) as well as from all normal item + * pointers (which have item numbers in the range 1..MaxHeapTuplesPerPage). + */ +#define ItemPointerSetMin(p) \ + ItemPointerSet((p), (BlockNumber)0, (OffsetNumber)0) +#define ItemPointerIsMin(p) \ + (GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0 && \ + GinItemPointerGetBlockNumber(p) == (BlockNumber)0) +#define ItemPointerSetMax(p) \ + ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)0xffff) +#define ItemPointerSetLossyPage(p, b) \ + ItemPointerSet((p), (b), (OffsetNumber)0xffff) +#define ItemPointerIsLossyPage(p) \ + (GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \ + GinItemPointerGetBlockNumber(p) != InvalidBlockNumber) + +/* + * Posting item in a non-leaf posting-tree page + */ +typedef struct +{ + /* We use BlockIdData not BlockNumber to avoid padding space wastage */ + BlockIdData child_blkno; + ItemPointerData key; +} PostingItem; + +#define PostingItemGetBlockNumber(pointer) \ + BlockIdGetBlockNumber(&(pointer)->child_blkno) + +#define PostingItemSetBlockNumber(pointer, blockNumber) \ + BlockIdSet(&((pointer)->child_blkno), (blockNumber)) + +/* + * Category codes to distinguish placeholder nulls from ordinary NULL keys. + * + * The first two code values were chosen to be compatible with the usual usage + * of bool isNull flags. However, casting between bool and GinNullCategory is + * risky because of the possibility of different bit patterns and type sizes, + * so it is no longer done. + * + * GIN_CAT_EMPTY_QUERY is never stored in the index; and notice that it is + * chosen to sort before not after regular key values. + */ +typedef signed char GinNullCategory; + +#define GIN_CAT_NORM_KEY 0 /* normal, non-null key value */ +#define GIN_CAT_NULL_KEY 1 /* null key value */ +#define GIN_CAT_EMPTY_ITEM 2 /* placeholder for zero-key item */ +#define GIN_CAT_NULL_ITEM 3 /* placeholder for null item */ +#define GIN_CAT_EMPTY_QUERY (-1) /* placeholder for full-scan query */ + +/* + * Access macros for null category byte in entry tuples + */ +#define GinCategoryOffset(itup,ginstate) \ + (IndexInfoFindDataOffset((itup)->t_info) + \ + ((ginstate)->oneCol ? 0 : sizeof(int16))) +#define GinGetNullCategory(itup,ginstate) \ + (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate)))) +#define GinSetNullCategory(itup,ginstate,c) \ + (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate))) = (c)) + +/* + * Access macros for leaf-page entry tuples (see discussion in README) + */ +#define GinGetNPosting(itup) GinItemPointerGetOffsetNumber(&(itup)->t_tid) +#define GinSetNPosting(itup,n) ItemPointerSetOffsetNumber(&(itup)->t_tid,n) +#define GIN_TREE_POSTING ((OffsetNumber)0xffff) +#define GinIsPostingTree(itup) (GinGetNPosting(itup) == GIN_TREE_POSTING) +#define GinSetPostingTree(itup, blkno) ( GinSetNPosting((itup),GIN_TREE_POSTING), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) ) +#define GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid) + +#define GIN_ITUP_COMPRESSED (1U << 31) +#define GinGetPostingOffset(itup) (GinItemPointerGetBlockNumber(&(itup)->t_tid) & (~GIN_ITUP_COMPRESSED)) +#define GinSetPostingOffset(itup,n) ItemPointerSetBlockNumber(&(itup)->t_tid,(n)|GIN_ITUP_COMPRESSED) +#define GinGetPosting(itup) ((Pointer) ((char*)(itup) + GinGetPostingOffset(itup))) +#define GinItupIsCompressed(itup) ((GinItemPointerGetBlockNumber(&(itup)->t_tid) & GIN_ITUP_COMPRESSED) != 0) + +/* + * Maximum size of an item on entry tree page. Make sure that we fit at least + * three items on each page. (On regular B-tree indexes, we must fit at least + * three items: two data items and the "high key". In GIN entry tree, we don't + * currently store the high key explicitly, we just use the rightmost item on + * the page, so it would actually be enough to fit two items.) + */ +#define GinMaxItemSize \ + Min(INDEX_SIZE_MASK, \ + MAXALIGN_DOWN(((BLCKSZ - \ + MAXALIGN(SizeOfPageHeaderData + 3 * sizeof(ItemIdData)) - \ + MAXALIGN(sizeof(GinPageOpaqueData))) / 3))) + +/* + * Access macros for non-leaf entry tuples + */ +#define GinGetDownlink(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid) +#define GinSetDownlink(itup,blkno) ItemPointerSet(&(itup)->t_tid, blkno, InvalidOffsetNumber) + + +/* + * Data (posting tree) pages + * + * Posting tree pages don't store regular tuples. Non-leaf pages contain + * PostingItems, which are pairs of ItemPointers and child block numbers. + * Leaf pages contain GinPostingLists and an uncompressed array of item + * pointers. + * + * In a leaf page, the compressed posting lists are stored after the regular + * page header, one after each other. Although we don't store regular tuples, + * pd_lower is used to indicate the end of the posting lists. After that, free + * space follows. This layout is compatible with the "standard" heap and + * index page layout described in bufpage.h, so that we can e.g set buffer_std + * when writing WAL records. + * + * In the special space is the GinPageOpaque struct. + */ +#define GinDataLeafPageGetPostingList(page) \ + (GinPostingList *) ((PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData)))) +#define GinDataLeafPageGetPostingListSize(page) \ + (((PageHeader) page)->pd_lower - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(ItemPointerData))) + +#define GinDataLeafPageIsEmpty(page) \ + (GinPageIsCompressed(page) ? (GinDataLeafPageGetPostingListSize(page) == 0) : (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)) + +#define GinDataLeafPageGetFreeSpace(page) PageGetExactFreeSpace(page) + +#define GinDataPageGetRightBound(page) ((ItemPointer) PageGetContents(page)) +/* + * Pointer to the data portion of a posting tree page. For internal pages, + * that's the beginning of the array of PostingItems. For compressed leaf + * pages, the first compressed posting list. For uncompressed (pre-9.4) leaf + * pages, it's the beginning of the ItemPointer array. + */ +#define GinDataPageGetData(page) \ + (PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData))) +/* non-leaf pages contain PostingItems */ +#define GinDataPageGetPostingItem(page, i) \ + ((PostingItem *) (GinDataPageGetData(page) + ((i)-1) * sizeof(PostingItem))) + +/* + * Note: there is no GinDataPageGetDataSize macro, because before version + * 9.4, we didn't set pd_lower on data pages. There can be pages in the index + * that were binary-upgraded from earlier versions and still have an invalid + * pd_lower, so we cannot trust it in general. Compressed posting tree leaf + * pages are new in 9.4, however, so we can trust them; see + * GinDataLeafPageGetPostingListSize. + */ +#define GinDataPageSetDataSize(page, size) \ + { \ + Assert(size <= GinDataPageMaxDataSize); \ + ((PageHeader) page)->pd_lower = (size) + MAXALIGN(SizeOfPageHeaderData) + MAXALIGN(sizeof(ItemPointerData)); \ + } + +#define GinNonLeafDataPageGetFreeSpace(page) \ + (GinDataPageMaxDataSize - \ + GinPageGetOpaque(page)->maxoff * sizeof(PostingItem)) + +#define GinDataPageMaxDataSize \ + (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \ + - MAXALIGN(sizeof(ItemPointerData)) \ + - MAXALIGN(sizeof(GinPageOpaqueData))) + +/* + * List pages + */ +#define GinListPageSize \ + ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) ) + +/* + * A compressed posting list. + * + * Note: This requires 2-byte alignment. + */ +typedef struct +{ + ItemPointerData first; /* first item in this posting list (unpacked) */ + uint16 nbytes; /* number of bytes that follow */ + unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]; /* varbyte encoded items */ +} GinPostingList; + +#define SizeOfGinPostingList(plist) (offsetof(GinPostingList, bytes) + SHORTALIGN((plist)->nbytes) ) +#define GinNextPostingListSegment(cur) ((GinPostingList *) (((char *) (cur)) + SizeOfGinPostingList((cur)))) + +#endif /* GINBLOCK_H */ diff --git a/src/include/access/ginxlog.h b/src/include/access/ginxlog.h new file mode 100644 index 0000000..21de389 --- /dev/null +++ b/src/include/access/ginxlog.h @@ -0,0 +1,216 @@ +/*-------------------------------------------------------------------------- + * ginxlog.h + * header file for postgres inverted index xlog implementation. + * + * Copyright (c) 2006-2022, PostgreSQL Global Development Group + * + * src/include/access/ginxlog.h + *-------------------------------------------------------------------------- + */ +#ifndef GINXLOG_H +#define GINXLOG_H + +#include "access/ginblock.h" +#include "access/itup.h" +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/off.h" + +#define XLOG_GIN_CREATE_PTREE 0x10 + +typedef struct ginxlogCreatePostingTree +{ + uint32 size; + /* A compressed posting list follows */ +} ginxlogCreatePostingTree; + +/* + * The format of the insertion record varies depending on the page type. + * ginxlogInsert is the common part between all variants. + * + * Backup Blk 0: target page + * Backup Blk 1: left child, if this insertion finishes an incomplete split + */ + +#define XLOG_GIN_INSERT 0x20 + +typedef struct +{ + uint16 flags; /* GIN_INSERT_ISLEAF and/or GIN_INSERT_ISDATA */ + + /* + * FOLLOWS: + * + * 1. if not leaf page, block numbers of the left and right child pages + * whose split this insertion finishes, as BlockIdData[2] (beware of + * adding fields in this struct that would make them not 16-bit aligned) + * + * 2. a ginxlogInsertEntry or ginxlogRecompressDataLeaf struct, depending + * on tree type. + * + * NB: the below structs are only 16-bit aligned when appended to a + * ginxlogInsert struct! Beware of adding fields to them that require + * stricter alignment. + */ +} ginxlogInsert; + +typedef struct +{ + OffsetNumber offset; + bool isDelete; + IndexTupleData tuple; /* variable length */ +} ginxlogInsertEntry; + + +typedef struct +{ + uint16 nactions; + + /* Variable number of 'actions' follow */ +} ginxlogRecompressDataLeaf; + +/* + * Note: this struct is currently not used in code, and only acts as + * documentation. The WAL record format is as specified here, but the code + * uses straight access through a Pointer and memcpy to read/write these. + */ +typedef struct +{ + uint8 segno; /* segment this action applies to */ + char type; /* action type (see below) */ + + /* + * Action-specific data follows. For INSERT and REPLACE actions that is a + * GinPostingList struct. For ADDITEMS, a uint16 for the number of items + * added, followed by the items themselves as ItemPointers. DELETE actions + * have no further data. + */ +} ginxlogSegmentAction; + +/* Action types */ +#define GIN_SEGMENT_UNMODIFIED 0 /* no action (not used in WAL records) */ +#define GIN_SEGMENT_DELETE 1 /* a whole segment is removed */ +#define GIN_SEGMENT_INSERT 2 /* a whole segment is added */ +#define GIN_SEGMENT_REPLACE 3 /* a segment is replaced */ +#define GIN_SEGMENT_ADDITEMS 4 /* items are added to existing segment */ + +typedef struct +{ + OffsetNumber offset; + PostingItem newitem; +} ginxlogInsertDataInternal; + +/* + * Backup Blk 0: new left page (= original page, if not root split) + * Backup Blk 1: new right page + * Backup Blk 2: original page / new root page, if root split + * Backup Blk 3: left child, if this insertion completes an earlier split + */ +#define XLOG_GIN_SPLIT 0x30 + +typedef struct ginxlogSplit +{ + RelFileNode node; + BlockNumber rrlink; /* right link, or root's blocknumber if root + * split */ + BlockNumber leftChildBlkno; /* valid on a non-leaf split */ + BlockNumber rightChildBlkno; + uint16 flags; /* see below */ +} ginxlogSplit; + +/* + * Flags used in ginxlogInsert and ginxlogSplit records + */ +#define GIN_INSERT_ISDATA 0x01 /* for both insert and split records */ +#define GIN_INSERT_ISLEAF 0x02 /* ditto */ +#define GIN_SPLIT_ROOT 0x04 /* only for split records */ + +/* + * Vacuum simply WAL-logs the whole page, when anything is modified. This + * is functionally identical to XLOG_FPI records, but is kept separate for + * debugging purposes. (When inspecting the WAL stream, it's easier to see + * what's going on when GIN vacuum records are marked as such, not as heap + * records.) This is currently only used for entry tree leaf pages. + */ +#define XLOG_GIN_VACUUM_PAGE 0x40 + +/* + * Vacuuming posting tree leaf page is WAL-logged like recompression caused + * by insertion. + */ +#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE 0x90 + +typedef struct ginxlogVacuumDataLeafPage +{ + ginxlogRecompressDataLeaf data; +} ginxlogVacuumDataLeafPage; + +/* + * Backup Blk 0: deleted page + * Backup Blk 1: parent + * Backup Blk 2: left sibling + */ +#define XLOG_GIN_DELETE_PAGE 0x50 + +typedef struct ginxlogDeletePage +{ + OffsetNumber parentOffset; + BlockNumber rightLink; + TransactionId deleteXid; /* last Xid which could see this page in scan */ +} ginxlogDeletePage; + +#define XLOG_GIN_UPDATE_META_PAGE 0x60 + +/* + * Backup Blk 0: metapage + * Backup Blk 1: tail page + */ +typedef struct ginxlogUpdateMeta +{ + RelFileNode node; + GinMetaPageData metadata; + BlockNumber prevTail; + BlockNumber newRightlink; + int32 ntuples; /* if ntuples > 0 then metadata.tail was + * updated with that many tuples; else new sub + * list was inserted */ + /* array of inserted tuples follows */ +} ginxlogUpdateMeta; + +#define XLOG_GIN_INSERT_LISTPAGE 0x70 + +typedef struct ginxlogInsertListPage +{ + BlockNumber rightlink; + int32 ntuples; + /* array of inserted tuples follows */ +} ginxlogInsertListPage; + +/* + * Backup Blk 0: metapage + * Backup Blk 1 to (ndeleted + 1): deleted pages + */ + +#define XLOG_GIN_DELETE_LISTPAGE 0x80 + +/* + * The WAL record for deleting list pages must contain a block reference to + * all the deleted pages, so the number of pages that can be deleted in one + * record is limited by XLR_MAX_BLOCK_ID. (block_id 0 is used for the + * metapage.) + */ +#define GIN_NDELETE_AT_ONCE Min(16, XLR_MAX_BLOCK_ID - 1) +typedef struct ginxlogDeleteListPages +{ + GinMetaPageData metadata; + int32 ndeleted; +} ginxlogDeleteListPages; + +extern void gin_redo(XLogReaderState *record); +extern void gin_desc(StringInfo buf, XLogReaderState *record); +extern const char *gin_identify(uint8 info); +extern void gin_xlog_startup(void); +extern void gin_xlog_cleanup(void); +extern void gin_mask(char *pagedata, BlockNumber blkno); + +#endif /* GINXLOG_H */ diff --git a/src/include/access/gist.h b/src/include/access/gist.h new file mode 100644 index 0000000..a333762 --- /dev/null +++ b/src/include/access/gist.h @@ -0,0 +1,248 @@ +/*------------------------------------------------------------------------- + * + * gist.h + * The public API for GiST indexes. This API is exposed to + * individuals implementing GiST indexes, so backward-incompatible + * changes should be made with care. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/gist.h + * + *------------------------------------------------------------------------- + */ +#ifndef GIST_H +#define GIST_H + +#include "access/itup.h" +#include "access/transam.h" +#include "access/xlog.h" +#include "access/xlogdefs.h" +#include "storage/block.h" +#include "storage/bufpage.h" +#include "utils/relcache.h" + +/* + * amproc indexes for GiST indexes. + */ +#define GIST_CONSISTENT_PROC 1 +#define GIST_UNION_PROC 2 +#define GIST_COMPRESS_PROC 3 +#define GIST_DECOMPRESS_PROC 4 +#define GIST_PENALTY_PROC 5 +#define GIST_PICKSPLIT_PROC 6 +#define GIST_EQUAL_PROC 7 +#define GIST_DISTANCE_PROC 8 +#define GIST_FETCH_PROC 9 +#define GIST_OPTIONS_PROC 10 +#define GIST_SORTSUPPORT_PROC 11 +#define GISTNProcs 11 + +/* + * Page opaque data in a GiST index page. + */ +#define F_LEAF (1 << 0) /* leaf page */ +#define F_DELETED (1 << 1) /* the page has been deleted */ +#define F_TUPLES_DELETED (1 << 2) /* some tuples on the page were + * deleted */ +#define F_FOLLOW_RIGHT (1 << 3) /* page to the right has no downlink */ +#define F_HAS_GARBAGE (1 << 4) /* some tuples on the page are dead, + * but not deleted yet */ + +/* + * NSN (node sequence number) is a special-purpose LSN which is stored on each + * index page in GISTPageOpaqueData and updated only during page splits. By + * recording the parent's LSN in GISTSearchItem.parentlsn, it is possible to + * detect concurrent child page splits by checking if parentlsn < child's NSN, + * and handle them properly. The child page's LSN is insufficient for this + * purpose since it is updated for every page change. + */ +typedef XLogRecPtr GistNSN; + +/* + * A fake LSN / NSN value used during index builds. Must be smaller than any + * real or fake (unlogged) LSN generated after the index build completes so + * that all splits are considered complete. + */ +#define GistBuildLSN ((XLogRecPtr) 1) + +/* + * For on-disk compatibility with pre-9.3 servers, NSN is stored as two + * 32-bit fields on disk, same as LSNs. + */ +typedef PageXLogRecPtr PageGistNSN; + +typedef struct GISTPageOpaqueData +{ + PageGistNSN nsn; /* this value must change on page split */ + BlockNumber rightlink; /* next page if any */ + uint16 flags; /* see bit definitions above */ + uint16 gist_page_id; /* for identification of GiST indexes */ +} GISTPageOpaqueData; + +typedef GISTPageOpaqueData *GISTPageOpaque; + +/* + * Maximum possible sizes for GiST index tuple and index key. Calculation is + * based on assumption that GiST page should fit at least 4 tuples. In theory, + * GiST index can be functional when page can fit 3 tuples. But that seems + * rather inefficient, so we use a bit conservative estimate. + * + * The maximum size of index key is true for unicolumn index. Therefore, this + * estimation should be used to figure out which maximum size of GiST index key + * makes sense at all. For multicolumn indexes, user might be able to tune + * key size using opclass parameters. + */ +#define GISTMaxIndexTupleSize \ + MAXALIGN_DOWN((BLCKSZ - SizeOfPageHeaderData - sizeof(GISTPageOpaqueData)) / \ + 4 - sizeof(ItemIdData)) + +#define GISTMaxIndexKeySize \ + (GISTMaxIndexTupleSize - MAXALIGN(sizeof(IndexTupleData))) + +/* + * The page ID is for the convenience of pg_filedump and similar utilities, + * which otherwise would have a hard time telling pages of different index + * types apart. It should be the last 2 bytes on the page. This is more or + * less "free" due to alignment considerations. + */ +#define GIST_PAGE_ID 0xFF81 + +/* + * This is the Split Vector to be returned by the PickSplit method. + * PickSplit should fill the indexes of tuples to go to the left side into + * spl_left[], and those to go to the right into spl_right[] (note the method + * is responsible for palloc'ing both of these arrays!). The tuple counts + * go into spl_nleft/spl_nright, and spl_ldatum/spl_rdatum must be set to + * the union keys for each side. + * + * If spl_ldatum_exists and spl_rdatum_exists are true, then we are performing + * a "secondary split" using a non-first index column. In this case some + * decisions have already been made about a page split, and the set of tuples + * being passed to PickSplit is just the tuples about which we are undecided. + * spl_ldatum/spl_rdatum then contain the union keys for the tuples already + * chosen to go left or right. Ideally the PickSplit method should take those + * keys into account while deciding what to do with the remaining tuples, ie + * it should try to "build out" from those unions so as to minimally expand + * them. If it does so, it should union the given tuples' keys into the + * existing spl_ldatum/spl_rdatum values rather than just setting those values + * from scratch, and then set spl_ldatum_exists/spl_rdatum_exists to false to + * show it has done this. + * + * If the PickSplit method fails to clear spl_ldatum_exists/spl_rdatum_exists, + * the core GiST code will make its own decision about how to merge the + * secondary-split results with the previously-chosen tuples, and will then + * recompute the union keys from scratch. This is a workable though often not + * optimal approach. + */ +typedef struct GIST_SPLITVEC +{ + OffsetNumber *spl_left; /* array of entries that go left */ + int spl_nleft; /* size of this array */ + Datum spl_ldatum; /* Union of keys in spl_left */ + bool spl_ldatum_exists; /* true, if spl_ldatum already exists. */ + + OffsetNumber *spl_right; /* array of entries that go right */ + int spl_nright; /* size of the array */ + Datum spl_rdatum; /* Union of keys in spl_right */ + bool spl_rdatum_exists; /* true, if spl_rdatum already exists. */ +} GIST_SPLITVEC; + +/* + * An entry on a GiST node. Contains the key, as well as its own + * location (rel,page,offset) which can supply the matching pointer. + * leafkey is a flag to tell us if the entry is in a leaf node. + */ +typedef struct GISTENTRY +{ + Datum key; + Relation rel; + Page page; + OffsetNumber offset; + bool leafkey; +} GISTENTRY; + +#define GistPageGetOpaque(page) ( (GISTPageOpaque) PageGetSpecialPointer(page) ) + +#define GistPageIsLeaf(page) ( GistPageGetOpaque(page)->flags & F_LEAF) +#define GIST_LEAF(entry) (GistPageIsLeaf((entry)->page)) + +#define GistPageIsDeleted(page) ( GistPageGetOpaque(page)->flags & F_DELETED) + +#define GistTuplesDeleted(page) ( GistPageGetOpaque(page)->flags & F_TUPLES_DELETED) +#define GistMarkTuplesDeleted(page) ( GistPageGetOpaque(page)->flags |= F_TUPLES_DELETED) +#define GistClearTuplesDeleted(page) ( GistPageGetOpaque(page)->flags &= ~F_TUPLES_DELETED) + +#define GistPageHasGarbage(page) ( GistPageGetOpaque(page)->flags & F_HAS_GARBAGE) +#define GistMarkPageHasGarbage(page) ( GistPageGetOpaque(page)->flags |= F_HAS_GARBAGE) +#define GistClearPageHasGarbage(page) ( GistPageGetOpaque(page)->flags &= ~F_HAS_GARBAGE) + +#define GistFollowRight(page) ( GistPageGetOpaque(page)->flags & F_FOLLOW_RIGHT) +#define GistMarkFollowRight(page) ( GistPageGetOpaque(page)->flags |= F_FOLLOW_RIGHT) +#define GistClearFollowRight(page) ( GistPageGetOpaque(page)->flags &= ~F_FOLLOW_RIGHT) + +#define GistPageGetNSN(page) ( PageXLogRecPtrGet(GistPageGetOpaque(page)->nsn)) +#define GistPageSetNSN(page, val) ( PageXLogRecPtrSet(GistPageGetOpaque(page)->nsn, val)) + + +/* + * On a deleted page, we store this struct. A deleted page doesn't contain any + * tuples, so we don't use the normal page layout with line pointers. Instead, + * this struct is stored right after the standard page header. pd_lower points + * to the end of this struct. If we add fields to this struct in the future, we + * can distinguish the old and new formats by pd_lower. + */ +typedef struct GISTDeletedPageContents +{ + /* last xid which could see the page in a scan */ + FullTransactionId deleteXid; +} GISTDeletedPageContents; + +static inline void +GistPageSetDeleted(Page page, FullTransactionId deletexid) +{ + Assert(PageIsEmpty(page)); + + GistPageGetOpaque(page)->flags |= F_DELETED; + ((PageHeader) page)->pd_lower = MAXALIGN(SizeOfPageHeaderData) + sizeof(GISTDeletedPageContents); + + ((GISTDeletedPageContents *) PageGetContents(page))->deleteXid = deletexid; +} + +static inline FullTransactionId +GistPageGetDeleteXid(Page page) +{ + Assert(GistPageIsDeleted(page)); + + /* Is the deleteXid field present? */ + if (((PageHeader) page)->pd_lower >= MAXALIGN(SizeOfPageHeaderData) + + offsetof(GISTDeletedPageContents, deleteXid) + sizeof(FullTransactionId)) + { + return ((GISTDeletedPageContents *) PageGetContents(page))->deleteXid; + } + else + return FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId); +} + +/* + * Vector of GISTENTRY structs; user-defined methods union and picksplit + * take it as one of their arguments + */ +typedef struct +{ + int32 n; /* number of elements */ + GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]; +} GistEntryVector; + +#define GEVHDRSZ (offsetof(GistEntryVector, vector)) + +/* + * macro to initialize a GISTENTRY + */ +#define gistentryinit(e, k, r, pg, o, l) \ + do { (e).key = (k); (e).rel = (r); (e).page = (pg); \ + (e).offset = (o); (e).leafkey = (l); } while (0) + +#endif /* GIST_H */ diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h new file mode 100644 index 0000000..240131e --- /dev/null +++ b/src/include/access/gist_private.h @@ -0,0 +1,571 @@ +/*------------------------------------------------------------------------- + * + * gist_private.h + * private declarations for GiST -- declarations related to the + * internal implementation of GiST, not the public API + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/gist_private.h + * + *------------------------------------------------------------------------- + */ +#ifndef GIST_PRIVATE_H +#define GIST_PRIVATE_H + +#include "access/amapi.h" +#include "access/gist.h" +#include "access/itup.h" +#include "lib/pairingheap.h" +#include "storage/bufmgr.h" +#include "storage/buffile.h" +#include "utils/hsearch.h" +#include "access/genam.h" + +/* + * Maximum number of "halves" a page can be split into in one operation. + * Typically a split produces 2 halves, but can be more if keys have very + * different lengths, or when inserting multiple keys in one operation (as + * when inserting downlinks to an internal node). There is no theoretical + * limit on this, but in practice if you get more than a handful page halves + * in one split, there's something wrong with the opclass implementation. + * GIST_MAX_SPLIT_PAGES is an arbitrary limit on that, used to size some + * local arrays used during split. Note that there is also a limit on the + * number of buffers that can be held locked at a time, MAX_SIMUL_LWLOCKS, + * so if you raise this higher than that limit, you'll just get a different + * error. + */ +#define GIST_MAX_SPLIT_PAGES 75 + +/* Buffer lock modes */ +#define GIST_SHARE BUFFER_LOCK_SHARE +#define GIST_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE +#define GIST_UNLOCK BUFFER_LOCK_UNLOCK + +typedef struct +{ + BlockNumber prev; + uint32 freespace; + char tupledata[FLEXIBLE_ARRAY_MEMBER]; +} GISTNodeBufferPage; + +#define BUFFER_PAGE_DATA_OFFSET MAXALIGN(offsetof(GISTNodeBufferPage, tupledata)) +/* Returns free space in node buffer page */ +#define PAGE_FREE_SPACE(nbp) (nbp->freespace) +/* Checks if node buffer page is empty */ +#define PAGE_IS_EMPTY(nbp) (nbp->freespace == BLCKSZ - BUFFER_PAGE_DATA_OFFSET) +/* Checks if node buffers page don't contain sufficient space for index tuple */ +#define PAGE_NO_SPACE(nbp, itup) (PAGE_FREE_SPACE(nbp) < \ + MAXALIGN(IndexTupleSize(itup))) + +/* + * GISTSTATE: information needed for any GiST index operation + * + * This struct retains call info for the index's opclass-specific support + * functions (per index column), plus the index's tuple descriptor. + * + * scanCxt holds the GISTSTATE itself as well as any data that lives for the + * lifetime of the index operation. We pass this to the support functions + * via fn_mcxt, so that they can store scan-lifespan data in it. The + * functions are invoked in tempCxt, which is typically short-lifespan + * (that is, it's reset after each tuple). However, tempCxt can be the same + * as scanCxt if we're not bothering with per-tuple context resets. + */ +typedef struct GISTSTATE +{ + MemoryContext scanCxt; /* context for scan-lifespan data */ + MemoryContext tempCxt; /* short-term context for calling functions */ + + TupleDesc leafTupdesc; /* index's tuple descriptor */ + TupleDesc nonLeafTupdesc; /* truncated tuple descriptor for non-leaf + * pages */ + TupleDesc fetchTupdesc; /* tuple descriptor for tuples returned in an + * index-only scan */ + + FmgrInfo consistentFn[INDEX_MAX_KEYS]; + FmgrInfo unionFn[INDEX_MAX_KEYS]; + FmgrInfo compressFn[INDEX_MAX_KEYS]; + FmgrInfo decompressFn[INDEX_MAX_KEYS]; + FmgrInfo penaltyFn[INDEX_MAX_KEYS]; + FmgrInfo picksplitFn[INDEX_MAX_KEYS]; + FmgrInfo equalFn[INDEX_MAX_KEYS]; + FmgrInfo distanceFn[INDEX_MAX_KEYS]; + FmgrInfo fetchFn[INDEX_MAX_KEYS]; + + /* Collations to pass to the support functions */ + Oid supportCollation[INDEX_MAX_KEYS]; +} GISTSTATE; + + +/* + * During a GiST index search, we must maintain a queue of unvisited items, + * which can be either individual heap tuples or whole index pages. If it + * is an ordered search, the unvisited items should be visited in distance + * order. Unvisited items at the same distance should be visited in + * depth-first order, that is heap items first, then lower index pages, then + * upper index pages; this rule avoids doing extra work during a search that + * ends early due to LIMIT. + * + * To perform an ordered search, we use a pairing heap to manage the + * distance-order queue. In a non-ordered search (no order-by operators), + * we use it to return heap tuples before unvisited index pages, to + * ensure depth-first order, but all entries are otherwise considered + * equal. + */ + +/* Individual heap tuple to be visited */ +typedef struct GISTSearchHeapItem +{ + ItemPointerData heapPtr; + bool recheck; /* T if quals must be rechecked */ + bool recheckDistances; /* T if distances must be rechecked */ + HeapTuple recontup; /* data reconstructed from the index, used in + * index-only scans */ + OffsetNumber offnum; /* track offset in page to mark tuple as + * LP_DEAD */ +} GISTSearchHeapItem; + +/* Unvisited item, either index page or heap tuple */ +typedef struct GISTSearchItem +{ + pairingheap_node phNode; + BlockNumber blkno; /* index page number, or InvalidBlockNumber */ + union + { + GistNSN parentlsn; /* parent page's LSN, if index page */ + /* we must store parentlsn to detect whether a split occurred */ + GISTSearchHeapItem heap; /* heap info, if heap tuple */ + } data; + + /* numberOfOrderBys entries */ + IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]; +} GISTSearchItem; + +#define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber) + +#define SizeOfGISTSearchItem(n_distances) \ + (offsetof(GISTSearchItem, distances) + \ + sizeof(IndexOrderByDistance) * (n_distances)) + +/* + * GISTScanOpaqueData: private state for a scan of a GiST index + */ +typedef struct GISTScanOpaqueData +{ + GISTSTATE *giststate; /* index information, see above */ + Oid *orderByTypes; /* datatypes of ORDER BY expressions */ + + pairingheap *queue; /* queue of unvisited items */ + MemoryContext queueCxt; /* context holding the queue */ + bool qual_ok; /* false if qual can never be satisfied */ + bool firstCall; /* true until first gistgettuple call */ + + /* pre-allocated workspace arrays */ + IndexOrderByDistance *distances; /* output area for gistindex_keytest */ + + /* info about killed items if any (killedItems is NULL if never used) */ + OffsetNumber *killedItems; /* offset numbers of killed items */ + int numKilled; /* number of currently stored items */ + BlockNumber curBlkno; /* current number of block */ + GistNSN curPageLSN; /* pos in the WAL stream when page was read */ + + /* In a non-ordered search, returnable heap items are stored here: */ + GISTSearchHeapItem pageData[BLCKSZ / sizeof(IndexTupleData)]; + OffsetNumber nPageData; /* number of valid items in array */ + OffsetNumber curPageData; /* next item to return */ + MemoryContext pageDataCxt; /* context holding the fetched tuples, for + * index-only scans */ +} GISTScanOpaqueData; + +typedef GISTScanOpaqueData *GISTScanOpaque; + +/* despite the name, gistxlogPage is not part of any xlog record */ +typedef struct gistxlogPage +{ + BlockNumber blkno; + int num; /* number of index tuples following */ +} gistxlogPage; + +/* SplitedPageLayout - gistSplit function result */ +typedef struct SplitedPageLayout +{ + gistxlogPage block; + IndexTupleData *list; + int lenlist; + IndexTuple itup; /* union key for page */ + Page page; /* to operate */ + Buffer buffer; /* to write after all proceed */ + + struct SplitedPageLayout *next; +} SplitedPageLayout; + +/* + * GISTInsertStack used for locking buffers and transfer arguments during + * insertion + */ +typedef struct GISTInsertStack +{ + /* current page */ + BlockNumber blkno; + Buffer buffer; + Page page; + + /* + * log sequence number from page->lsn to recognize page update and compare + * it with page's nsn to recognize page split + */ + GistNSN lsn; + + /* + * If set, we split the page while descending the tree to find an + * insertion target. It means that we need to retry from the parent, + * because the downlink of this page might no longer cover the new key. + */ + bool retry_from_parent; + + /* offset of the downlink in the parent page, that points to this page */ + OffsetNumber downlinkoffnum; + + /* pointer to parent */ + struct GISTInsertStack *parent; +} GISTInsertStack; + +/* Working state and results for multi-column split logic in gistsplit.c */ +typedef struct GistSplitVector +{ + GIST_SPLITVEC splitVector; /* passed to/from user PickSplit method */ + + Datum spl_lattr[INDEX_MAX_KEYS]; /* Union of subkeys in + * splitVector.spl_left */ + bool spl_lisnull[INDEX_MAX_KEYS]; + + Datum spl_rattr[INDEX_MAX_KEYS]; /* Union of subkeys in + * splitVector.spl_right */ + bool spl_risnull[INDEX_MAX_KEYS]; + + bool *spl_dontcare; /* flags tuples which could go to either side + * of the split for zero penalty */ +} GistSplitVector; + +typedef struct +{ + Relation r; + Relation heapRel; + Size freespace; /* free space to be left */ + bool is_build; + + GISTInsertStack *stack; +} GISTInsertState; + +/* root page of a gist index */ +#define GIST_ROOT_BLKNO 0 + +/* + * Before PostgreSQL 9.1, we used to rely on so-called "invalid tuples" on + * inner pages to finish crash recovery of incomplete page splits. If a crash + * happened in the middle of a page split, so that the downlink pointers were + * not yet inserted, crash recovery inserted a special downlink pointer. The + * semantics of an invalid tuple was that it if you encounter one in a scan, + * it must always be followed, because we don't know if the tuples on the + * child page match or not. + * + * We no longer create such invalid tuples, we now mark the left-half of such + * an incomplete split with the F_FOLLOW_RIGHT flag instead, and finish the + * split properly the next time we need to insert on that page. To retain + * on-disk compatibility for the sake of pg_upgrade, we still store 0xffff as + * the offset number of all inner tuples. If we encounter any invalid tuples + * with 0xfffe during insertion, we throw an error, though scans still handle + * them. You should only encounter invalid tuples if you pg_upgrade a pre-9.1 + * gist index which already has invalid tuples in it because of a crash. That + * should be rare, and you are recommended to REINDEX anyway if you have any + * invalid tuples in an index, so throwing an error is as far as we go with + * supporting that. + */ +#define TUPLE_IS_VALID 0xffff +#define TUPLE_IS_INVALID 0xfffe + +#define GistTupleIsInvalid(itup) ( ItemPointerGetOffsetNumber( &((itup)->t_tid) ) == TUPLE_IS_INVALID ) +#define GistTupleSetValid(itup) ItemPointerSetOffsetNumber( &((itup)->t_tid), TUPLE_IS_VALID ) + + + + +/* + * A buffer attached to an internal node, used when building an index in + * buffering mode. + */ +typedef struct +{ + BlockNumber nodeBlocknum; /* index block # this buffer is for */ + int32 blocksCount; /* current # of blocks occupied by buffer */ + + BlockNumber pageBlocknum; /* temporary file block # */ + GISTNodeBufferPage *pageBuffer; /* in-memory buffer page */ + + /* is this buffer queued for emptying? */ + bool queuedForEmptying; + + /* is this a temporary copy, not in the hash table? */ + bool isTemp; + + int level; /* 0 == leaf */ +} GISTNodeBuffer; + +/* + * Does specified level have buffers? (Beware of multiple evaluation of + * arguments.) + */ +#define LEVEL_HAS_BUFFERS(nlevel, gfbb) \ + ((nlevel) != 0 && (nlevel) % (gfbb)->levelStep == 0 && \ + (nlevel) != (gfbb)->rootlevel) + +/* Is specified buffer at least half-filled (should be queued for emptying)? */ +#define BUFFER_HALF_FILLED(nodeBuffer, gfbb) \ + ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer / 2) + +/* + * Is specified buffer full? Our buffers can actually grow indefinitely, + * beyond the "maximum" size, so this just means whether the buffer has grown + * beyond the nominal maximum size. + */ +#define BUFFER_OVERFLOWED(nodeBuffer, gfbb) \ + ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer) + +/* + * Data structure with general information about build buffers. + */ +typedef struct GISTBuildBuffers +{ + /* Persistent memory context for the buffers and metadata. */ + MemoryContext context; + + BufFile *pfile; /* Temporary file to store buffers in */ + long nFileBlocks; /* Current size of the temporary file */ + + /* + * resizable array of free blocks. + */ + long *freeBlocks; + int nFreeBlocks; /* # of currently free blocks in the array */ + int freeBlocksLen; /* current allocated length of the array */ + + /* Hash for buffers by block number */ + HTAB *nodeBuffersTab; + + /* List of buffers scheduled for emptying */ + List *bufferEmptyingQueue; + + /* + * Parameters to the buffering build algorithm. levelStep determines which + * levels in the tree have buffers, and pagesPerBuffer determines how + * large each buffer is. + */ + int levelStep; + int pagesPerBuffer; + + /* Array of lists of buffers on each level, for final emptying */ + List **buffersOnLevels; + int buffersOnLevelsLen; + + /* + * Dynamically-sized array of buffers that currently have their last page + * loaded in main memory. + */ + GISTNodeBuffer **loadedBuffers; + int loadedBuffersCount; /* # of entries in loadedBuffers */ + int loadedBuffersLen; /* allocated size of loadedBuffers */ + + /* Level of the current root node (= height of the index tree - 1) */ + int rootlevel; +} GISTBuildBuffers; + +/* GiSTOptions->buffering_mode values */ +typedef enum GistOptBufferingMode +{ + GIST_OPTION_BUFFERING_AUTO, + GIST_OPTION_BUFFERING_ON, + GIST_OPTION_BUFFERING_OFF +} GistOptBufferingMode; + +/* + * Storage type for GiST's reloptions + */ +typedef struct GiSTOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ + GistOptBufferingMode buffering_mode; /* buffering build mode */ +} GiSTOptions; + +/* gist.c */ +extern void gistbuildempty(Relation index); +extern bool gistinsert(Relation r, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); +extern MemoryContext createTempGistContext(void); +extern GISTSTATE *initGISTstate(Relation index); +extern void freeGISTstate(GISTSTATE *giststate); +extern void gistdoinsert(Relation r, + IndexTuple itup, + Size freespace, + GISTSTATE *giststate, + Relation heapRel, + bool is_build); + +/* A List of these is returned from gistplacetopage() in *splitinfo */ +typedef struct +{ + Buffer buf; /* the split page "half" */ + IndexTuple downlink; /* downlink for this half. */ +} GISTPageSplitInfo; + +extern bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, + Buffer buffer, + IndexTuple *itup, int ntup, + OffsetNumber oldoffnum, BlockNumber *newblkno, + Buffer leftchildbuf, + List **splitinfo, + bool markfollowright, + Relation heapRel, + bool is_build); + +extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup, + int len, GISTSTATE *giststate); + +/* gistxlog.c */ +extern XLogRecPtr gistXLogPageDelete(Buffer buffer, + FullTransactionId xid, Buffer parentBuffer, + OffsetNumber downlinkOffset); + +extern void gistXLogPageReuse(Relation rel, BlockNumber blkno, + FullTransactionId latestRemovedXid); + +extern XLogRecPtr gistXLogUpdate(Buffer buffer, + OffsetNumber *todelete, int ntodelete, + IndexTuple *itup, int ntup, + Buffer leftchild); + +extern XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, + int ntodelete, TransactionId latestRemovedXid); + +extern XLogRecPtr gistXLogSplit(bool page_is_leaf, + SplitedPageLayout *dist, + BlockNumber origrlink, GistNSN oldnsn, + Buffer leftchild, bool markfollowright); + +extern XLogRecPtr gistXLogAssignLSN(void); + +/* gistget.c */ +extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern bool gistcanreturn(Relation index, int attno); + +/* gistvalidate.c */ +extern bool gistvalidate(Oid opclassoid); +extern void gistadjustmembers(Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +/* gistutil.c */ + +#define GiSTPageSize \ + ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) ) + +#define GIST_MIN_FILLFACTOR 10 +#define GIST_DEFAULT_FILLFACTOR 90 + +extern bytea *gistoptions(Datum reloptions, bool validate); +extern bool gistproperty(Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull); +extern bool gistfitpage(IndexTuple *itvec, int len); +extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace); +extern void gistcheckpage(Relation rel, Buffer buf); +extern Buffer gistNewBuffer(Relation r); +extern bool gistPageRecyclable(Page page); +extern void gistfillbuffer(Page page, IndexTuple *itup, int len, + OffsetNumber off); +extern IndexTuple *gistextractpage(Page page, int *len /* out */ ); +extern IndexTuple *gistjoinvector(IndexTuple *itvec, int *len, + IndexTuple *additvec, int addlen); +extern IndexTupleData *gistfillitupvec(IndexTuple *vec, int veclen, int *memlen); + +extern IndexTuple gistunion(Relation r, IndexTuple *itvec, + int len, GISTSTATE *giststate); +extern IndexTuple gistgetadjusted(Relation r, + IndexTuple oldtup, + IndexTuple addtup, + GISTSTATE *giststate); +extern IndexTuple gistFormTuple(GISTSTATE *giststate, + Relation r, Datum *attdata, bool *isnull, bool isleaf); +extern void gistCompressValues(GISTSTATE *giststate, Relation r, + Datum *attdata, bool *isnull, bool isleaf, Datum *compatt); + +extern OffsetNumber gistchoose(Relation r, Page p, + IndexTuple it, + GISTSTATE *giststate); + +extern void GISTInitBuffer(Buffer b, uint32 f); +extern void gistinitpage(Page page, uint32 f); +extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, + Datum k, Relation r, Page pg, OffsetNumber o, + bool l, bool isNull); + +extern float gistpenalty(GISTSTATE *giststate, int attno, + GISTENTRY *key1, bool isNull1, + GISTENTRY *key2, bool isNull2); +extern void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, + Datum *attr, bool *isnull); +extern bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b); +extern void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, + OffsetNumber o, GISTENTRY *attdata, bool *isnull); +extern HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, + IndexTuple tuple); +extern void gistMakeUnionKey(GISTSTATE *giststate, int attno, + GISTENTRY *entry1, bool isnull1, + GISTENTRY *entry2, bool isnull2, + Datum *dst, bool *dstisnull); + +extern XLogRecPtr gistGetFakeLSN(Relation rel); + +/* gistvacuum.c */ +extern IndexBulkDeleteResult *gistbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *gistvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); + +/* gistsplit.c */ +extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup, + int len, GISTSTATE *giststate, + GistSplitVector *v, + int attno); + +/* gistbuild.c */ +extern IndexBuildResult *gistbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void gistValidateBufferingOption(const char *value); + +/* gistbuildbuffers.c */ +extern GISTBuildBuffers *gistInitBuildBuffers(int pagesPerBuffer, int levelStep, + int maxLevel); +extern GISTNodeBuffer *gistGetNodeBuffer(GISTBuildBuffers *gfbb, + GISTSTATE *giststate, + BlockNumber blkno, int level); +extern void gistPushItupToNodeBuffer(GISTBuildBuffers *gfbb, + GISTNodeBuffer *nodeBuffer, IndexTuple item); +extern bool gistPopItupFromNodeBuffer(GISTBuildBuffers *gfbb, + GISTNodeBuffer *nodeBuffer, IndexTuple *item); +extern void gistFreeBuildBuffers(GISTBuildBuffers *gfbb); +extern void gistRelocateBuildBuffersOnSplit(GISTBuildBuffers *gfbb, + GISTSTATE *giststate, Relation r, + int level, Buffer buffer, + List *splitinfo); +extern void gistUnloadNodeBuffers(GISTBuildBuffers *gfbb); + +#endif /* GIST_PRIVATE_H */ diff --git a/src/include/access/gistscan.h b/src/include/access/gistscan.h new file mode 100644 index 0000000..bafed97 --- /dev/null +++ b/src/include/access/gistscan.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * gistscan.h + * routines defined in access/gist/gistscan.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/gistscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef GISTSCAN_H +#define GISTSCAN_H + +#include "access/amapi.h" + +extern IndexScanDesc gistbeginscan(Relation r, int nkeys, int norderbys); +extern void gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, + ScanKey orderbys, int norderbys); +extern void gistendscan(IndexScanDesc scan); + +#endif /* GISTSCAN_H */ diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h new file mode 100644 index 0000000..4537e67 --- /dev/null +++ b/src/include/access/gistxlog.h @@ -0,0 +1,114 @@ +/*------------------------------------------------------------------------- + * + * gistxlog.h + * gist xlog routines + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/gistxlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef GIST_XLOG_H +#define GIST_XLOG_H + +#include "access/gist.h" +#include "access/xlogreader.h" +#include "lib/stringinfo.h" + +#define XLOG_GIST_PAGE_UPDATE 0x00 +#define XLOG_GIST_DELETE 0x10 /* delete leaf index tuples for a + * page */ +#define XLOG_GIST_PAGE_REUSE 0x20 /* old page is about to be reused + * from FSM */ +#define XLOG_GIST_PAGE_SPLIT 0x30 + /* #define XLOG_GIST_INSERT_COMPLETE 0x40 */ /* not used anymore */ + /* #define XLOG_GIST_CREATE_INDEX 0x50 */ /* not used anymore */ +#define XLOG_GIST_PAGE_DELETE 0x60 +#define XLOG_GIST_ASSIGN_LSN 0x70 /* nop, assign new LSN */ + +/* + * Backup Blk 0: updated page. + * Backup Blk 1: If this operation completes a page split, by inserting a + * downlink for the split page, the left half of the split + */ +typedef struct gistxlogPageUpdate +{ + /* number of deleted offsets */ + uint16 ntodelete; + uint16 ntoinsert; + + /* + * In payload of blk 0 : 1. todelete OffsetNumbers 2. tuples to insert + */ +} gistxlogPageUpdate; + +/* + * Backup Blk 0: Leaf page, whose index tuples are deleted. + */ +typedef struct gistxlogDelete +{ + TransactionId latestRemovedXid; + uint16 ntodelete; /* number of deleted offsets */ + + /* + * In payload of blk 0 : todelete OffsetNumbers + */ +} gistxlogDelete; + +#define SizeOfGistxlogDelete (offsetof(gistxlogDelete, ntodelete) + sizeof(uint16)) + +/* + * Backup Blk 0: If this operation completes a page split, by inserting a + * downlink for the split page, the left half of the split + * Backup Blk 1 - npage: split pages (1 is the original page) + */ +typedef struct gistxlogPageSplit +{ + BlockNumber origrlink; /* rightlink of the page before split */ + GistNSN orignsn; /* NSN of the page before split */ + bool origleaf; /* was splitted page a leaf page? */ + + uint16 npage; /* # of pages in the split */ + bool markfollowright; /* set F_FOLLOW_RIGHT flags */ + + /* + * follow: 1. gistxlogPage and array of IndexTupleData per page + */ +} gistxlogPageSplit; + +/* + * Backup Blk 0: page that was deleted. + * Backup Blk 1: parent page, containing the downlink to the deleted page. + */ +typedef struct gistxlogPageDelete +{ + FullTransactionId deleteXid; /* last Xid which could see page in scan */ + OffsetNumber downlinkOffset; /* Offset of downlink referencing this + * page */ +} gistxlogPageDelete; + +#define SizeOfGistxlogPageDelete (offsetof(gistxlogPageDelete, downlinkOffset) + sizeof(OffsetNumber)) + + +/* + * This is what we need to know about page reuse, for hot standby. + */ +typedef struct gistxlogPageReuse +{ + RelFileNode node; + BlockNumber block; + FullTransactionId latestRemovedFullXid; +} gistxlogPageReuse; + +#define SizeOfGistxlogPageReuse (offsetof(gistxlogPageReuse, latestRemovedFullXid) + sizeof(FullTransactionId)) + +extern void gist_redo(XLogReaderState *record); +extern void gist_desc(StringInfo buf, XLogReaderState *record); +extern const char *gist_identify(uint8 info); +extern void gist_xlog_startup(void); +extern void gist_xlog_cleanup(void); +extern void gist_mask(char *pagedata, BlockNumber blkno); + +#endif diff --git a/src/include/access/hash.h b/src/include/access/hash.h new file mode 100644 index 0000000..da37284 --- /dev/null +++ b/src/include/access/hash.h @@ -0,0 +1,485 @@ +/*------------------------------------------------------------------------- + * + * hash.h + * header file for postgres hash access method implementation + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/hash.h + * + * NOTES + * modeled after Margo Seltzer's hash implementation for unix. + * + *------------------------------------------------------------------------- + */ +#ifndef HASH_H +#define HASH_H + +#include "access/amapi.h" +#include "access/itup.h" +#include "access/sdir.h" +#include "catalog/pg_am_d.h" +#include "common/hashfn.h" +#include "lib/stringinfo.h" +#include "storage/bufmgr.h" +#include "storage/lockdefs.h" +#include "utils/hsearch.h" +#include "utils/relcache.h" + +/* + * Mapping from hash bucket number to physical block number of bucket's + * starting page. Beware of multiple evaluations of argument! + */ +typedef uint32 Bucket; + +#define InvalidBucket ((Bucket) 0xFFFFFFFF) + +#define BUCKET_TO_BLKNO(metap,B) \ + ((BlockNumber) ((B) + ((B) ? (metap)->hashm_spares[_hash_spareindex((B)+1)-1] : 0)) + 1) + +/* + * Special space for hash index pages. + * + * hasho_flag's LH_PAGE_TYPE bits tell us which type of page we're looking at. + * Additional bits in the flag word are used for more transient purposes. + * + * To test a page's type, do (hasho_flag & LH_PAGE_TYPE) == LH_xxx_PAGE. + * However, we ensure that each used page type has a distinct bit so that + * we can OR together page types for uses such as the allowable-page-types + * argument of _hash_checkpage(). + */ +#define LH_UNUSED_PAGE (0) +#define LH_OVERFLOW_PAGE (1 << 0) +#define LH_BUCKET_PAGE (1 << 1) +#define LH_BITMAP_PAGE (1 << 2) +#define LH_META_PAGE (1 << 3) +#define LH_BUCKET_BEING_POPULATED (1 << 4) +#define LH_BUCKET_BEING_SPLIT (1 << 5) +#define LH_BUCKET_NEEDS_SPLIT_CLEANUP (1 << 6) +#define LH_PAGE_HAS_DEAD_TUPLES (1 << 7) + +#define LH_PAGE_TYPE \ + (LH_OVERFLOW_PAGE | LH_BUCKET_PAGE | LH_BITMAP_PAGE | LH_META_PAGE) + +/* + * In an overflow page, hasho_prevblkno stores the block number of the previous + * page in the bucket chain; in a bucket page, hasho_prevblkno stores the + * hashm_maxbucket value as of the last time the bucket was last split, or + * else as of the time the bucket was created. The latter convention is used + * to determine whether a cached copy of the metapage is too stale to be used + * without needing to lock or pin the metapage. + * + * hasho_nextblkno is always the block number of the next page in the + * bucket chain, or InvalidBlockNumber if there are no more such pages. + */ +typedef struct HashPageOpaqueData +{ + BlockNumber hasho_prevblkno; /* see above */ + BlockNumber hasho_nextblkno; /* see above */ + Bucket hasho_bucket; /* bucket number this pg belongs to */ + uint16 hasho_flag; /* page type code + flag bits, see above */ + uint16 hasho_page_id; /* for identification of hash indexes */ +} HashPageOpaqueData; + +typedef HashPageOpaqueData *HashPageOpaque; + +#define HashPageGetOpaque(page) ((HashPageOpaque) PageGetSpecialPointer(page)) + +#define H_NEEDS_SPLIT_CLEANUP(opaque) (((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0) +#define H_BUCKET_BEING_SPLIT(opaque) (((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0) +#define H_BUCKET_BEING_POPULATED(opaque) (((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0) +#define H_HAS_DEAD_TUPLES(opaque) (((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) != 0) + +/* + * The page ID is for the convenience of pg_filedump and similar utilities, + * which otherwise would have a hard time telling pages of different index + * types apart. It should be the last 2 bytes on the page. This is more or + * less "free" due to alignment considerations. + */ +#define HASHO_PAGE_ID 0xFF80 + +typedef struct HashScanPosItem /* what we remember about each match */ +{ + ItemPointerData heapTid; /* TID of referenced heap item */ + OffsetNumber indexOffset; /* index item's location within page */ +} HashScanPosItem; + +typedef struct HashScanPosData +{ + Buffer buf; /* if valid, the buffer is pinned */ + BlockNumber currPage; /* current hash index page */ + BlockNumber nextPage; /* next overflow page */ + BlockNumber prevPage; /* prev overflow or bucket page */ + + /* + * The items array is always ordered in index order (ie, increasing + * indexoffset). When scanning backwards it is convenient to fill the + * array back-to-front, so we start at the last slot and fill downwards. + * Hence we need both a first-valid-entry and a last-valid-entry counter. + * itemIndex is a cursor showing which entry was last returned to caller. + */ + int firstItem; /* first valid index in items[] */ + int lastItem; /* last valid index in items[] */ + int itemIndex; /* current index in items[] */ + + HashScanPosItem items[MaxIndexTuplesPerPage]; /* MUST BE LAST */ +} HashScanPosData; + +#define HashScanPosIsPinned(scanpos) \ +( \ + AssertMacro(BlockNumberIsValid((scanpos).currPage) || \ + !BufferIsValid((scanpos).buf)), \ + BufferIsValid((scanpos).buf) \ +) + +#define HashScanPosIsValid(scanpos) \ +( \ + AssertMacro(BlockNumberIsValid((scanpos).currPage) || \ + !BufferIsValid((scanpos).buf)), \ + BlockNumberIsValid((scanpos).currPage) \ +) + +#define HashScanPosInvalidate(scanpos) \ + do { \ + (scanpos).buf = InvalidBuffer; \ + (scanpos).currPage = InvalidBlockNumber; \ + (scanpos).nextPage = InvalidBlockNumber; \ + (scanpos).prevPage = InvalidBlockNumber; \ + (scanpos).firstItem = 0; \ + (scanpos).lastItem = 0; \ + (scanpos).itemIndex = 0; \ + } while (0) + +/* + * HashScanOpaqueData is private state for a hash index scan. + */ +typedef struct HashScanOpaqueData +{ + /* Hash value of the scan key, ie, the hash key we seek */ + uint32 hashso_sk_hash; + + /* remember the buffer associated with primary bucket */ + Buffer hashso_bucket_buf; + + /* + * remember the buffer associated with primary bucket page of bucket being + * split. it is required during the scan of the bucket which is being + * populated during split operation. + */ + Buffer hashso_split_bucket_buf; + + /* Whether scan starts on bucket being populated due to split */ + bool hashso_buc_populated; + + /* + * Whether scanning bucket being split? The value of this parameter is + * referred only when hashso_buc_populated is true. + */ + bool hashso_buc_split; + /* info about killed items if any (killedItems is NULL if never used) */ + int *killedItems; /* currPos.items indexes of killed items */ + int numKilled; /* number of currently stored items */ + + /* + * Identify all the matching items on a page and save them in + * HashScanPosData + */ + HashScanPosData currPos; /* current position data */ +} HashScanOpaqueData; + +typedef HashScanOpaqueData *HashScanOpaque; + +/* + * Definitions for metapage. + */ + +#define HASH_METAPAGE 0 /* metapage is always block 0 */ + +#define HASH_MAGIC 0x6440640 +#define HASH_VERSION 4 + +/* + * spares[] holds the number of overflow pages currently allocated at or + * before a certain splitpoint. For example, if spares[3] = 7 then there are + * 7 ovflpages before splitpoint 3 (compare BUCKET_TO_BLKNO macro). The + * value in spares[ovflpoint] increases as overflow pages are added at the + * end of the index. Once ovflpoint increases (ie, we have actually allocated + * the bucket pages belonging to that splitpoint) the number of spares at the + * prior splitpoint cannot change anymore. + * + * ovflpages that have been recycled for reuse can be found by looking at + * bitmaps that are stored within ovflpages dedicated for the purpose. + * The blknos of these bitmap pages are kept in mapp[]; nmaps is the + * number of currently existing bitmaps. + * + * The limitation on the size of spares[] comes from the fact that there's + * no point in having more than 2^32 buckets with only uint32 hashcodes. + * (Note: The value of HASH_MAX_SPLITPOINTS which is the size of spares[] is + * adjusted in such a way to accommodate multi phased allocation of buckets + * after HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE). + * + * There is no particular upper limit on the size of mapp[], other than + * needing to fit into the metapage. (With 8K block size, 1024 bitmaps + * limit us to 256 GB of overflow space...). For smaller block size we + * can not use 1024 bitmaps as it will lead to the meta page data crossing + * the block size boundary. So we use BLCKSZ to determine the maximum number + * of bitmaps. + */ +#define HASH_MAX_BITMAPS Min(BLCKSZ / 8, 1024) + +#define HASH_SPLITPOINT_PHASE_BITS 2 +#define HASH_SPLITPOINT_PHASES_PER_GRP (1 << HASH_SPLITPOINT_PHASE_BITS) +#define HASH_SPLITPOINT_PHASE_MASK (HASH_SPLITPOINT_PHASES_PER_GRP - 1) +#define HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE 10 + +/* defines max number of splitpoint phases a hash index can have */ +#define HASH_MAX_SPLITPOINT_GROUP 32 +#define HASH_MAX_SPLITPOINTS \ + (((HASH_MAX_SPLITPOINT_GROUP - HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE) * \ + HASH_SPLITPOINT_PHASES_PER_GRP) + \ + HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE) + +typedef struct HashMetaPageData +{ + uint32 hashm_magic; /* magic no. for hash tables */ + uint32 hashm_version; /* version ID */ + double hashm_ntuples; /* number of tuples stored in the table */ + uint16 hashm_ffactor; /* target fill factor (tuples/bucket) */ + uint16 hashm_bsize; /* index page size (bytes) */ + uint16 hashm_bmsize; /* bitmap array size (bytes) - must be a power + * of 2 */ + uint16 hashm_bmshift; /* log2(bitmap array size in BITS) */ + uint32 hashm_maxbucket; /* ID of maximum bucket in use */ + uint32 hashm_highmask; /* mask to modulo into entire table */ + uint32 hashm_lowmask; /* mask to modulo into lower half of table */ + uint32 hashm_ovflpoint; /* splitpoint from which ovflpage being + * allocated */ + uint32 hashm_firstfree; /* lowest-number free ovflpage (bit#) */ + uint32 hashm_nmaps; /* number of bitmap pages */ + RegProcedure hashm_procid; /* hash function id from pg_proc */ + uint32 hashm_spares[HASH_MAX_SPLITPOINTS]; /* spare pages before each + * splitpoint */ + BlockNumber hashm_mapp[HASH_MAX_BITMAPS]; /* blknos of ovfl bitmaps */ +} HashMetaPageData; + +typedef HashMetaPageData *HashMetaPage; + +typedef struct HashOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ +} HashOptions; + +#define HashGetFillFactor(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == HASH_AM_OID), \ + (relation)->rd_options ? \ + ((HashOptions *) (relation)->rd_options)->fillfactor : \ + HASH_DEFAULT_FILLFACTOR) +#define HashGetTargetPageUsage(relation) \ + (BLCKSZ * HashGetFillFactor(relation) / 100) + +/* + * Maximum size of a hash index item (it's okay to have only one per page) + */ +#define HashMaxItemSize(page) \ + MAXALIGN_DOWN(PageGetPageSize(page) - \ + SizeOfPageHeaderData - \ + sizeof(ItemIdData) - \ + MAXALIGN(sizeof(HashPageOpaqueData))) + +#define INDEX_MOVED_BY_SPLIT_MASK INDEX_AM_RESERVED_BIT + +#define HASH_MIN_FILLFACTOR 10 +#define HASH_DEFAULT_FILLFACTOR 75 + +/* + * Constants + */ +#define BYTE_TO_BIT 3 /* 2^3 bits/byte */ +#define ALL_SET ((uint32) ~0) + +/* + * Bitmap pages do not contain tuples. They do contain the standard + * page headers and trailers; however, everything in between is a + * giant bit array. The number of bits that fit on a page obviously + * depends on the page size and the header/trailer overhead. We require + * the number of bits per page to be a power of 2. + */ +#define BMPGSZ_BYTE(metap) ((metap)->hashm_bmsize) +#define BMPGSZ_BIT(metap) ((metap)->hashm_bmsize << BYTE_TO_BIT) +#define BMPG_SHIFT(metap) ((metap)->hashm_bmshift) +#define BMPG_MASK(metap) (BMPGSZ_BIT(metap) - 1) + +#define HashPageGetBitmap(page) \ + ((uint32 *) PageGetContents(page)) + +#define HashGetMaxBitmapSize(page) \ + (PageGetPageSize((Page) page) - \ + (MAXALIGN(SizeOfPageHeaderData) + MAXALIGN(sizeof(HashPageOpaqueData)))) + +#define HashPageGetMeta(page) \ + ((HashMetaPage) PageGetContents(page)) + +/* + * The number of bits in an ovflpage bitmap word. + */ +#define BITS_PER_MAP 32 /* Number of bits in uint32 */ + +/* Given the address of the beginning of a bit map, clear/set the nth bit */ +#define CLRBIT(A, N) ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP))) +#define SETBIT(A, N) ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP))) +#define ISSET(A, N) ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP))) + +/* + * page-level and high-level locking modes (see README) + */ +#define HASH_READ BUFFER_LOCK_SHARE +#define HASH_WRITE BUFFER_LOCK_EXCLUSIVE +#define HASH_NOLOCK (-1) + +/* + * When a new operator class is declared, we require that the user supply + * us with an amproc function for hashing a key of the new type, returning + * a 32-bit hash value. We call this the "standard" hash function. We + * also allow an optional "extended" hash function which accepts a salt and + * returns a 64-bit hash value. This is highly recommended but, for reasons + * of backward compatibility, optional. + * + * When the salt is 0, the low 32 bits of the value returned by the extended + * hash function should match the value that would have been returned by the + * standard hash function. + */ +#define HASHSTANDARD_PROC 1 +#define HASHEXTENDED_PROC 2 +#define HASHOPTIONS_PROC 3 +#define HASHNProcs 3 + + +/* public routines */ + +extern IndexBuildResult *hashbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void hashbuildempty(Relation index); +extern bool hashinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); +extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys); +extern void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void hashendscan(IndexScanDesc scan); +extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bytea *hashoptions(Datum reloptions, bool validate); +extern bool hashvalidate(Oid opclassoid); +extern void hashadjustmembers(Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +/* private routines */ + +/* hashinsert.c */ +extern void _hash_doinsert(Relation rel, IndexTuple itup, Relation heapRel); +extern OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf, + Size itemsize, IndexTuple itup); +extern void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups, + OffsetNumber *itup_offsets, uint16 nitups); + +/* hashovfl.c */ +extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin); +extern BlockNumber _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf, + Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets, + Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy); +extern void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage); +extern void _hash_squeezebucket(Relation rel, + Bucket bucket, BlockNumber bucket_blkno, + Buffer bucket_buf, + BufferAccessStrategy bstrategy); +extern uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno); + +/* hashpage.c */ +extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno, + int access, int flags); +extern Buffer _hash_getbuf_with_condlock_cleanup(Relation rel, + BlockNumber blkno, int flags); +extern HashMetaPage _hash_getcachedmetap(Relation rel, Buffer *metabuf, + bool force_refresh); +extern Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, + int access, + HashMetaPage *cachedmetap); +extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno); +extern void _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket, + uint32 flag, bool initpage); +extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, + ForkNumber forkNum); +extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, + int access, int flags, + BufferAccessStrategy bstrategy); +extern void _hash_relbuf(Relation rel, Buffer buf); +extern void _hash_dropbuf(Relation rel, Buffer buf); +extern void _hash_dropscanbuf(Relation rel, HashScanOpaque so); +extern uint32 _hash_init(Relation rel, double num_tuples, + ForkNumber forkNum); +extern void _hash_init_metabuffer(Buffer buf, double num_tuples, + RegProcedure procid, uint16 ffactor, bool initpage); +extern void _hash_pageinit(Page page, Size size); +extern void _hash_expandtable(Relation rel, Buffer metabuf); +extern void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, + Bucket obucket, uint32 maxbucket, uint32 highmask, + uint32 lowmask); + +/* hashsearch.c */ +extern bool _hash_next(IndexScanDesc scan, ScanDirection dir); +extern bool _hash_first(IndexScanDesc scan, ScanDirection dir); + +/* hashsort.c */ +typedef struct HSpool HSpool; /* opaque struct in hashsort.c */ + +extern HSpool *_h_spoolinit(Relation heap, Relation index, uint32 num_buckets); +extern void _h_spooldestroy(HSpool *hspool); +extern void _h_spool(HSpool *hspool, ItemPointer self, + Datum *values, bool *isnull); +extern void _h_indexbuild(HSpool *hspool, Relation heapRel); + +/* hashutil.c */ +extern bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup); +extern uint32 _hash_datum2hashkey(Relation rel, Datum key); +extern uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype); +extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, + uint32 highmask, uint32 lowmask); +extern uint32 _hash_spareindex(uint32 num_bucket); +extern uint32 _hash_get_totalbuckets(uint32 splitpoint_phase); +extern void _hash_checkpage(Relation rel, Buffer buf, int flags); +extern uint32 _hash_get_indextuple_hashkey(IndexTuple itup); +extern bool _hash_convert_tuple(Relation index, + Datum *user_values, bool *user_isnull, + Datum *index_values, bool *index_isnull); +extern OffsetNumber _hash_binsearch(Page page, uint32 hash_value); +extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value); +extern BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket); +extern BlockNumber _hash_get_newblock_from_oldbucket(Relation rel, Bucket old_bucket); +extern Bucket _hash_get_newbucket_from_oldbucket(Relation rel, Bucket old_bucket, + uint32 lowmask, uint32 maxbucket); +extern void _hash_kill_items(IndexScanDesc scan); + +/* hash.c */ +extern void hashbucketcleanup(Relation rel, Bucket cur_bucket, + Buffer bucket_buf, BlockNumber bucket_blkno, + BufferAccessStrategy bstrategy, + uint32 maxbucket, uint32 highmask, uint32 lowmask, + double *tuples_removed, double *num_index_tuples, + bool split_cleanup, + IndexBulkDeleteCallback callback, void *callback_state); + +#endif /* HASH_H */ diff --git a/src/include/access/hash_xlog.h b/src/include/access/hash_xlog.h new file mode 100644 index 0000000..5923070 --- /dev/null +++ b/src/include/access/hash_xlog.h @@ -0,0 +1,267 @@ +/*------------------------------------------------------------------------- + * + * hash_xlog.h + * header file for Postgres hash AM implementation + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/hash_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef HASH_XLOG_H +#define HASH_XLOG_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/off.h" + +/* Number of buffers required for XLOG_HASH_SQUEEZE_PAGE operation */ +#define HASH_XLOG_FREE_OVFL_BUFS 6 + +/* + * XLOG records for hash operations + */ +#define XLOG_HASH_INIT_META_PAGE 0x00 /* initialize the meta page */ +#define XLOG_HASH_INIT_BITMAP_PAGE 0x10 /* initialize the bitmap page */ +#define XLOG_HASH_INSERT 0x20 /* add index tuple without split */ +#define XLOG_HASH_ADD_OVFL_PAGE 0x30 /* add overflow page */ +#define XLOG_HASH_SPLIT_ALLOCATE_PAGE 0x40 /* allocate new page for split */ +#define XLOG_HASH_SPLIT_PAGE 0x50 /* split page */ +#define XLOG_HASH_SPLIT_COMPLETE 0x60 /* completion of split operation */ +#define XLOG_HASH_MOVE_PAGE_CONTENTS 0x70 /* remove tuples from one page + * and add to another page */ +#define XLOG_HASH_SQUEEZE_PAGE 0x80 /* add tuples to one of the previous + * pages in chain and free the ovfl + * page */ +#define XLOG_HASH_DELETE 0x90 /* delete index tuples from a page */ +#define XLOG_HASH_SPLIT_CLEANUP 0xA0 /* clear split-cleanup flag in primary + * bucket page after deleting tuples + * that are moved due to split */ +#define XLOG_HASH_UPDATE_META_PAGE 0xB0 /* update meta page after vacuum */ + +#define XLOG_HASH_VACUUM_ONE_PAGE 0xC0 /* remove dead tuples from index + * page */ + +/* + * xl_hash_split_allocate_page flag values, 8 bits are available. + */ +#define XLH_SPLIT_META_UPDATE_MASKS (1<<0) +#define XLH_SPLIT_META_UPDATE_SPLITPOINT (1<<1) + +/* + * This is what we need to know about simple (without split) insert. + * + * This data record is used for XLOG_HASH_INSERT + * + * Backup Blk 0: original page (data contains the inserted tuple) + * Backup Blk 1: metapage (HashMetaPageData) + */ +typedef struct xl_hash_insert +{ + OffsetNumber offnum; +} xl_hash_insert; + +#define SizeOfHashInsert (offsetof(xl_hash_insert, offnum) + sizeof(OffsetNumber)) + +/* + * This is what we need to know about addition of overflow page. + * + * This data record is used for XLOG_HASH_ADD_OVFL_PAGE + * + * Backup Blk 0: newly allocated overflow page + * Backup Blk 1: page before new overflow page in the bucket chain + * Backup Blk 2: bitmap page + * Backup Blk 3: new bitmap page + * Backup Blk 4: metapage + */ +typedef struct xl_hash_add_ovfl_page +{ + uint16 bmsize; + bool bmpage_found; +} xl_hash_add_ovfl_page; + +#define SizeOfHashAddOvflPage \ + (offsetof(xl_hash_add_ovfl_page, bmpage_found) + sizeof(bool)) + +/* + * This is what we need to know about allocating a page for split. + * + * This data record is used for XLOG_HASH_SPLIT_ALLOCATE_PAGE + * + * Backup Blk 0: page for old bucket + * Backup Blk 1: page for new bucket + * Backup Blk 2: metapage + */ +typedef struct xl_hash_split_allocate_page +{ + uint32 new_bucket; + uint16 old_bucket_flag; + uint16 new_bucket_flag; + uint8 flags; +} xl_hash_split_allocate_page; + +#define SizeOfHashSplitAllocPage \ + (offsetof(xl_hash_split_allocate_page, flags) + sizeof(uint8)) + +/* + * This is what we need to know about completing the split operation. + * + * This data record is used for XLOG_HASH_SPLIT_COMPLETE + * + * Backup Blk 0: page for old bucket + * Backup Blk 1: page for new bucket + */ +typedef struct xl_hash_split_complete +{ + uint16 old_bucket_flag; + uint16 new_bucket_flag; +} xl_hash_split_complete; + +#define SizeOfHashSplitComplete \ + (offsetof(xl_hash_split_complete, new_bucket_flag) + sizeof(uint16)) + +/* + * This is what we need to know about move page contents required during + * squeeze operation. + * + * This data record is used for XLOG_HASH_MOVE_PAGE_CONTENTS + * + * Backup Blk 0: bucket page + * Backup Blk 1: page containing moved tuples + * Backup Blk 2: page from which tuples will be removed + */ +typedef struct xl_hash_move_page_contents +{ + uint16 ntups; + bool is_prim_bucket_same_wrt; /* true if the page to which + * tuples are moved is same as + * primary bucket page */ +} xl_hash_move_page_contents; + +#define SizeOfHashMovePageContents \ + (offsetof(xl_hash_move_page_contents, is_prim_bucket_same_wrt) + sizeof(bool)) + +/* + * This is what we need to know about the squeeze page operation. + * + * This data record is used for XLOG_HASH_SQUEEZE_PAGE + * + * Backup Blk 0: page containing tuples moved from freed overflow page + * Backup Blk 1: freed overflow page + * Backup Blk 2: page previous to the freed overflow page + * Backup Blk 3: page next to the freed overflow page + * Backup Blk 4: bitmap page containing info of freed overflow page + * Backup Blk 5: meta page + */ +typedef struct xl_hash_squeeze_page +{ + BlockNumber prevblkno; + BlockNumber nextblkno; + uint16 ntups; + bool is_prim_bucket_same_wrt; /* true if the page to which + * tuples are moved is same as + * primary bucket page */ + bool is_prev_bucket_same_wrt; /* true if the page to which + * tuples are moved is the page + * previous to the freed overflow + * page */ +} xl_hash_squeeze_page; + +#define SizeOfHashSqueezePage \ + (offsetof(xl_hash_squeeze_page, is_prev_bucket_same_wrt) + sizeof(bool)) + +/* + * This is what we need to know about the deletion of index tuples from a page. + * + * This data record is used for XLOG_HASH_DELETE + * + * Backup Blk 0: primary bucket page + * Backup Blk 1: page from which tuples are deleted + */ +typedef struct xl_hash_delete +{ + bool clear_dead_marking; /* true if this operation clears + * LH_PAGE_HAS_DEAD_TUPLES flag */ + bool is_primary_bucket_page; /* true if the operation is for + * primary bucket page */ +} xl_hash_delete; + +#define SizeOfHashDelete (offsetof(xl_hash_delete, is_primary_bucket_page) + sizeof(bool)) + +/* + * This is what we need for metapage update operation. + * + * This data record is used for XLOG_HASH_UPDATE_META_PAGE + * + * Backup Blk 0: meta page + */ +typedef struct xl_hash_update_meta_page +{ + double ntuples; +} xl_hash_update_meta_page; + +#define SizeOfHashUpdateMetaPage \ + (offsetof(xl_hash_update_meta_page, ntuples) + sizeof(double)) + +/* + * This is what we need to initialize metapage. + * + * This data record is used for XLOG_HASH_INIT_META_PAGE + * + * Backup Blk 0: meta page + */ +typedef struct xl_hash_init_meta_page +{ + double num_tuples; + RegProcedure procid; + uint16 ffactor; +} xl_hash_init_meta_page; + +#define SizeOfHashInitMetaPage \ + (offsetof(xl_hash_init_meta_page, ffactor) + sizeof(uint16)) + +/* + * This is what we need to initialize bitmap page. + * + * This data record is used for XLOG_HASH_INIT_BITMAP_PAGE + * + * Backup Blk 0: bitmap page + * Backup Blk 1: meta page + */ +typedef struct xl_hash_init_bitmap_page +{ + uint16 bmsize; +} xl_hash_init_bitmap_page; + +#define SizeOfHashInitBitmapPage \ + (offsetof(xl_hash_init_bitmap_page, bmsize) + sizeof(uint16)) + +/* + * This is what we need for index tuple deletion and to + * update the meta page. + * + * This data record is used for XLOG_HASH_VACUUM_ONE_PAGE + * + * Backup Blk 0: bucket page + * Backup Blk 1: meta page + */ +typedef struct xl_hash_vacuum_one_page +{ + TransactionId latestRemovedXid; + int ntuples; + + /* TARGET OFFSET NUMBERS FOLLOW AT THE END */ +} xl_hash_vacuum_one_page; + +#define SizeOfHashVacuumOnePage \ + (offsetof(xl_hash_vacuum_one_page, ntuples) + sizeof(int)) + +extern void hash_redo(XLogReaderState *record); +extern void hash_desc(StringInfo buf, XLogReaderState *record); +extern const char *hash_identify(uint8 info); +extern void hash_mask(char *pagedata, BlockNumber blkno); + +#endif /* HASH_XLOG_H */ diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h new file mode 100644 index 0000000..abf62d9 --- /dev/null +++ b/src/include/access/heapam.h @@ -0,0 +1,233 @@ +/*------------------------------------------------------------------------- + * + * heapam.h + * POSTGRES heap access method definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/heapam.h + * + *------------------------------------------------------------------------- + */ +#ifndef HEAPAM_H +#define HEAPAM_H + +#include "access/relation.h" /* for backward compatibility */ +#include "access/relscan.h" +#include "access/sdir.h" +#include "access/skey.h" +#include "access/table.h" /* for backward compatibility */ +#include "access/tableam.h" +#include "nodes/lockoptions.h" +#include "nodes/primnodes.h" +#include "storage/bufpage.h" +#include "storage/dsm.h" +#include "storage/lockdefs.h" +#include "storage/shm_toc.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + + +/* "options" flag bits for heap_insert */ +#define HEAP_INSERT_SKIP_FSM TABLE_INSERT_SKIP_FSM +#define HEAP_INSERT_FROZEN TABLE_INSERT_FROZEN +#define HEAP_INSERT_NO_LOGICAL TABLE_INSERT_NO_LOGICAL +#define HEAP_INSERT_SPECULATIVE 0x0010 + +typedef struct BulkInsertStateData *BulkInsertState; +struct TupleTableSlot; + +#define MaxLockTupleMode LockTupleExclusive + +/* + * Descriptor for heap table scans. + */ +typedef struct HeapScanDescData +{ + TableScanDescData rs_base; /* AM independent part of the descriptor */ + + /* state set up at initscan time */ + BlockNumber rs_nblocks; /* total number of blocks in rel */ + BlockNumber rs_startblock; /* block # to start at */ + BlockNumber rs_numblocks; /* max number of blocks to scan */ + /* rs_numblocks is usually InvalidBlockNumber, meaning "scan whole rel" */ + + /* scan current state */ + bool rs_inited; /* false = scan not init'd yet */ + BlockNumber rs_cblock; /* current block # in scan, if any */ + Buffer rs_cbuf; /* current buffer in scan, if any */ + /* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */ + + /* rs_numblocks is usually InvalidBlockNumber, meaning "scan whole rel" */ + BufferAccessStrategy rs_strategy; /* access strategy for reads */ + + HeapTupleData rs_ctup; /* current tuple in scan, if any */ + + /* + * For parallel scans to store page allocation data. NULL when not + * performing a parallel scan. + */ + ParallelBlockTableScanWorkerData *rs_parallelworkerdata; + + /* these fields only used in page-at-a-time mode and for bitmap scans */ + int rs_cindex; /* current tuple's index in vistuples */ + int rs_ntuples; /* number of visible tuples on page */ + OffsetNumber rs_vistuples[MaxHeapTuplesPerPage]; /* their offsets */ +} HeapScanDescData; +typedef struct HeapScanDescData *HeapScanDesc; + +/* + * Descriptor for fetches from heap via an index. + */ +typedef struct IndexFetchHeapData +{ + IndexFetchTableData xs_base; /* AM independent part of the descriptor */ + + Buffer xs_cbuf; /* current heap buffer in scan, if any */ + /* NB: if xs_cbuf is not InvalidBuffer, we hold a pin on that buffer */ +} IndexFetchHeapData; + +/* Result codes for HeapTupleSatisfiesVacuum */ +typedef enum +{ + HEAPTUPLE_DEAD, /* tuple is dead and deletable */ + HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ + HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ + HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ + HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ +} HTSV_Result; + +/* ---------------- + * function prototypes for heap access method + * + * heap_create, heap_create_with_catalog, and heap_drop_with_catalog + * are declared in catalog/heap.h + * ---------------- + */ + + +/* + * HeapScanIsValid + * True iff the heap scan is valid. + */ +#define HeapScanIsValid(scan) PointerIsValid(scan) + +extern TableScanDesc heap_beginscan(Relation relation, Snapshot snapshot, + int nkeys, ScanKey key, + ParallelTableScanDesc parallel_scan, + uint32 flags); +extern void heap_setscanlimits(TableScanDesc scan, BlockNumber startBlk, + BlockNumber numBlks); +extern void heapgetpage(TableScanDesc scan, BlockNumber page); +extern void heap_rescan(TableScanDesc scan, ScanKey key, bool set_params, + bool allow_strat, bool allow_sync, bool allow_pagemode); +extern void heap_endscan(TableScanDesc scan); +extern HeapTuple heap_getnext(TableScanDesc scan, ScanDirection direction); +extern bool heap_getnextslot(TableScanDesc sscan, + ScanDirection direction, struct TupleTableSlot *slot); +extern void heap_set_tidrange(TableScanDesc sscan, ItemPointer mintid, + ItemPointer maxtid); +extern bool heap_getnextslot_tidrange(TableScanDesc sscan, + ScanDirection direction, + TupleTableSlot *slot); +extern bool heap_fetch(Relation relation, Snapshot snapshot, + HeapTuple tuple, Buffer *userbuf, bool keep_buf); +extern bool heap_hot_search_buffer(ItemPointer tid, Relation relation, + Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, + bool *all_dead, bool first_call); + +extern void heap_get_latest_tid(TableScanDesc scan, ItemPointer tid); + +extern BulkInsertState GetBulkInsertState(void); +extern void FreeBulkInsertState(BulkInsertState); +extern void ReleaseBulkInsertStatePin(BulkInsertState bistate); + +extern void heap_insert(Relation relation, HeapTuple tup, CommandId cid, + int options, BulkInsertState bistate); +extern void heap_multi_insert(Relation relation, struct TupleTableSlot **slots, + int ntuples, CommandId cid, int options, + BulkInsertState bistate); +extern TM_Result heap_delete(Relation relation, ItemPointer tid, + CommandId cid, Snapshot crosscheck, bool wait, + struct TM_FailureData *tmfd, bool changingPart); +extern void heap_finish_speculative(Relation relation, ItemPointer tid); +extern void heap_abort_speculative(Relation relation, ItemPointer tid); +extern TM_Result heap_update(Relation relation, ItemPointer otid, + HeapTuple newtup, + CommandId cid, Snapshot crosscheck, bool wait, + struct TM_FailureData *tmfd, LockTupleMode *lockmode); +extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple, + CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, + bool follow_update, + Buffer *buffer, struct TM_FailureData *tmfd); + +extern void heap_inplace_update(Relation relation, HeapTuple tuple); +extern bool heap_freeze_tuple(HeapTupleHeader tuple, + TransactionId relfrozenxid, TransactionId relminmxid, + TransactionId cutoff_xid, TransactionId cutoff_multi); +extern bool heap_tuple_would_freeze(HeapTupleHeader tuple, TransactionId cutoff_xid, + MultiXactId cutoff_multi, + TransactionId *relfrozenxid_out, + MultiXactId *relminmxid_out); +extern bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple); + +extern void simple_heap_insert(Relation relation, HeapTuple tup); +extern void simple_heap_delete(Relation relation, ItemPointer tid); +extern void simple_heap_update(Relation relation, ItemPointer otid, + HeapTuple tup); + +extern TransactionId heap_index_delete_tuples(Relation rel, + TM_IndexDeleteOp *delstate); + +/* in heap/pruneheap.c */ +struct GlobalVisState; +extern void heap_page_prune_opt(Relation relation, Buffer buffer); +extern int heap_page_prune(Relation relation, Buffer buffer, + struct GlobalVisState *vistest, + TransactionId old_snap_xmin, + TimestampTz old_snap_ts_ts, + int *nnewlpdead, + OffsetNumber *off_loc); +extern void heap_page_prune_execute(Buffer buffer, + OffsetNumber *redirected, int nredirected, + OffsetNumber *nowdead, int ndead, + OffsetNumber *nowunused, int nunused); +extern void heap_get_root_tuples(Page page, OffsetNumber *root_offsets); + +/* in heap/vacuumlazy.c */ +struct VacuumParams; +extern void heap_vacuum_rel(Relation rel, + struct VacuumParams *params, BufferAccessStrategy bstrategy); + +/* in heap/heapam_visibility.c */ +extern bool HeapTupleSatisfiesVisibility(HeapTuple stup, Snapshot snapshot, + Buffer buffer); +extern TM_Result HeapTupleSatisfiesUpdate(HeapTuple stup, CommandId curcid, + Buffer buffer); +extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple stup, TransactionId OldestXmin, + Buffer buffer); +extern HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple stup, Buffer buffer, + TransactionId *dead_after); +extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, + uint16 infomask, TransactionId xid); +extern bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple); +extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); +extern bool HeapTupleIsSurelyDead(HeapTuple htup, + struct GlobalVisState *vistest); + +/* + * To avoid leaking too much knowledge about reorderbuffer implementation + * details this is implemented in reorderbuffer.c not heapam_visibility.c + */ +struct HTAB; +extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data, + Snapshot snapshot, + HeapTuple htup, + Buffer buffer, + CommandId *cmin, CommandId *cmax); +extern void HeapCheckForSerializableConflictOut(bool valid, Relation relation, HeapTuple tuple, + Buffer buffer, Snapshot snapshot); + +#endif /* HEAPAM_H */ diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h new file mode 100644 index 0000000..2d8a7f6 --- /dev/null +++ b/src/include/access/heapam_xlog.h @@ -0,0 +1,421 @@ +/*------------------------------------------------------------------------- + * + * heapam_xlog.h + * POSTGRES heap access XLOG definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/heapam_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef HEAPAM_XLOG_H +#define HEAPAM_XLOG_H + +#include "access/htup.h" +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/buf.h" +#include "storage/bufpage.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + + +/* + * WAL record definitions for heapam.c's WAL operations + * + * XLOG allows to store some information in high 4 bits of log + * record xl_info field. We use 3 for opcode and one for init bit. + */ +#define XLOG_HEAP_INSERT 0x00 +#define XLOG_HEAP_DELETE 0x10 +#define XLOG_HEAP_UPDATE 0x20 +#define XLOG_HEAP_TRUNCATE 0x30 +#define XLOG_HEAP_HOT_UPDATE 0x40 +#define XLOG_HEAP_CONFIRM 0x50 +#define XLOG_HEAP_LOCK 0x60 +#define XLOG_HEAP_INPLACE 0x70 + +#define XLOG_HEAP_OPMASK 0x70 +/* + * When we insert 1st item on new page in INSERT, UPDATE, HOT_UPDATE, + * or MULTI_INSERT, we can (and we do) restore entire page in redo + */ +#define XLOG_HEAP_INIT_PAGE 0x80 +/* + * We ran out of opcodes, so heapam.c now has a second RmgrId. These opcodes + * are associated with RM_HEAP2_ID, but are not logically different from + * the ones above associated with RM_HEAP_ID. XLOG_HEAP_OPMASK applies to + * these, too. + */ +#define XLOG_HEAP2_REWRITE 0x00 +#define XLOG_HEAP2_PRUNE 0x10 +#define XLOG_HEAP2_VACUUM 0x20 +#define XLOG_HEAP2_FREEZE_PAGE 0x30 +#define XLOG_HEAP2_VISIBLE 0x40 +#define XLOG_HEAP2_MULTI_INSERT 0x50 +#define XLOG_HEAP2_LOCK_UPDATED 0x60 +#define XLOG_HEAP2_NEW_CID 0x70 + +/* + * xl_heap_insert/xl_heap_multi_insert flag values, 8 bits are available. + */ +/* PD_ALL_VISIBLE was cleared */ +#define XLH_INSERT_ALL_VISIBLE_CLEARED (1<<0) +#define XLH_INSERT_LAST_IN_MULTI (1<<1) +#define XLH_INSERT_IS_SPECULATIVE (1<<2) +#define XLH_INSERT_CONTAINS_NEW_TUPLE (1<<3) +#define XLH_INSERT_ON_TOAST_RELATION (1<<4) + +/* all_frozen_set always implies all_visible_set */ +#define XLH_INSERT_ALL_FROZEN_SET (1<<5) + +/* + * xl_heap_update flag values, 8 bits are available. + */ +/* PD_ALL_VISIBLE was cleared */ +#define XLH_UPDATE_OLD_ALL_VISIBLE_CLEARED (1<<0) +/* PD_ALL_VISIBLE was cleared in the 2nd page */ +#define XLH_UPDATE_NEW_ALL_VISIBLE_CLEARED (1<<1) +#define XLH_UPDATE_CONTAINS_OLD_TUPLE (1<<2) +#define XLH_UPDATE_CONTAINS_OLD_KEY (1<<3) +#define XLH_UPDATE_CONTAINS_NEW_TUPLE (1<<4) +#define XLH_UPDATE_PREFIX_FROM_OLD (1<<5) +#define XLH_UPDATE_SUFFIX_FROM_OLD (1<<6) + +/* convenience macro for checking whether any form of old tuple was logged */ +#define XLH_UPDATE_CONTAINS_OLD \ + (XLH_UPDATE_CONTAINS_OLD_TUPLE | XLH_UPDATE_CONTAINS_OLD_KEY) + +/* + * xl_heap_delete flag values, 8 bits are available. + */ +/* PD_ALL_VISIBLE was cleared */ +#define XLH_DELETE_ALL_VISIBLE_CLEARED (1<<0) +#define XLH_DELETE_CONTAINS_OLD_TUPLE (1<<1) +#define XLH_DELETE_CONTAINS_OLD_KEY (1<<2) +#define XLH_DELETE_IS_SUPER (1<<3) +#define XLH_DELETE_IS_PARTITION_MOVE (1<<4) + +/* convenience macro for checking whether any form of old tuple was logged */ +#define XLH_DELETE_CONTAINS_OLD \ + (XLH_DELETE_CONTAINS_OLD_TUPLE | XLH_DELETE_CONTAINS_OLD_KEY) + +/* This is what we need to know about delete */ +typedef struct xl_heap_delete +{ + TransactionId xmax; /* xmax of the deleted tuple */ + OffsetNumber offnum; /* deleted tuple's offset */ + uint8 infobits_set; /* infomask bits */ + uint8 flags; +} xl_heap_delete; + +#define SizeOfHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8)) + +/* + * xl_heap_truncate flag values, 8 bits are available. + */ +#define XLH_TRUNCATE_CASCADE (1<<0) +#define XLH_TRUNCATE_RESTART_SEQS (1<<1) + +/* + * For truncate we list all truncated relids in an array, followed by all + * sequence relids that need to be restarted, if any. + * All rels are always within the same database, so we just list dbid once. + */ +typedef struct xl_heap_truncate +{ + Oid dbId; + uint32 nrelids; + uint8 flags; + Oid relids[FLEXIBLE_ARRAY_MEMBER]; +} xl_heap_truncate; + +#define SizeOfHeapTruncate (offsetof(xl_heap_truncate, relids)) + +/* + * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted + * or updated tuple in WAL; we can save a few bytes by reconstructing the + * fields that are available elsewhere in the WAL record, or perhaps just + * plain needn't be reconstructed. These are the fields we must store. + */ +typedef struct xl_heap_header +{ + uint16 t_infomask2; + uint16 t_infomask; + uint8 t_hoff; +} xl_heap_header; + +#define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8)) + +/* This is what we need to know about insert */ +typedef struct xl_heap_insert +{ + OffsetNumber offnum; /* inserted tuple's offset */ + uint8 flags; + + /* xl_heap_header & TUPLE DATA in backup block 0 */ +} xl_heap_insert; + +#define SizeOfHeapInsert (offsetof(xl_heap_insert, flags) + sizeof(uint8)) + +/* + * This is what we need to know about a multi-insert. + * + * The main data of the record consists of this xl_heap_multi_insert header. + * 'offsets' array is omitted if the whole page is reinitialized + * (XLOG_HEAP_INIT_PAGE). + * + * In block 0's data portion, there is an xl_multi_insert_tuple struct, + * followed by the tuple data for each tuple. There is padding to align + * each xl_multi_insert_tuple struct. + */ +typedef struct xl_heap_multi_insert +{ + uint8 flags; + uint16 ntuples; + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} xl_heap_multi_insert; + +#define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets) + +typedef struct xl_multi_insert_tuple +{ + uint16 datalen; /* size of tuple data that follows */ + uint16 t_infomask2; + uint16 t_infomask; + uint8 t_hoff; + /* TUPLE DATA FOLLOWS AT END OF STRUCT */ +} xl_multi_insert_tuple; + +#define SizeOfMultiInsertTuple (offsetof(xl_multi_insert_tuple, t_hoff) + sizeof(uint8)) + +/* + * This is what we need to know about update|hot_update + * + * Backup blk 0: new page + * + * If XLH_UPDATE_PREFIX_FROM_OLD or XLH_UPDATE_SUFFIX_FROM_OLD flags are set, + * the prefix and/or suffix come first, as one or two uint16s. + * + * After that, xl_heap_header and new tuple data follow. The new tuple + * data doesn't include the prefix and suffix, which are copied from the + * old tuple on replay. + * + * If XLH_UPDATE_CONTAINS_NEW_TUPLE flag is given, the tuple data is + * included even if a full-page image was taken. + * + * Backup blk 1: old page, if different. (no data, just a reference to the blk) + */ +typedef struct xl_heap_update +{ + TransactionId old_xmax; /* xmax of the old tuple */ + OffsetNumber old_offnum; /* old tuple's offset */ + uint8 old_infobits_set; /* infomask bits to set on old tuple */ + uint8 flags; + TransactionId new_xmax; /* xmax of the new tuple */ + OffsetNumber new_offnum; /* new tuple's offset */ + + /* + * If XLH_UPDATE_CONTAINS_OLD_TUPLE or XLH_UPDATE_CONTAINS_OLD_KEY flags + * are set, xl_heap_header and tuple data for the old tuple follow. + */ +} xl_heap_update; + +#define SizeOfHeapUpdate (offsetof(xl_heap_update, new_offnum) + sizeof(OffsetNumber)) + +/* + * This is what we need to know about page pruning (both during VACUUM and + * during opportunistic pruning) + * + * The array of OffsetNumbers following the fixed part of the record contains: + * * for each redirected item: the item offset, then the offset redirected to + * * for each now-dead item: the item offset + * * for each now-unused item: the item offset + * The total number of OffsetNumbers is therefore 2*nredirected+ndead+nunused. + * Note that nunused is not explicitly stored, but may be found by reference + * to the total record length. + * + * Acquires a full cleanup lock. + */ +typedef struct xl_heap_prune +{ + TransactionId latestRemovedXid; + uint16 nredirected; + uint16 ndead; + /* OFFSET NUMBERS are in the block reference 0 */ +} xl_heap_prune; + +#define SizeOfHeapPrune (offsetof(xl_heap_prune, ndead) + sizeof(uint16)) + +/* + * The vacuum page record is similar to the prune record, but can only mark + * already LP_DEAD items LP_UNUSED (during VACUUM's second heap pass) + * + * Acquires an ordinary exclusive lock only. + */ +typedef struct xl_heap_vacuum +{ + uint16 nunused; + /* OFFSET NUMBERS are in the block reference 0 */ +} xl_heap_vacuum; + +#define SizeOfHeapVacuum (offsetof(xl_heap_vacuum, nunused) + sizeof(uint16)) + +/* flags for infobits_set */ +#define XLHL_XMAX_IS_MULTI 0x01 +#define XLHL_XMAX_LOCK_ONLY 0x02 +#define XLHL_XMAX_EXCL_LOCK 0x04 +#define XLHL_XMAX_KEYSHR_LOCK 0x08 +#define XLHL_KEYS_UPDATED 0x10 + +/* flag bits for xl_heap_lock / xl_heap_lock_updated's flag field */ +#define XLH_LOCK_ALL_FROZEN_CLEARED 0x01 + +/* This is what we need to know about lock */ +typedef struct xl_heap_lock +{ + TransactionId locking_xid; /* might be a MultiXactId not xid */ + OffsetNumber offnum; /* locked tuple's offset on page */ + int8 infobits_set; /* infomask and infomask2 bits to set */ + uint8 flags; /* XLH_LOCK_* flag bits */ +} xl_heap_lock; + +#define SizeOfHeapLock (offsetof(xl_heap_lock, flags) + sizeof(int8)) + +/* This is what we need to know about locking an updated version of a row */ +typedef struct xl_heap_lock_updated +{ + TransactionId xmax; + OffsetNumber offnum; + uint8 infobits_set; + uint8 flags; +} xl_heap_lock_updated; + +#define SizeOfHeapLockUpdated (offsetof(xl_heap_lock_updated, flags) + sizeof(uint8)) + +/* This is what we need to know about confirmation of speculative insertion */ +typedef struct xl_heap_confirm +{ + OffsetNumber offnum; /* confirmed tuple's offset on page */ +} xl_heap_confirm; + +#define SizeOfHeapConfirm (offsetof(xl_heap_confirm, offnum) + sizeof(OffsetNumber)) + +/* This is what we need to know about in-place update */ +typedef struct xl_heap_inplace +{ + OffsetNumber offnum; /* updated tuple's offset on page */ + /* TUPLE DATA FOLLOWS AT END OF STRUCT */ +} xl_heap_inplace; + +#define SizeOfHeapInplace (offsetof(xl_heap_inplace, offnum) + sizeof(OffsetNumber)) + +/* + * This struct represents a 'freeze plan', which is what we need to know about + * a single tuple being frozen during vacuum. + */ +/* 0x01 was XLH_FREEZE_XMIN */ +#define XLH_FREEZE_XVAC 0x02 +#define XLH_INVALID_XVAC 0x04 + +typedef struct xl_heap_freeze_tuple +{ + TransactionId xmax; + OffsetNumber offset; + uint16 t_infomask2; + uint16 t_infomask; + uint8 frzflags; +} xl_heap_freeze_tuple; + +/* + * This is what we need to know about a block being frozen during vacuum + * + * Backup block 0's data contains an array of xl_heap_freeze_tuple structs, + * one for each tuple. + */ +typedef struct xl_heap_freeze_page +{ + TransactionId cutoff_xid; + uint16 ntuples; +} xl_heap_freeze_page; + +#define SizeOfHeapFreezePage (offsetof(xl_heap_freeze_page, ntuples) + sizeof(uint16)) + +/* + * This is what we need to know about setting a visibility map bit + * + * Backup blk 0: visibility map buffer + * Backup blk 1: heap buffer + */ +typedef struct xl_heap_visible +{ + TransactionId cutoff_xid; + uint8 flags; +} xl_heap_visible; + +#define SizeOfHeapVisible (offsetof(xl_heap_visible, flags) + sizeof(uint8)) + +typedef struct xl_heap_new_cid +{ + /* + * store toplevel xid so we don't have to merge cids from different + * transactions + */ + TransactionId top_xid; + CommandId cmin; + CommandId cmax; + CommandId combocid; /* just for debugging */ + + /* + * Store the relfilenode/ctid pair to facilitate lookups. + */ + RelFileNode target_node; + ItemPointerData target_tid; +} xl_heap_new_cid; + +#define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target_tid) + sizeof(ItemPointerData)) + +/* logical rewrite xlog record header */ +typedef struct xl_heap_rewrite_mapping +{ + TransactionId mapped_xid; /* xid that might need to see the row */ + Oid mapped_db; /* DbOid or InvalidOid for shared rels */ + Oid mapped_rel; /* Oid of the mapped relation */ + off_t offset; /* How far have we written so far */ + uint32 num_mappings; /* Number of in-memory mappings */ + XLogRecPtr start_lsn; /* Insert LSN at begin of rewrite */ +} xl_heap_rewrite_mapping; + +extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, + TransactionId *latestRemovedXid); + +extern void heap_redo(XLogReaderState *record); +extern void heap_desc(StringInfo buf, XLogReaderState *record); +extern const char *heap_identify(uint8 info); +extern void heap_mask(char *pagedata, BlockNumber blkno); +extern void heap2_redo(XLogReaderState *record); +extern void heap2_desc(StringInfo buf, XLogReaderState *record); +extern const char *heap2_identify(uint8 info); +extern void heap_xlog_logical_rewrite(XLogReaderState *r); + +extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer, + TransactionId cutoff_xid, xl_heap_freeze_tuple *tuples, + int ntuples); +extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, + TransactionId relfrozenxid, + TransactionId relminmxid, + TransactionId cutoff_xid, + TransactionId cutoff_multi, + xl_heap_freeze_tuple *frz, + bool *totally_frozen, + TransactionId *relfrozenxid_out, + MultiXactId *relminmxid_out); +extern void heap_execute_freeze_tuple(HeapTupleHeader tuple, + xl_heap_freeze_tuple *xlrec_tp); +extern XLogRecPtr log_heap_visible(RelFileNode rnode, Buffer heap_buffer, + Buffer vm_buffer, TransactionId cutoff_xid, uint8 flags); + +#endif /* HEAPAM_XLOG_H */ diff --git a/src/include/access/heaptoast.h b/src/include/access/heaptoast.h new file mode 100644 index 0000000..a756990 --- /dev/null +++ b/src/include/access/heaptoast.h @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------- + * + * heaptoast.h + * Heap-specific definitions for external and compressed storage + * of variable size attributes. + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/access/heaptoast.h + * + *------------------------------------------------------------------------- + */ +#ifndef HEAPTOAST_H +#define HEAPTOAST_H + +#include "access/htup_details.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" + +/* + * Find the maximum size of a tuple if there are to be N tuples per page. + */ +#define MaximumBytesPerTuple(tuplesPerPage) \ + MAXALIGN_DOWN((BLCKSZ - \ + MAXALIGN(SizeOfPageHeaderData + (tuplesPerPage) * sizeof(ItemIdData))) \ + / (tuplesPerPage)) + +/* + * These symbols control toaster activation. If a tuple is larger than + * TOAST_TUPLE_THRESHOLD, we will try to toast it down to no more than + * TOAST_TUPLE_TARGET bytes through compressing compressible fields and + * moving EXTENDED and EXTERNAL data out-of-line. + * + * The numbers need not be the same, though they currently are. It doesn't + * make sense for TARGET to exceed THRESHOLD, but it could be useful to make + * it be smaller. + * + * Currently we choose both values to match the largest tuple size for which + * TOAST_TUPLES_PER_PAGE tuples can fit on a heap page. + * + * XXX while these can be modified without initdb, some thought needs to be + * given to needs_toast_table() in toasting.c before unleashing random + * changes. Also see LOBLKSIZE in large_object.h, which can *not* be + * changed without initdb. + */ +#define TOAST_TUPLES_PER_PAGE 4 + +#define TOAST_TUPLE_THRESHOLD MaximumBytesPerTuple(TOAST_TUPLES_PER_PAGE) + +#define TOAST_TUPLE_TARGET TOAST_TUPLE_THRESHOLD + +/* + * The code will also consider moving MAIN data out-of-line, but only as a + * last resort if the previous steps haven't reached the target tuple size. + * In this phase we use a different target size, currently equal to the + * largest tuple that will fit on a heap page. This is reasonable since + * the user has told us to keep the data in-line if at all possible. + */ +#define TOAST_TUPLES_PER_PAGE_MAIN 1 + +#define TOAST_TUPLE_TARGET_MAIN MaximumBytesPerTuple(TOAST_TUPLES_PER_PAGE_MAIN) + +/* + * If an index value is larger than TOAST_INDEX_TARGET, we will try to + * compress it (we can't move it out-of-line, however). Note that this + * number is per-datum, not per-tuple, for simplicity in index_form_tuple(). + */ +#define TOAST_INDEX_TARGET (MaxHeapTupleSize / 16) + +/* + * When we store an oversize datum externally, we divide it into chunks + * containing at most TOAST_MAX_CHUNK_SIZE data bytes. This number *must* + * be small enough that the completed toast-table tuple (including the + * ID and sequence fields and all overhead) will fit on a page. + * The coding here sets the size on the theory that we want to fit + * EXTERN_TUPLES_PER_PAGE tuples of maximum size onto a page. + * + * NB: Changing TOAST_MAX_CHUNK_SIZE requires an initdb. + */ +#define EXTERN_TUPLES_PER_PAGE 4 /* tweak only this */ + +#define EXTERN_TUPLE_MAX_SIZE MaximumBytesPerTuple(EXTERN_TUPLES_PER_PAGE) + +#define TOAST_MAX_CHUNK_SIZE \ + (EXTERN_TUPLE_MAX_SIZE - \ + MAXALIGN(SizeofHeapTupleHeader) - \ + sizeof(Oid) - \ + sizeof(int32) - \ + VARHDRSZ) + +/* ---------- + * heap_toast_insert_or_update - + * + * Called by heap_insert() and heap_update(). + * ---------- + */ +extern HeapTuple heap_toast_insert_or_update(Relation rel, HeapTuple newtup, + HeapTuple oldtup, int options); + +/* ---------- + * heap_toast_delete - + * + * Called by heap_delete(). + * ---------- + */ +extern void heap_toast_delete(Relation rel, HeapTuple oldtup, + bool is_speculative); + +/* ---------- + * toast_flatten_tuple - + * + * "Flatten" a tuple to contain no out-of-line toasted fields. + * (This does not eliminate compressed or short-header datums.) + * ---------- + */ +extern HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc); + +/* ---------- + * toast_flatten_tuple_to_datum - + * + * "Flatten" a tuple containing out-of-line toasted fields into a Datum. + * ---------- + */ +extern Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup, + uint32 tup_len, + TupleDesc tupleDesc); + +/* ---------- + * toast_build_flattened_tuple - + * + * Build a tuple containing no out-of-line toasted fields. + * (This does not eliminate compressed or short-header datums.) + * ---------- + */ +extern HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc, + Datum *values, + bool *isnull); + +/* ---------- + * heap_fetch_toast_slice + * + * Fetch a slice from a toast value stored in a heap table. + * ---------- + */ +extern void heap_fetch_toast_slice(Relation toastrel, Oid valueid, + int32 attrsize, int32 sliceoffset, + int32 slicelength, struct varlena *result); + +#endif /* HEAPTOAST_H */ diff --git a/src/include/access/hio.h b/src/include/access/hio.h new file mode 100644 index 0000000..bb90c6f --- /dev/null +++ b/src/include/access/hio.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + * + * hio.h + * POSTGRES heap access method input/output definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/hio.h + * + *------------------------------------------------------------------------- + */ +#ifndef HIO_H +#define HIO_H + +#include "access/htup.h" +#include "storage/buf.h" +#include "utils/relcache.h" + +/* + * state for bulk inserts --- private to heapam.c and hio.c + * + * If current_buf isn't InvalidBuffer, then we are holding an extra pin + * on that buffer. + * + * "typedef struct BulkInsertStateData *BulkInsertState" is in heapam.h + */ +typedef struct BulkInsertStateData +{ + BufferAccessStrategy strategy; /* our BULKWRITE strategy object */ + Buffer current_buf; /* current insertion target page */ +} BulkInsertStateData; + + +extern void RelationPutHeapTuple(Relation relation, Buffer buffer, + HeapTuple tuple, bool token); +extern Buffer RelationGetBufferForTuple(Relation relation, Size len, + Buffer otherBuffer, int options, + BulkInsertStateData *bistate, + Buffer *vmbuffer, Buffer *vmbuffer_other); + +#endif /* HIO_H */ diff --git a/src/include/access/htup.h b/src/include/access/htup.h new file mode 100644 index 0000000..a4bc725 --- /dev/null +++ b/src/include/access/htup.h @@ -0,0 +1,89 @@ +/*------------------------------------------------------------------------- + * + * htup.h + * POSTGRES heap tuple definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/htup.h + * + *------------------------------------------------------------------------- + */ +#ifndef HTUP_H +#define HTUP_H + +#include "storage/itemptr.h" + +/* typedefs and forward declarations for structs defined in htup_details.h */ + +typedef struct HeapTupleHeaderData HeapTupleHeaderData; + +typedef HeapTupleHeaderData *HeapTupleHeader; + +typedef struct MinimalTupleData MinimalTupleData; + +typedef MinimalTupleData *MinimalTuple; + + +/* + * HeapTupleData is an in-memory data structure that points to a tuple. + * + * There are several ways in which this data structure is used: + * + * * Pointer to a tuple in a disk buffer: t_data points directly into the + * buffer (which the code had better be holding a pin on, but this is not + * reflected in HeapTupleData itself). + * + * * Pointer to nothing: t_data is NULL. This is used as a failure indication + * in some functions. + * + * * Part of a palloc'd tuple: the HeapTupleData itself and the tuple + * form a single palloc'd chunk. t_data points to the memory location + * immediately following the HeapTupleData struct (at offset HEAPTUPLESIZE). + * This is the output format of heap_form_tuple and related routines. + * + * * Separately allocated tuple: t_data points to a palloc'd chunk that + * is not adjacent to the HeapTupleData. (This case is deprecated since + * it's difficult to tell apart from case #1. It should be used only in + * limited contexts where the code knows that case #1 will never apply.) + * + * * Separately allocated minimal tuple: t_data points MINIMAL_TUPLE_OFFSET + * bytes before the start of a MinimalTuple. As with the previous case, + * this can't be told apart from case #1 by inspection; code setting up + * or destroying this representation has to know what it's doing. + * + * t_len should always be valid, except in the pointer-to-nothing case. + * t_self and t_tableOid should be valid if the HeapTupleData points to + * a disk buffer, or if it represents a copy of a tuple on disk. They + * should be explicitly set invalid in manufactured tuples. + */ +typedef struct HeapTupleData +{ + uint32 t_len; /* length of *t_data */ + ItemPointerData t_self; /* SelfItemPointer */ + Oid t_tableOid; /* table the tuple came from */ +#define FIELDNO_HEAPTUPLEDATA_DATA 3 + HeapTupleHeader t_data; /* -> tuple header and data */ +} HeapTupleData; + +typedef HeapTupleData *HeapTuple; + +#define HEAPTUPLESIZE MAXALIGN(sizeof(HeapTupleData)) + +/* + * Accessor macros to be used with HeapTuple pointers. + */ +#define HeapTupleIsValid(tuple) PointerIsValid(tuple) + +/* HeapTupleHeader functions implemented in utils/time/combocid.c */ +extern CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup); +extern CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup); +extern void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup, + CommandId *cmax, bool *iscombo); + +/* Prototype for HeapTupleHeader accessors in heapam.c */ +extern TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple); + +#endif /* HTUP_H */ diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h new file mode 100644 index 0000000..51a60ed --- /dev/null +++ b/src/include/access/htup_details.h @@ -0,0 +1,807 @@ +/*------------------------------------------------------------------------- + * + * htup_details.h + * POSTGRES heap tuple header definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/htup_details.h + * + *------------------------------------------------------------------------- + */ +#ifndef HTUP_DETAILS_H +#define HTUP_DETAILS_H + +#include "access/htup.h" +#include "access/transam.h" +#include "access/tupdesc.h" +#include "access/tupmacs.h" +#include "storage/bufpage.h" + +/* + * MaxTupleAttributeNumber limits the number of (user) columns in a tuple. + * The key limit on this value is that the size of the fixed overhead for + * a tuple, plus the size of the null-values bitmap (at 1 bit per column), + * plus MAXALIGN alignment, must fit into t_hoff which is uint8. On most + * machines the upper limit without making t_hoff wider would be a little + * over 1700. We use round numbers here and for MaxHeapAttributeNumber + * so that alterations in HeapTupleHeaderData layout won't change the + * supported max number of columns. + */ +#define MaxTupleAttributeNumber 1664 /* 8 * 208 */ + +/* + * MaxHeapAttributeNumber limits the number of (user) columns in a table. + * This should be somewhat less than MaxTupleAttributeNumber. It must be + * at least one less, else we will fail to do UPDATEs on a maximal-width + * table (because UPDATE has to form working tuples that include CTID). + * In practice we want some additional daylight so that we can gracefully + * support operations that add hidden "resjunk" columns, for example + * SELECT * FROM wide_table ORDER BY foo, bar, baz. + * In any case, depending on column data types you will likely be running + * into the disk-block-based limit on overall tuple size if you have more + * than a thousand or so columns. TOAST won't help. + */ +#define MaxHeapAttributeNumber 1600 /* 8 * 200 */ + +/* + * Heap tuple header. To avoid wasting space, the fields should be + * laid out in such a way as to avoid structure padding. + * + * Datums of composite types (row types) share the same general structure + * as on-disk tuples, so that the same routines can be used to build and + * examine them. However the requirements are slightly different: a Datum + * does not need any transaction visibility information, and it does need + * a length word and some embedded type information. We can achieve this + * by overlaying the xmin/cmin/xmax/cmax/xvac fields of a heap tuple + * with the fields needed in the Datum case. Typically, all tuples built + * in-memory will be initialized with the Datum fields; but when a tuple is + * about to be inserted in a table, the transaction fields will be filled, + * overwriting the datum fields. + * + * The overall structure of a heap tuple looks like: + * fixed fields (HeapTupleHeaderData struct) + * nulls bitmap (if HEAP_HASNULL is set in t_infomask) + * alignment padding (as needed to make user data MAXALIGN'd) + * object ID (if HEAP_HASOID_OLD is set in t_infomask, not created + * anymore) + * user data fields + * + * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in three + * physical fields. Xmin and Xmax are always really stored, but Cmin, Cmax + * and Xvac share a field. This works because we know that Cmin and Cmax + * are only interesting for the lifetime of the inserting and deleting + * transaction respectively. If a tuple is inserted and deleted in the same + * transaction, we store a "combo" command id that can be mapped to the real + * cmin and cmax, but only by use of local state within the originating + * backend. See combocid.c for more details. Meanwhile, Xvac is only set by + * old-style VACUUM FULL, which does not have any command sub-structure and so + * does not need either Cmin or Cmax. (This requires that old-style VACUUM + * FULL never try to move a tuple whose Cmin or Cmax is still interesting, + * ie, an insert-in-progress or delete-in-progress tuple.) + * + * A word about t_ctid: whenever a new tuple is stored on disk, its t_ctid + * is initialized with its own TID (location). If the tuple is ever updated, + * its t_ctid is changed to point to the replacement version of the tuple. Or + * if the tuple is moved from one partition to another, due to an update of + * the partition key, t_ctid is set to a special value to indicate that + * (see ItemPointerSetMovedPartitions). Thus, a tuple is the latest version + * of its row iff XMAX is invalid or + * t_ctid points to itself (in which case, if XMAX is valid, the tuple is + * either locked or deleted). One can follow the chain of t_ctid links + * to find the newest version of the row, unless it was moved to a different + * partition. Beware however that VACUUM might + * erase the pointed-to (newer) tuple before erasing the pointing (older) + * tuple. Hence, when following a t_ctid link, it is necessary to check + * to see if the referenced slot is empty or contains an unrelated tuple. + * Check that the referenced tuple has XMIN equal to the referencing tuple's + * XMAX to verify that it is actually the descendant version and not an + * unrelated tuple stored into a slot recently freed by VACUUM. If either + * check fails, one may assume that there is no live descendant version. + * + * t_ctid is sometimes used to store a speculative insertion token, instead + * of a real TID. A speculative token is set on a tuple that's being + * inserted, until the inserter is sure that it wants to go ahead with the + * insertion. Hence a token should only be seen on a tuple with an XMAX + * that's still in-progress, or invalid/aborted. The token is replaced with + * the tuple's real TID when the insertion is confirmed. One should never + * see a speculative insertion token while following a chain of t_ctid links, + * because they are not used on updates, only insertions. + * + * Following the fixed header fields, the nulls bitmap is stored (beginning + * at t_bits). The bitmap is *not* stored if t_infomask shows that there + * are no nulls in the tuple. If an OID field is present (as indicated by + * t_infomask), then it is stored just before the user data, which begins at + * the offset shown by t_hoff. Note that t_hoff must be a multiple of + * MAXALIGN. + */ + +typedef struct HeapTupleFields +{ + TransactionId t_xmin; /* inserting xact ID */ + TransactionId t_xmax; /* deleting or locking xact ID */ + + union + { + CommandId t_cid; /* inserting or deleting command ID, or both */ + TransactionId t_xvac; /* old-style VACUUM FULL xact ID */ + } t_field3; +} HeapTupleFields; + +typedef struct DatumTupleFields +{ + int32 datum_len_; /* varlena header (do not touch directly!) */ + + int32 datum_typmod; /* -1, or identifier of a record type */ + + Oid datum_typeid; /* composite type OID, or RECORDOID */ + + /* + * datum_typeid cannot be a domain over composite, only plain composite, + * even if the datum is meant as a value of a domain-over-composite type. + * This is in line with the general principle that CoerceToDomain does not + * change the physical representation of the base type value. + * + * Note: field ordering is chosen with thought that Oid might someday + * widen to 64 bits. + */ +} DatumTupleFields; + +struct HeapTupleHeaderData +{ + union + { + HeapTupleFields t_heap; + DatumTupleFields t_datum; + } t_choice; + + ItemPointerData t_ctid; /* current TID of this or newer tuple (or a + * speculative insertion token) */ + + /* Fields below here must match MinimalTupleData! */ + +#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2 2 + uint16 t_infomask2; /* number of attributes + various flags */ + +#define FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK 3 + uint16 t_infomask; /* various flag bits, see below */ + +#define FIELDNO_HEAPTUPLEHEADERDATA_HOFF 4 + uint8 t_hoff; /* sizeof header incl. bitmap, padding */ + + /* ^ - 23 bytes - ^ */ + +#define FIELDNO_HEAPTUPLEHEADERDATA_BITS 5 + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ + + /* MORE DATA FOLLOWS AT END OF STRUCT */ +}; + +/* typedef appears in htup.h */ + +#define SizeofHeapTupleHeader offsetof(HeapTupleHeaderData, t_bits) + +/* + * information stored in t_infomask: + */ +#define HEAP_HASNULL 0x0001 /* has null attribute(s) */ +#define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ +#define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ +#define HEAP_HASOID_OLD 0x0008 /* has an object-id field */ +#define HEAP_XMAX_KEYSHR_LOCK 0x0010 /* xmax is a key-shared locker */ +#define HEAP_COMBOCID 0x0020 /* t_cid is a combo CID */ +#define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ +#define HEAP_XMAX_LOCK_ONLY 0x0080 /* xmax, if valid, is only a locker */ + + /* xmax is a shared locker */ +#define HEAP_XMAX_SHR_LOCK (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK) + +#define HEAP_LOCK_MASK (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | \ + HEAP_XMAX_KEYSHR_LOCK) +#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */ +#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */ +#define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID) +#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */ +#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */ +#define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */ +#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */ +#define HEAP_MOVED_OFF 0x4000 /* moved to another place by pre-9.0 + * VACUUM FULL; kept for binary + * upgrade support */ +#define HEAP_MOVED_IN 0x8000 /* moved from another place by pre-9.0 + * VACUUM FULL; kept for binary + * upgrade support */ +#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN) + +#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */ + +/* + * A tuple is only locked (i.e. not updated by its Xmax) if the + * HEAP_XMAX_LOCK_ONLY bit is set; or, for pg_upgrade's sake, if the Xmax is + * not a multi and the EXCL_LOCK bit is set. + * + * See also HeapTupleHeaderIsOnlyLocked, which also checks for a possible + * aborted updater transaction. + * + * Beware of multiple evaluations of the argument. + */ +#define HEAP_XMAX_IS_LOCKED_ONLY(infomask) \ + (((infomask) & HEAP_XMAX_LOCK_ONLY) || \ + (((infomask) & (HEAP_XMAX_IS_MULTI | HEAP_LOCK_MASK)) == HEAP_XMAX_EXCL_LOCK)) + +/* + * A tuple that has HEAP_XMAX_IS_MULTI and HEAP_XMAX_LOCK_ONLY but neither of + * HEAP_XMAX_EXCL_LOCK and HEAP_XMAX_KEYSHR_LOCK must come from a tuple that was + * share-locked in 9.2 or earlier and then pg_upgrade'd. + * + * In 9.2 and prior, HEAP_XMAX_IS_MULTI was only set when there were multiple + * FOR SHARE lockers of that tuple. That set HEAP_XMAX_LOCK_ONLY (with a + * different name back then) but neither of HEAP_XMAX_EXCL_LOCK and + * HEAP_XMAX_KEYSHR_LOCK. That combination is no longer possible in 9.3 and + * up, so if we see that combination we know for certain that the tuple was + * locked in an earlier release; since all such lockers are gone (they cannot + * survive through pg_upgrade), such tuples can safely be considered not + * locked. + * + * We must not resolve such multixacts locally, because the result would be + * bogus, regardless of where they stand with respect to the current valid + * multixact range. + */ +#define HEAP_LOCKED_UPGRADED(infomask) \ +( \ + ((infomask) & HEAP_XMAX_IS_MULTI) != 0 && \ + ((infomask) & HEAP_XMAX_LOCK_ONLY) != 0 && \ + (((infomask) & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) == 0) \ +) + +/* + * Use these to test whether a particular lock is applied to a tuple + */ +#define HEAP_XMAX_IS_SHR_LOCKED(infomask) \ + (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_SHR_LOCK) +#define HEAP_XMAX_IS_EXCL_LOCKED(infomask) \ + (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_EXCL_LOCK) +#define HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) \ + (((infomask) & HEAP_LOCK_MASK) == HEAP_XMAX_KEYSHR_LOCK) + +/* turn these all off when Xmax is to change */ +#define HEAP_XMAX_BITS (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID | \ + HEAP_XMAX_IS_MULTI | HEAP_LOCK_MASK | HEAP_XMAX_LOCK_ONLY) + +/* + * information stored in t_infomask2: + */ +#define HEAP_NATTS_MASK 0x07FF /* 11 bits for number of attributes */ +/* bits 0x1800 are available */ +#define HEAP_KEYS_UPDATED 0x2000 /* tuple was updated and key cols + * modified, or tuple deleted */ +#define HEAP_HOT_UPDATED 0x4000 /* tuple was HOT-updated */ +#define HEAP_ONLY_TUPLE 0x8000 /* this is heap-only tuple */ + +#define HEAP2_XACT_MASK 0xE000 /* visibility-related bits */ + +/* + * HEAP_TUPLE_HAS_MATCH is a temporary flag used during hash joins. It is + * only used in tuples that are in the hash table, and those don't need + * any visibility information, so we can overlay it on a visibility flag + * instead of using up a dedicated bit. + */ +#define HEAP_TUPLE_HAS_MATCH HEAP_ONLY_TUPLE /* tuple has a join match */ + +/* + * HeapTupleHeader accessor macros + * + * Note: beware of multiple evaluations of "tup" argument. But the Set + * macros evaluate their other argument only once. + */ + +/* + * HeapTupleHeaderGetRawXmin returns the "raw" xmin field, which is the xid + * originally used to insert the tuple. However, the tuple might actually + * be frozen (via HeapTupleHeaderSetXminFrozen) in which case the tuple's xmin + * is visible to every snapshot. Prior to PostgreSQL 9.4, we actually changed + * the xmin to FrozenTransactionId, and that value may still be encountered + * on disk. + */ +#define HeapTupleHeaderGetRawXmin(tup) \ +( \ + (tup)->t_choice.t_heap.t_xmin \ +) + +#define HeapTupleHeaderGetXmin(tup) \ +( \ + HeapTupleHeaderXminFrozen(tup) ? \ + FrozenTransactionId : HeapTupleHeaderGetRawXmin(tup) \ +) + +#define HeapTupleHeaderSetXmin(tup, xid) \ +( \ + (tup)->t_choice.t_heap.t_xmin = (xid) \ +) + +#define HeapTupleHeaderXminCommitted(tup) \ +( \ + ((tup)->t_infomask & HEAP_XMIN_COMMITTED) != 0 \ +) + +#define HeapTupleHeaderXminInvalid(tup) \ +( \ + ((tup)->t_infomask & (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)) == \ + HEAP_XMIN_INVALID \ +) + +#define HeapTupleHeaderXminFrozen(tup) \ +( \ + ((tup)->t_infomask & (HEAP_XMIN_FROZEN)) == HEAP_XMIN_FROZEN \ +) + +#define HeapTupleHeaderSetXminCommitted(tup) \ +( \ + AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \ + ((tup)->t_infomask |= HEAP_XMIN_COMMITTED) \ +) + +#define HeapTupleHeaderSetXminInvalid(tup) \ +( \ + AssertMacro(!HeapTupleHeaderXminCommitted(tup)), \ + ((tup)->t_infomask |= HEAP_XMIN_INVALID) \ +) + +#define HeapTupleHeaderSetXminFrozen(tup) \ +( \ + AssertMacro(!HeapTupleHeaderXminInvalid(tup)), \ + ((tup)->t_infomask |= HEAP_XMIN_FROZEN) \ +) + +/* + * HeapTupleHeaderGetRawXmax gets you the raw Xmax field. To find out the Xid + * that updated a tuple, you might need to resolve the MultiXactId if certain + * bits are set. HeapTupleHeaderGetUpdateXid checks those bits and takes care + * to resolve the MultiXactId if necessary. This might involve multixact I/O, + * so it should only be used if absolutely necessary. + */ +#define HeapTupleHeaderGetUpdateXid(tup) \ +( \ + (!((tup)->t_infomask & HEAP_XMAX_INVALID) && \ + ((tup)->t_infomask & HEAP_XMAX_IS_MULTI) && \ + !((tup)->t_infomask & HEAP_XMAX_LOCK_ONLY)) ? \ + HeapTupleGetUpdateXid(tup) \ + : \ + HeapTupleHeaderGetRawXmax(tup) \ +) + +#define HeapTupleHeaderGetRawXmax(tup) \ +( \ + (tup)->t_choice.t_heap.t_xmax \ +) + +#define HeapTupleHeaderSetXmax(tup, xid) \ +( \ + (tup)->t_choice.t_heap.t_xmax = (xid) \ +) + +/* + * HeapTupleHeaderGetRawCommandId will give you what's in the header whether + * it is useful or not. Most code should use HeapTupleHeaderGetCmin or + * HeapTupleHeaderGetCmax instead, but note that those Assert that you can + * get a legitimate result, ie you are in the originating transaction! + */ +#define HeapTupleHeaderGetRawCommandId(tup) \ +( \ + (tup)->t_choice.t_heap.t_field3.t_cid \ +) + +/* SetCmin is reasonably simple since we never need a combo CID */ +#define HeapTupleHeaderSetCmin(tup, cid) \ +do { \ + Assert(!((tup)->t_infomask & HEAP_MOVED)); \ + (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \ + (tup)->t_infomask &= ~HEAP_COMBOCID; \ +} while (0) + +/* SetCmax must be used after HeapTupleHeaderAdjustCmax; see combocid.c */ +#define HeapTupleHeaderSetCmax(tup, cid, iscombo) \ +do { \ + Assert(!((tup)->t_infomask & HEAP_MOVED)); \ + (tup)->t_choice.t_heap.t_field3.t_cid = (cid); \ + if (iscombo) \ + (tup)->t_infomask |= HEAP_COMBOCID; \ + else \ + (tup)->t_infomask &= ~HEAP_COMBOCID; \ +} while (0) + +#define HeapTupleHeaderGetXvac(tup) \ +( \ + ((tup)->t_infomask & HEAP_MOVED) ? \ + (tup)->t_choice.t_heap.t_field3.t_xvac \ + : \ + InvalidTransactionId \ +) + +#define HeapTupleHeaderSetXvac(tup, xid) \ +do { \ + Assert((tup)->t_infomask & HEAP_MOVED); \ + (tup)->t_choice.t_heap.t_field3.t_xvac = (xid); \ +} while (0) + +#define HeapTupleHeaderIsSpeculative(tup) \ +( \ + (ItemPointerGetOffsetNumberNoCheck(&(tup)->t_ctid) == SpecTokenOffsetNumber) \ +) + +#define HeapTupleHeaderGetSpeculativeToken(tup) \ +( \ + AssertMacro(HeapTupleHeaderIsSpeculative(tup)), \ + ItemPointerGetBlockNumber(&(tup)->t_ctid) \ +) + +#define HeapTupleHeaderSetSpeculativeToken(tup, token) \ +( \ + ItemPointerSet(&(tup)->t_ctid, token, SpecTokenOffsetNumber) \ +) + +#define HeapTupleHeaderIndicatesMovedPartitions(tup) \ + ItemPointerIndicatesMovedPartitions(&(tup)->t_ctid) + +#define HeapTupleHeaderSetMovedPartitions(tup) \ + ItemPointerSetMovedPartitions(&(tup)->t_ctid) + +#define HeapTupleHeaderGetDatumLength(tup) \ + VARSIZE(tup) + +#define HeapTupleHeaderSetDatumLength(tup, len) \ + SET_VARSIZE(tup, len) + +#define HeapTupleHeaderGetTypeId(tup) \ +( \ + (tup)->t_choice.t_datum.datum_typeid \ +) + +#define HeapTupleHeaderSetTypeId(tup, typeid) \ +( \ + (tup)->t_choice.t_datum.datum_typeid = (typeid) \ +) + +#define HeapTupleHeaderGetTypMod(tup) \ +( \ + (tup)->t_choice.t_datum.datum_typmod \ +) + +#define HeapTupleHeaderSetTypMod(tup, typmod) \ +( \ + (tup)->t_choice.t_datum.datum_typmod = (typmod) \ +) + +/* + * Note that we stop considering a tuple HOT-updated as soon as it is known + * aborted or the would-be updating transaction is known aborted. For best + * efficiency, check tuple visibility before using this macro, so that the + * INVALID bits will be as up to date as possible. + */ +#define HeapTupleHeaderIsHotUpdated(tup) \ +( \ + ((tup)->t_infomask2 & HEAP_HOT_UPDATED) != 0 && \ + ((tup)->t_infomask & HEAP_XMAX_INVALID) == 0 && \ + !HeapTupleHeaderXminInvalid(tup) \ +) + +#define HeapTupleHeaderSetHotUpdated(tup) \ +( \ + (tup)->t_infomask2 |= HEAP_HOT_UPDATED \ +) + +#define HeapTupleHeaderClearHotUpdated(tup) \ +( \ + (tup)->t_infomask2 &= ~HEAP_HOT_UPDATED \ +) + +#define HeapTupleHeaderIsHeapOnly(tup) \ +( \ + ((tup)->t_infomask2 & HEAP_ONLY_TUPLE) != 0 \ +) + +#define HeapTupleHeaderSetHeapOnly(tup) \ +( \ + (tup)->t_infomask2 |= HEAP_ONLY_TUPLE \ +) + +#define HeapTupleHeaderClearHeapOnly(tup) \ +( \ + (tup)->t_infomask2 &= ~HEAP_ONLY_TUPLE \ +) + +#define HeapTupleHeaderHasMatch(tup) \ +( \ + ((tup)->t_infomask2 & HEAP_TUPLE_HAS_MATCH) != 0 \ +) + +#define HeapTupleHeaderSetMatch(tup) \ +( \ + (tup)->t_infomask2 |= HEAP_TUPLE_HAS_MATCH \ +) + +#define HeapTupleHeaderClearMatch(tup) \ +( \ + (tup)->t_infomask2 &= ~HEAP_TUPLE_HAS_MATCH \ +) + +#define HeapTupleHeaderGetNatts(tup) \ + ((tup)->t_infomask2 & HEAP_NATTS_MASK) + +#define HeapTupleHeaderSetNatts(tup, natts) \ +( \ + (tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \ +) + +#define HeapTupleHeaderHasExternal(tup) \ + (((tup)->t_infomask & HEAP_HASEXTERNAL) != 0) + + +/* + * BITMAPLEN(NATTS) - + * Computes size of null bitmap given number of data columns. + */ +#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) + +/* + * MaxHeapTupleSize is the maximum allowed size of a heap tuple, including + * header and MAXALIGN alignment padding. Basically it's BLCKSZ minus the + * other stuff that has to be on a disk page. Since heap pages use no + * "special space", there's no deduction for that. + * + * NOTE: we allow for the ItemId that must point to the tuple, ensuring that + * an otherwise-empty page can indeed hold a tuple of this size. Because + * ItemIds and tuples have different alignment requirements, don't assume that + * you can, say, fit 2 tuples of size MaxHeapTupleSize/2 on the same page. + */ +#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData))) +#define MinHeapTupleSize MAXALIGN(SizeofHeapTupleHeader) + +/* + * MaxHeapTuplesPerPage is an upper bound on the number of tuples that can + * fit on one heap page. (Note that indexes could have more, because they + * use a smaller tuple header.) We arrive at the divisor because each tuple + * must be maxaligned, and it must have an associated line pointer. + * + * Note: with HOT, there could theoretically be more line pointers (not actual + * tuples) than this on a heap page. However we constrain the number of line + * pointers to this anyway, to avoid excessive line-pointer bloat and not + * require increases in the size of work arrays. + */ +#define MaxHeapTuplesPerPage \ + ((int) ((BLCKSZ - SizeOfPageHeaderData) / \ + (MAXALIGN(SizeofHeapTupleHeader) + sizeof(ItemIdData)))) + +/* + * MaxAttrSize is a somewhat arbitrary upper limit on the declared size of + * data fields of char(n) and similar types. It need not have anything + * directly to do with the *actual* upper limit of varlena values, which + * is currently 1Gb (see TOAST structures in postgres.h). I've set it + * at 10Mb which seems like a reasonable number --- tgl 8/6/00. + */ +#define MaxAttrSize (10 * 1024 * 1024) + + +/* + * MinimalTuple is an alternative representation that is used for transient + * tuples inside the executor, in places where transaction status information + * is not required, the tuple rowtype is known, and shaving off a few bytes + * is worthwhile because we need to store many tuples. The representation + * is chosen so that tuple access routines can work with either full or + * minimal tuples via a HeapTupleData pointer structure. The access routines + * see no difference, except that they must not access the transaction status + * or t_ctid fields because those aren't there. + * + * For the most part, MinimalTuples should be accessed via TupleTableSlot + * routines. These routines will prevent access to the "system columns" + * and thereby prevent accidental use of the nonexistent fields. + * + * MinimalTupleData contains a length word, some padding, and fields matching + * HeapTupleHeaderData beginning with t_infomask2. The padding is chosen so + * that offsetof(t_infomask2) is the same modulo MAXIMUM_ALIGNOF in both + * structs. This makes data alignment rules equivalent in both cases. + * + * When a minimal tuple is accessed via a HeapTupleData pointer, t_data is + * set to point MINIMAL_TUPLE_OFFSET bytes before the actual start of the + * minimal tuple --- that is, where a full tuple matching the minimal tuple's + * data would start. This trick is what makes the structs seem equivalent. + * + * Note that t_hoff is computed the same as in a full tuple, hence it includes + * the MINIMAL_TUPLE_OFFSET distance. t_len does not include that, however. + * + * MINIMAL_TUPLE_DATA_OFFSET is the offset to the first useful (non-pad) data + * other than the length word. tuplesort.c and tuplestore.c use this to avoid + * writing the padding to disk. + */ +#define MINIMAL_TUPLE_OFFSET \ + ((offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) / MAXIMUM_ALIGNOF * MAXIMUM_ALIGNOF) +#define MINIMAL_TUPLE_PADDING \ + ((offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) % MAXIMUM_ALIGNOF) +#define MINIMAL_TUPLE_DATA_OFFSET \ + offsetof(MinimalTupleData, t_infomask2) + +struct MinimalTupleData +{ + uint32 t_len; /* actual length of minimal tuple */ + + char mt_padding[MINIMAL_TUPLE_PADDING]; + + /* Fields below here must match HeapTupleHeaderData! */ + + uint16 t_infomask2; /* number of attributes + various flags */ + + uint16 t_infomask; /* various flag bits, see below */ + + uint8 t_hoff; /* sizeof header incl. bitmap, padding */ + + /* ^ - 23 bytes - ^ */ + + bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ + + /* MORE DATA FOLLOWS AT END OF STRUCT */ +}; + +/* typedef appears in htup.h */ + +#define SizeofMinimalTupleHeader offsetof(MinimalTupleData, t_bits) + + +/* + * GETSTRUCT - given a HeapTuple pointer, return address of the user data + */ +#define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff) + +/* + * Accessor macros to be used with HeapTuple pointers. + */ + +#define HeapTupleHasNulls(tuple) \ + (((tuple)->t_data->t_infomask & HEAP_HASNULL) != 0) + +#define HeapTupleNoNulls(tuple) \ + (!((tuple)->t_data->t_infomask & HEAP_HASNULL)) + +#define HeapTupleHasVarWidth(tuple) \ + (((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH) != 0) + +#define HeapTupleAllFixed(tuple) \ + (!((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH)) + +#define HeapTupleHasExternal(tuple) \ + (((tuple)->t_data->t_infomask & HEAP_HASEXTERNAL) != 0) + +#define HeapTupleIsHotUpdated(tuple) \ + HeapTupleHeaderIsHotUpdated((tuple)->t_data) + +#define HeapTupleSetHotUpdated(tuple) \ + HeapTupleHeaderSetHotUpdated((tuple)->t_data) + +#define HeapTupleClearHotUpdated(tuple) \ + HeapTupleHeaderClearHotUpdated((tuple)->t_data) + +#define HeapTupleIsHeapOnly(tuple) \ + HeapTupleHeaderIsHeapOnly((tuple)->t_data) + +#define HeapTupleSetHeapOnly(tuple) \ + HeapTupleHeaderSetHeapOnly((tuple)->t_data) + +#define HeapTupleClearHeapOnly(tuple) \ + HeapTupleHeaderClearHeapOnly((tuple)->t_data) + +/* prototypes for functions in common/heaptuple.c */ +extern Size heap_compute_data_size(TupleDesc tupleDesc, + Datum *values, bool *isnull); +extern void heap_fill_tuple(TupleDesc tupleDesc, + Datum *values, bool *isnull, + char *data, Size data_size, + uint16 *infomask, bits8 *bit); +extern bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc); +extern Datum nocachegetattr(HeapTuple tup, int attnum, + TupleDesc att); +extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, + bool *isnull); +extern Datum getmissingattr(TupleDesc tupleDesc, + int attnum, bool *isnull); +extern HeapTuple heap_copytuple(HeapTuple tuple); +extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest); +extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc); +extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, + Datum *values, bool *isnull); +extern HeapTuple heap_modify_tuple(HeapTuple tuple, + TupleDesc tupleDesc, + Datum *replValues, + bool *replIsnull, + bool *doReplace); +extern HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, + TupleDesc tupleDesc, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull); +extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, + Datum *values, bool *isnull); +extern void heap_freetuple(HeapTuple htup); +extern MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, + Datum *values, bool *isnull); +extern void heap_free_minimal_tuple(MinimalTuple mtup); +extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup); +extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup); +extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup); +extern size_t varsize_any(void *p); +extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); +extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); + +#ifndef FRONTEND +/* + * fastgetattr + * Fetch a user attribute's value as a Datum (might be either a + * value, or a pointer into the data area of the tuple). + * + * This must not be used when a system attribute might be requested. + * Furthermore, the passed attnum MUST be valid. Use heap_getattr() + * instead, if in doubt. + * + * This gets called many times, so we macro the cacheable and NULL + * lookups, and call nocachegetattr() for the rest. + */ +static inline Datum +fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) +{ + Assert(attnum > 0); + + *isnull = false; + if (HeapTupleNoNulls(tup)) + { + Form_pg_attribute att; + + att = TupleDescAttr(tupleDesc, attnum - 1); + if (att->attcacheoff >= 0) + return fetchatt(att, (char *) tup->t_data + tup->t_data->t_hoff + + att->attcacheoff); + else + return nocachegetattr(tup, attnum, tupleDesc); + } + else + { + if (att_isnull(attnum - 1, tup->t_data->t_bits)) + { + *isnull = true; + return (Datum) NULL; + } + else + return nocachegetattr(tup, attnum, tupleDesc); + } +} + +/* + * heap_getattr + * Extract an attribute of a heap tuple and return it as a Datum. + * This works for either system or user attributes. The given attnum + * is properly range-checked. + * + * If the field in question has a NULL value, we return a zero Datum + * and set *isnull == true. Otherwise, we set *isnull == false. + * + * <tup> is the pointer to the heap tuple. <attnum> is the attribute + * number of the column (field) caller wants. <tupleDesc> is a + * pointer to the structure describing the row and all its fields. + * + */ +static inline Datum +heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) +{ + if (attnum > 0) + { + if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data)) + return getmissingattr(tupleDesc, attnum, isnull); + else + return fastgetattr(tup, attnum, tupleDesc, isnull); + } + else + return heap_getsysattr(tup, attnum, tupleDesc, isnull); +} +#endif /* FRONTEND */ + +#endif /* HTUP_DETAILS_H */ diff --git a/src/include/access/itup.h b/src/include/access/itup.h new file mode 100644 index 0000000..7458bc2 --- /dev/null +++ b/src/include/access/itup.h @@ -0,0 +1,167 @@ +/*------------------------------------------------------------------------- + * + * itup.h + * POSTGRES index tuple definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/itup.h + * + *------------------------------------------------------------------------- + */ +#ifndef ITUP_H +#define ITUP_H + +#include "access/tupdesc.h" +#include "access/tupmacs.h" +#include "storage/bufpage.h" +#include "storage/itemptr.h" + +/* + * Index tuple header structure + * + * All index tuples start with IndexTupleData. If the HasNulls bit is set, + * this is followed by an IndexAttributeBitMapData. The index attribute + * values follow, beginning at a MAXALIGN boundary. + * + * Note that the space allocated for the bitmap does not vary with the number + * of attributes; that is because we don't have room to store the number of + * attributes in the header. Given the MAXALIGN constraint there's no space + * savings to be had anyway, for usual values of INDEX_MAX_KEYS. + */ + +typedef struct IndexTupleData +{ + ItemPointerData t_tid; /* reference TID to heap tuple */ + + /* --------------- + * t_info is laid out in the following fashion: + * + * 15th (high) bit: has nulls + * 14th bit: has var-width attributes + * 13th bit: AM-defined meaning + * 12-0 bit: size of tuple + * --------------- + */ + + unsigned short t_info; /* various info about tuple */ + +} IndexTupleData; /* MORE DATA FOLLOWS AT END OF STRUCT */ + +typedef IndexTupleData *IndexTuple; + +typedef struct IndexAttributeBitMapData +{ + bits8 bits[(INDEX_MAX_KEYS + 8 - 1) / 8]; +} IndexAttributeBitMapData; + +typedef IndexAttributeBitMapData * IndexAttributeBitMap; + +/* + * t_info manipulation macros + */ +#define INDEX_SIZE_MASK 0x1FFF +#define INDEX_AM_RESERVED_BIT 0x2000 /* reserved for index-AM specific + * usage */ +#define INDEX_VAR_MASK 0x4000 +#define INDEX_NULL_MASK 0x8000 + +#define IndexTupleSize(itup) ((Size) ((itup)->t_info & INDEX_SIZE_MASK)) +#define IndexTupleHasNulls(itup) ((((IndexTuple) (itup))->t_info & INDEX_NULL_MASK)) +#define IndexTupleHasVarwidths(itup) ((((IndexTuple) (itup))->t_info & INDEX_VAR_MASK)) + + +/* + * Takes an infomask as argument (primarily because this needs to be usable + * at index_form_tuple time so enough space is allocated). + */ +#define IndexInfoFindDataOffset(t_info) \ +( \ + (!((t_info) & INDEX_NULL_MASK)) ? \ + ( \ + (Size)MAXALIGN(sizeof(IndexTupleData)) \ + ) \ + : \ + ( \ + (Size)MAXALIGN(sizeof(IndexTupleData) + sizeof(IndexAttributeBitMapData)) \ + ) \ +) + +/* ---------------- + * index_getattr + * + * This gets called many times, so we macro the cacheable and NULL + * lookups, and call nocache_index_getattr() for the rest. + * + * ---------------- + */ +#define index_getattr(tup, attnum, tupleDesc, isnull) \ +( \ + AssertMacro(PointerIsValid(isnull) && (attnum) > 0), \ + *(isnull) = false, \ + !IndexTupleHasNulls(tup) ? \ + ( \ + TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff >= 0 ? \ + ( \ + fetchatt(TupleDescAttr((tupleDesc), (attnum)-1), \ + (char *) (tup) + IndexInfoFindDataOffset((tup)->t_info) \ + + TupleDescAttr((tupleDesc), (attnum)-1)->attcacheoff) \ + ) \ + : \ + nocache_index_getattr((tup), (attnum), (tupleDesc)) \ + ) \ + : \ + ( \ + (att_isnull((attnum)-1, (char *)(tup) + sizeof(IndexTupleData))) ? \ + ( \ + *(isnull) = true, \ + (Datum)NULL \ + ) \ + : \ + ( \ + nocache_index_getattr((tup), (attnum), (tupleDesc)) \ + ) \ + ) \ +) + +/* + * MaxIndexTuplesPerPage is an upper bound on the number of tuples that can + * fit on one index page. An index tuple must have either data or a null + * bitmap, so we can safely assume it's at least 1 byte bigger than a bare + * IndexTupleData struct. We arrive at the divisor because each tuple + * must be maxaligned, and it must have an associated line pointer. + * + * To be index-type-independent, this does not account for any special space + * on the page, and is thus conservative. + * + * Note: in btree non-leaf pages, the first tuple has no key (it's implicitly + * minus infinity), thus breaking the "at least 1 byte bigger" assumption. + * On such a page, N tuples could take one MAXALIGN quantum less space than + * estimated here, seemingly allowing one more tuple than estimated here. + * But such a page always has at least MAXALIGN special space, so we're safe. + */ +#define MaxIndexTuplesPerPage \ + ((int) ((BLCKSZ - SizeOfPageHeaderData) / \ + (MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData)))) + + +/* routines in indextuple.c */ +extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor, + Datum *values, bool *isnull); +extern IndexTuple index_form_tuple_context(TupleDesc tupleDescriptor, + Datum *values, bool *isnull, + MemoryContext context); +extern Datum nocache_index_getattr(IndexTuple tup, int attnum, + TupleDesc tupleDesc); +extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, + Datum *values, bool *isnull); +extern void index_deform_tuple_internal(TupleDesc tupleDescriptor, + Datum *values, bool *isnull, + char *tp, bits8 *bp, int hasnulls); +extern IndexTuple CopyIndexTuple(IndexTuple source); +extern IndexTuple index_truncate_tuple(TupleDesc sourceDescriptor, + IndexTuple source, int leavenatts); + +#endif /* ITUP_H */ diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h new file mode 100644 index 0000000..a5600a3 --- /dev/null +++ b/src/include/access/multixact.h @@ -0,0 +1,164 @@ +/* + * multixact.h + * + * PostgreSQL multi-transaction-log manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/multixact.h + */ +#ifndef MULTIXACT_H +#define MULTIXACT_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/sync.h" + + +/* + * The first two MultiXactId values are reserved to store the truncation Xid + * and epoch of the first segment, so we start assigning multixact values from + * 2. + */ +#define InvalidMultiXactId ((MultiXactId) 0) +#define FirstMultiXactId ((MultiXactId) 1) +#define MaxMultiXactId ((MultiXactId) 0xFFFFFFFF) + +#define MultiXactIdIsValid(multi) ((multi) != InvalidMultiXactId) + +#define MaxMultiXactOffset ((MultiXactOffset) 0xFFFFFFFF) + +/* Number of SLRU buffers to use for multixact */ +#define NUM_MULTIXACTOFFSET_BUFFERS 8 +#define NUM_MULTIXACTMEMBER_BUFFERS 16 + +/* + * Possible multixact lock modes ("status"). The first four modes are for + * tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the + * next two are used for update and delete modes. + */ +typedef enum +{ + MultiXactStatusForKeyShare = 0x00, + MultiXactStatusForShare = 0x01, + MultiXactStatusForNoKeyUpdate = 0x02, + MultiXactStatusForUpdate = 0x03, + /* an update that doesn't touch "key" columns */ + MultiXactStatusNoKeyUpdate = 0x04, + /* other updates, and delete */ + MultiXactStatusUpdate = 0x05 +} MultiXactStatus; + +#define MaxMultiXactStatus MultiXactStatusUpdate + +/* does a status value correspond to a tuple update? */ +#define ISUPDATE_from_mxstatus(status) \ + ((status) > MultiXactStatusForUpdate) + + +typedef struct MultiXactMember +{ + TransactionId xid; + MultiXactStatus status; +} MultiXactMember; + + +/* ---------------- + * multixact-related XLOG entries + * ---------------- + */ + +#define XLOG_MULTIXACT_ZERO_OFF_PAGE 0x00 +#define XLOG_MULTIXACT_ZERO_MEM_PAGE 0x10 +#define XLOG_MULTIXACT_CREATE_ID 0x20 +#define XLOG_MULTIXACT_TRUNCATE_ID 0x30 + +typedef struct xl_multixact_create +{ + MultiXactId mid; /* new MultiXact's ID */ + MultiXactOffset moff; /* its starting offset in members file */ + int32 nmembers; /* number of member XIDs */ + MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]; +} xl_multixact_create; + +#define SizeOfMultiXactCreate (offsetof(xl_multixact_create, members)) + +typedef struct xl_multixact_truncate +{ + Oid oldestMultiDB; + + /* to-be-truncated range of multixact offsets */ + MultiXactId startTruncOff; /* just for completeness' sake */ + MultiXactId endTruncOff; + + /* to-be-truncated range of multixact members */ + MultiXactOffset startTruncMemb; + MultiXactOffset endTruncMemb; +} xl_multixact_truncate; + +#define SizeOfMultiXactTruncate (sizeof(xl_multixact_truncate)) + + +extern MultiXactId MultiXactIdCreate(TransactionId xid1, + MultiXactStatus status1, TransactionId xid2, + MultiXactStatus status2); +extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, + MultiXactStatus status); +extern MultiXactId MultiXactIdCreateFromMembers(int nmembers, + MultiXactMember *members); + +extern MultiXactId ReadNextMultiXactId(void); +extern void ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next); +extern bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly); +extern void MultiXactIdSetOldestMember(void); +extern int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **xids, + bool allow_old, bool isLockOnly); +extern bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2); +extern bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, + MultiXactId multi2); + +extern int multixactoffsetssyncfiletag(const FileTag *ftag, char *path); +extern int multixactmemberssyncfiletag(const FileTag *ftag, char *path); + +extern void AtEOXact_MultiXact(void); +extern void AtPrepare_MultiXact(void); +extern void PostPrepare_MultiXact(TransactionId xid); + +extern Size MultiXactShmemSize(void); +extern void MultiXactShmemInit(void); +extern void BootStrapMultiXact(void); +extern void StartupMultiXact(void); +extern void TrimMultiXact(void); +extern void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, + Oid oldest_datoid, + bool is_startup); +extern void MultiXactGetCheckptMulti(bool is_shutdown, + MultiXactId *nextMulti, + MultiXactOffset *nextMultiOffset, + MultiXactId *oldestMulti, + Oid *oldestMultiDB); +extern void CheckPointMultiXact(void); +extern MultiXactId GetOldestMultiXactId(void); +extern void TruncateMultiXact(MultiXactId oldestMulti, Oid oldestMultiDB); +extern void MultiXactSetNextMXact(MultiXactId nextMulti, + MultiXactOffset nextMultiOffset); +extern void MultiXactAdvanceNextMXact(MultiXactId minMulti, + MultiXactOffset minMultiOffset); +extern void MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB); +extern int MultiXactMemberFreezeThreshold(void); + +extern void multixact_twophase_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void multixact_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void multixact_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len); + +extern void multixact_redo(XLogReaderState *record); +extern void multixact_desc(StringInfo buf, XLogReaderState *record); +extern const char *multixact_identify(uint8 info); +extern char *mxid_to_string(MultiXactId multi, int nmembers, + MultiXactMember *members); + +#endif /* MULTIXACT_H */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h new file mode 100644 index 0000000..3055a5c --- /dev/null +++ b/src/include/access/nbtree.h @@ -0,0 +1,1290 @@ +/*------------------------------------------------------------------------- + * + * nbtree.h + * header file for postgres btree access method implementation. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/nbtree.h + * + *------------------------------------------------------------------------- + */ +#ifndef NBTREE_H +#define NBTREE_H + +#include "access/amapi.h" +#include "access/itup.h" +#include "access/sdir.h" +#include "access/tableam.h" +#include "access/xlogreader.h" +#include "catalog/pg_am_d.h" +#include "catalog/pg_index.h" +#include "lib/stringinfo.h" +#include "storage/bufmgr.h" +#include "storage/shm_toc.h" + +/* There's room for a 16-bit vacuum cycle ID in BTPageOpaqueData */ +typedef uint16 BTCycleId; + +/* + * BTPageOpaqueData -- At the end of every page, we store a pointer + * to both siblings in the tree. This is used to do forward/backward + * index scans. The next-page link is also critical for recovery when + * a search has navigated to the wrong page due to concurrent page splits + * or deletions; see src/backend/access/nbtree/README for more info. + * + * In addition, we store the page's btree level (counting upwards from + * zero at a leaf page) as well as some flag bits indicating the page type + * and status. If the page is deleted, a BTDeletedPageData struct is stored + * in the page's tuple area, while a standard BTPageOpaqueData struct is + * stored in the page special area. + * + * We also store a "vacuum cycle ID". When a page is split while VACUUM is + * processing the index, a nonzero value associated with the VACUUM run is + * stored into both halves of the split page. (If VACUUM is not running, + * both pages receive zero cycleids.) This allows VACUUM to detect whether + * a page was split since it started, with a small probability of false match + * if the page was last split some exact multiple of MAX_BT_CYCLE_ID VACUUMs + * ago. Also, during a split, the BTP_SPLIT_END flag is cleared in the left + * (original) page, and set in the right page, but only if the next page + * to its right has a different cycleid. + * + * NOTE: the BTP_LEAF flag bit is redundant since level==0 could be tested + * instead. + * + * NOTE: the btpo_level field used to be a union type in order to allow + * deleted pages to store a 32-bit safexid in the same field. We now store + * 64-bit/full safexid values using BTDeletedPageData instead. + */ + +typedef struct BTPageOpaqueData +{ + BlockNumber btpo_prev; /* left sibling, or P_NONE if leftmost */ + BlockNumber btpo_next; /* right sibling, or P_NONE if rightmost */ + uint32 btpo_level; /* tree level --- zero for leaf pages */ + uint16 btpo_flags; /* flag bits, see below */ + BTCycleId btpo_cycleid; /* vacuum cycle ID of latest split */ +} BTPageOpaqueData; + +typedef BTPageOpaqueData *BTPageOpaque; + +#define BTPageGetOpaque(page) ((BTPageOpaque) PageGetSpecialPointer(page)) + +/* Bits defined in btpo_flags */ +#define BTP_LEAF (1 << 0) /* leaf page, i.e. not internal page */ +#define BTP_ROOT (1 << 1) /* root page (has no parent) */ +#define BTP_DELETED (1 << 2) /* page has been deleted from tree */ +#define BTP_META (1 << 3) /* meta-page */ +#define BTP_HALF_DEAD (1 << 4) /* empty, but still in tree */ +#define BTP_SPLIT_END (1 << 5) /* rightmost page of split group */ +#define BTP_HAS_GARBAGE (1 << 6) /* page has LP_DEAD tuples (deprecated) */ +#define BTP_INCOMPLETE_SPLIT (1 << 7) /* right sibling's downlink is missing */ +#define BTP_HAS_FULLXID (1 << 8) /* contains BTDeletedPageData */ + +/* + * The max allowed value of a cycle ID is a bit less than 64K. This is + * for convenience of pg_filedump and similar utilities: we want to use + * the last 2 bytes of special space as an index type indicator, and + * restricting cycle ID lets btree use that space for vacuum cycle IDs + * while still allowing index type to be identified. + */ +#define MAX_BT_CYCLE_ID 0xFF7F + + +/* + * The Meta page is always the first page in the btree index. + * Its primary purpose is to point to the location of the btree root page. + * We also point to the "fast" root, which is the current effective root; + * see README for discussion. + */ + +typedef struct BTMetaPageData +{ + uint32 btm_magic; /* should contain BTREE_MAGIC */ + uint32 btm_version; /* nbtree version (always <= BTREE_VERSION) */ + BlockNumber btm_root; /* current root location */ + uint32 btm_level; /* tree level of the root page */ + BlockNumber btm_fastroot; /* current "fast" root location */ + uint32 btm_fastlevel; /* tree level of the "fast" root page */ + /* remaining fields only valid when btm_version >= BTREE_NOVAC_VERSION */ + + /* number of deleted, non-recyclable pages during last cleanup */ + uint32 btm_last_cleanup_num_delpages; + /* number of heap tuples during last cleanup (deprecated) */ + float8 btm_last_cleanup_num_heap_tuples; + + bool btm_allequalimage; /* are all columns "equalimage"? */ +} BTMetaPageData; + +#define BTPageGetMeta(p) \ + ((BTMetaPageData *) PageGetContents(p)) + +/* + * The current Btree version is 4. That's what you'll get when you create + * a new index. + * + * Btree version 3 was used in PostgreSQL v11. It is mostly the same as + * version 4, but heap TIDs were not part of the keyspace. Index tuples + * with duplicate keys could be stored in any order. We continue to + * support reading and writing Btree versions 2 and 3, so that they don't + * need to be immediately re-indexed at pg_upgrade. In order to get the + * new heapkeyspace semantics, however, a REINDEX is needed. + * + * Deduplication is safe to use when the btm_allequalimage field is set to + * true. It's safe to read the btm_allequalimage field on version 3, but + * only version 4 indexes make use of deduplication. Even version 4 + * indexes created on PostgreSQL v12 will need a REINDEX to make use of + * deduplication, though, since there is no other way to set + * btm_allequalimage to true (pg_upgrade hasn't been taught to set the + * metapage field). + * + * Btree version 2 is mostly the same as version 3. There are two new + * fields in the metapage that were introduced in version 3. A version 2 + * metapage will be automatically upgraded to version 3 on the first + * insert to it. INCLUDE indexes cannot use version 2. + */ +#define BTREE_METAPAGE 0 /* first page is meta */ +#define BTREE_MAGIC 0x053162 /* magic number in metapage */ +#define BTREE_VERSION 4 /* current version number */ +#define BTREE_MIN_VERSION 2 /* minimum supported version */ +#define BTREE_NOVAC_VERSION 3 /* version with all meta fields set */ + +/* + * Maximum size of a btree index entry, including its tuple header. + * + * We actually need to be able to fit three items on every page, + * so restrict any one item to 1/3 the per-page available space. + * + * There are rare cases where _bt_truncate() will need to enlarge + * a heap index tuple to make space for a tiebreaker heap TID + * attribute, which we account for here. + */ +#define BTMaxItemSize(page) \ + MAXALIGN_DOWN((PageGetPageSize(page) - \ + MAXALIGN(SizeOfPageHeaderData + \ + 3*sizeof(ItemIdData) + \ + 3*sizeof(ItemPointerData)) - \ + MAXALIGN(sizeof(BTPageOpaqueData))) / 3) +#define BTMaxItemSizeNoHeapTid(page) \ + MAXALIGN_DOWN((PageGetPageSize(page) - \ + MAXALIGN(SizeOfPageHeaderData + 3*sizeof(ItemIdData)) - \ + MAXALIGN(sizeof(BTPageOpaqueData))) / 3) + +/* + * MaxTIDsPerBTreePage is an upper bound on the number of heap TIDs tuples + * that may be stored on a btree leaf page. It is used to size the + * per-page temporary buffers. + * + * Note: we don't bother considering per-tuple overheads here to keep + * things simple (value is based on how many elements a single array of + * heap TIDs must have to fill the space between the page header and + * special area). The value is slightly higher (i.e. more conservative) + * than necessary as a result, which is considered acceptable. + */ +#define MaxTIDsPerBTreePage \ + (int) ((BLCKSZ - SizeOfPageHeaderData - sizeof(BTPageOpaqueData)) / \ + sizeof(ItemPointerData)) + +/* + * The leaf-page fillfactor defaults to 90% but is user-adjustable. + * For pages above the leaf level, we use a fixed 70% fillfactor. + * The fillfactor is applied during index build and when splitting + * a rightmost page; when splitting non-rightmost pages we try to + * divide the data equally. When splitting a page that's entirely + * filled with a single value (duplicates), the effective leaf-page + * fillfactor is 96%, regardless of whether the page is a rightmost + * page. + */ +#define BTREE_MIN_FILLFACTOR 10 +#define BTREE_DEFAULT_FILLFACTOR 90 +#define BTREE_NONLEAF_FILLFACTOR 70 +#define BTREE_SINGLEVAL_FILLFACTOR 96 + +/* + * In general, the btree code tries to localize its knowledge about + * page layout to a couple of routines. However, we need a special + * value to indicate "no page number" in those places where we expect + * page numbers. We can use zero for this because we never need to + * make a pointer to the metadata page. + */ + +#define P_NONE 0 + +/* + * Macros to test whether a page is leftmost or rightmost on its tree level, + * as well as other state info kept in the opaque data. + */ +#define P_LEFTMOST(opaque) ((opaque)->btpo_prev == P_NONE) +#define P_RIGHTMOST(opaque) ((opaque)->btpo_next == P_NONE) +#define P_ISLEAF(opaque) (((opaque)->btpo_flags & BTP_LEAF) != 0) +#define P_ISROOT(opaque) (((opaque)->btpo_flags & BTP_ROOT) != 0) +#define P_ISDELETED(opaque) (((opaque)->btpo_flags & BTP_DELETED) != 0) +#define P_ISMETA(opaque) (((opaque)->btpo_flags & BTP_META) != 0) +#define P_ISHALFDEAD(opaque) (((opaque)->btpo_flags & BTP_HALF_DEAD) != 0) +#define P_IGNORE(opaque) (((opaque)->btpo_flags & (BTP_DELETED|BTP_HALF_DEAD)) != 0) +#define P_HAS_GARBAGE(opaque) (((opaque)->btpo_flags & BTP_HAS_GARBAGE) != 0) +#define P_INCOMPLETE_SPLIT(opaque) (((opaque)->btpo_flags & BTP_INCOMPLETE_SPLIT) != 0) +#define P_HAS_FULLXID(opaque) (((opaque)->btpo_flags & BTP_HAS_FULLXID) != 0) + +/* + * BTDeletedPageData is the page contents of a deleted page + */ +typedef struct BTDeletedPageData +{ + FullTransactionId safexid; /* See BTPageIsRecyclable() */ +} BTDeletedPageData; + +static inline void +BTPageSetDeleted(Page page, FullTransactionId safexid) +{ + BTPageOpaque opaque; + PageHeader header; + BTDeletedPageData *contents; + + opaque = BTPageGetOpaque(page); + header = ((PageHeader) page); + + opaque->btpo_flags &= ~BTP_HALF_DEAD; + opaque->btpo_flags |= BTP_DELETED | BTP_HAS_FULLXID; + header->pd_lower = MAXALIGN(SizeOfPageHeaderData) + + sizeof(BTDeletedPageData); + header->pd_upper = header->pd_special; + + /* Set safexid in deleted page */ + contents = ((BTDeletedPageData *) PageGetContents(page)); + contents->safexid = safexid; +} + +static inline FullTransactionId +BTPageGetDeleteXid(Page page) +{ + BTPageOpaque opaque; + BTDeletedPageData *contents; + + /* We only expect to be called with a deleted page */ + Assert(!PageIsNew(page)); + opaque = BTPageGetOpaque(page); + Assert(P_ISDELETED(opaque)); + + /* pg_upgrade'd deleted page -- must be safe to delete now */ + if (!P_HAS_FULLXID(opaque)) + return FirstNormalFullTransactionId; + + /* Get safexid from deleted page */ + contents = ((BTDeletedPageData *) PageGetContents(page)); + return contents->safexid; +} + +/* + * Is an existing page recyclable? + * + * This exists to centralize the policy on which deleted pages are now safe to + * re-use. However, _bt_pendingfsm_finalize() duplicates some of the same + * logic because it doesn't work directly with pages -- keep the two in sync. + * + * Note: PageIsNew() pages are always safe to recycle, but we can't deal with + * them here (caller is responsible for that case themselves). Caller might + * well need special handling for new pages anyway. + */ +static inline bool +BTPageIsRecyclable(Page page) +{ + BTPageOpaque opaque; + + Assert(!PageIsNew(page)); + + /* Recycling okay iff page is deleted and safexid is old enough */ + opaque = BTPageGetOpaque(page); + if (P_ISDELETED(opaque)) + { + /* + * The page was deleted, but when? If it was just deleted, a scan + * might have seen the downlink to it, and will read the page later. + * As long as that can happen, we must keep the deleted page around as + * a tombstone. + * + * For that check if the deletion XID could still be visible to + * anyone. If not, then no scan that's still in progress could have + * seen its downlink, and we can recycle it. + * + * XXX: If we had the heap relation we could be more aggressive about + * recycling deleted pages in non-catalog relations. For now we just + * pass NULL. That is at least simple and consistent. + */ + return GlobalVisCheckRemovableFullXid(NULL, BTPageGetDeleteXid(page)); + } + + return false; +} + +/* + * BTVacState and BTPendingFSM are private nbtree.c state used during VACUUM. + * They are exported for use by page deletion related code in nbtpage.c. + */ +typedef struct BTPendingFSM +{ + BlockNumber target; /* Page deleted by current VACUUM */ + FullTransactionId safexid; /* Page's BTDeletedPageData.safexid */ +} BTPendingFSM; + +typedef struct BTVacState +{ + IndexVacuumInfo *info; + IndexBulkDeleteResult *stats; + IndexBulkDeleteCallback callback; + void *callback_state; + BTCycleId cycleid; + MemoryContext pagedelcontext; + + /* + * _bt_pendingfsm_finalize() state + */ + int bufsize; /* pendingpages space (in # elements) */ + int maxbufsize; /* max bufsize that respects work_mem */ + BTPendingFSM *pendingpages; /* One entry per newly deleted page */ + int npendingpages; /* current # valid pendingpages */ +} BTVacState; + +/* + * Lehman and Yao's algorithm requires a ``high key'' on every non-rightmost + * page. The high key is not a tuple that is used to visit the heap. It is + * a pivot tuple (see "Notes on B-Tree tuple format" below for definition). + * The high key on a page is required to be greater than or equal to any + * other key that appears on the page. If we find ourselves trying to + * insert a key that is strictly > high key, we know we need to move right + * (this should only happen if the page was split since we examined the + * parent page). + * + * Our insertion algorithm guarantees that we can use the initial least key + * on our right sibling as the high key. Once a page is created, its high + * key changes only if the page is split. + * + * On a non-rightmost page, the high key lives in item 1 and data items + * start in item 2. Rightmost pages have no high key, so we store data + * items beginning in item 1. + */ + +#define P_HIKEY ((OffsetNumber) 1) +#define P_FIRSTKEY ((OffsetNumber) 2) +#define P_FIRSTDATAKEY(opaque) (P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY) + +/* + * Notes on B-Tree tuple format, and key and non-key attributes: + * + * INCLUDE B-Tree indexes have non-key attributes. These are extra + * attributes that may be returned by index-only scans, but do not influence + * the order of items in the index (formally, non-key attributes are not + * considered to be part of the key space). Non-key attributes are only + * present in leaf index tuples whose item pointers actually point to heap + * tuples (non-pivot tuples). _bt_check_natts() enforces the rules + * described here. + * + * Non-pivot tuple format (plain/non-posting variant): + * + * t_tid | t_info | key values | INCLUDE columns, if any + * + * t_tid points to the heap TID, which is a tiebreaker key column as of + * BTREE_VERSION 4. + * + * Non-pivot tuples complement pivot tuples, which only have key columns. + * The sole purpose of pivot tuples is to represent how the key space is + * separated. In general, any B-Tree index that has more than one level + * (i.e. any index that does not just consist of a metapage and a single + * leaf root page) must have some number of pivot tuples, since pivot + * tuples are used for traversing the tree. Suffix truncation can omit + * trailing key columns when a new pivot is formed, which makes minus + * infinity their logical value. Since BTREE_VERSION 4 indexes treat heap + * TID as a trailing key column that ensures that all index tuples are + * physically unique, it is necessary to represent heap TID as a trailing + * key column in pivot tuples, though very often this can be truncated + * away, just like any other key column. (Actually, the heap TID is + * omitted rather than truncated, since its representation is different to + * the non-pivot representation.) + * + * Pivot tuple format: + * + * t_tid | t_info | key values | [heap TID] + * + * We store the number of columns present inside pivot tuples by abusing + * their t_tid offset field, since pivot tuples never need to store a real + * offset (pivot tuples generally store a downlink in t_tid, though). The + * offset field only stores the number of columns/attributes when the + * INDEX_ALT_TID_MASK bit is set, which doesn't count the trailing heap + * TID column sometimes stored in pivot tuples -- that's represented by + * the presence of BT_PIVOT_HEAP_TID_ATTR. The INDEX_ALT_TID_MASK bit in + * t_info is always set on BTREE_VERSION 4 pivot tuples, since + * BTreeTupleIsPivot() must work reliably on heapkeyspace versions. + * + * In version 2 or version 3 (!heapkeyspace) indexes, INDEX_ALT_TID_MASK + * might not be set in pivot tuples. BTreeTupleIsPivot() won't work + * reliably as a result. The number of columns stored is implicitly the + * same as the number of columns in the index, just like any non-pivot + * tuple. (The number of columns stored should not vary, since suffix + * truncation of key columns is unsafe within any !heapkeyspace index.) + * + * The 12 least significant bits from t_tid's offset number are used to + * represent the number of key columns within a pivot tuple. This leaves 4 + * status bits (BT_STATUS_OFFSET_MASK bits), which are shared by all tuples + * that have the INDEX_ALT_TID_MASK bit set (set in t_info) to store basic + * tuple metadata. BTreeTupleIsPivot() and BTreeTupleIsPosting() use the + * BT_STATUS_OFFSET_MASK bits. + * + * Sometimes non-pivot tuples also use a representation that repurposes + * t_tid to store metadata rather than a TID. PostgreSQL v13 introduced a + * new non-pivot tuple format to support deduplication: posting list + * tuples. Deduplication merges together multiple equal non-pivot tuples + * into a logically equivalent, space efficient representation. A posting + * list is an array of ItemPointerData elements. Non-pivot tuples are + * merged together to form posting list tuples lazily, at the point where + * we'd otherwise have to split a leaf page. + * + * Posting tuple format (alternative non-pivot tuple representation): + * + * t_tid | t_info | key values | posting list (TID array) + * + * Posting list tuples are recognized as such by having the + * INDEX_ALT_TID_MASK status bit set in t_info and the BT_IS_POSTING status + * bit set in t_tid's offset number. These flags redefine the content of + * the posting tuple's t_tid to store the location of the posting list + * (instead of a block number), as well as the total number of heap TIDs + * present in the tuple (instead of a real offset number). + * + * The 12 least significant bits from t_tid's offset number are used to + * represent the number of heap TIDs present in the tuple, leaving 4 status + * bits (the BT_STATUS_OFFSET_MASK bits). Like any non-pivot tuple, the + * number of columns stored is always implicitly the total number in the + * index (in practice there can never be non-key columns stored, since + * deduplication is not supported with INCLUDE indexes). + */ +#define INDEX_ALT_TID_MASK INDEX_AM_RESERVED_BIT + +/* Item pointer offset bit masks */ +#define BT_OFFSET_MASK 0x0FFF +#define BT_STATUS_OFFSET_MASK 0xF000 +/* BT_STATUS_OFFSET_MASK status bits */ +#define BT_PIVOT_HEAP_TID_ATTR 0x1000 +#define BT_IS_POSTING 0x2000 + +/* + * Note: BTreeTupleIsPivot() can have false negatives (but not false + * positives) when used with !heapkeyspace indexes + */ +static inline bool +BTreeTupleIsPivot(IndexTuple itup) +{ + if ((itup->t_info & INDEX_ALT_TID_MASK) == 0) + return false; + /* absence of BT_IS_POSTING in offset number indicates pivot tuple */ + if ((ItemPointerGetOffsetNumberNoCheck(&itup->t_tid) & BT_IS_POSTING) != 0) + return false; + + return true; +} + +static inline bool +BTreeTupleIsPosting(IndexTuple itup) +{ + if ((itup->t_info & INDEX_ALT_TID_MASK) == 0) + return false; + /* presence of BT_IS_POSTING in offset number indicates posting tuple */ + if ((ItemPointerGetOffsetNumberNoCheck(&itup->t_tid) & BT_IS_POSTING) == 0) + return false; + + return true; +} + +static inline void +BTreeTupleSetPosting(IndexTuple itup, uint16 nhtids, int postingoffset) +{ + Assert(nhtids > 1); + Assert((nhtids & BT_STATUS_OFFSET_MASK) == 0); + Assert((size_t) postingoffset == MAXALIGN(postingoffset)); + Assert(postingoffset < INDEX_SIZE_MASK); + Assert(!BTreeTupleIsPivot(itup)); + + itup->t_info |= INDEX_ALT_TID_MASK; + ItemPointerSetOffsetNumber(&itup->t_tid, (nhtids | BT_IS_POSTING)); + ItemPointerSetBlockNumber(&itup->t_tid, postingoffset); +} + +static inline uint16 +BTreeTupleGetNPosting(IndexTuple posting) +{ + OffsetNumber existing; + + Assert(BTreeTupleIsPosting(posting)); + + existing = ItemPointerGetOffsetNumberNoCheck(&posting->t_tid); + return (existing & BT_OFFSET_MASK); +} + +static inline uint32 +BTreeTupleGetPostingOffset(IndexTuple posting) +{ + Assert(BTreeTupleIsPosting(posting)); + + return ItemPointerGetBlockNumberNoCheck(&posting->t_tid); +} + +static inline ItemPointer +BTreeTupleGetPosting(IndexTuple posting) +{ + return (ItemPointer) ((char *) posting + + BTreeTupleGetPostingOffset(posting)); +} + +static inline ItemPointer +BTreeTupleGetPostingN(IndexTuple posting, int n) +{ + return BTreeTupleGetPosting(posting) + n; +} + +/* + * Get/set downlink block number in pivot tuple. + * + * Note: Cannot assert that tuple is a pivot tuple. If we did so then + * !heapkeyspace indexes would exhibit false positive assertion failures. + */ +static inline BlockNumber +BTreeTupleGetDownLink(IndexTuple pivot) +{ + return ItemPointerGetBlockNumberNoCheck(&pivot->t_tid); +} + +static inline void +BTreeTupleSetDownLink(IndexTuple pivot, BlockNumber blkno) +{ + ItemPointerSetBlockNumber(&pivot->t_tid, blkno); +} + +/* + * Get number of attributes within tuple. + * + * Note that this does not include an implicit tiebreaker heap TID + * attribute, if any. Note also that the number of key attributes must be + * explicitly represented in all heapkeyspace pivot tuples. + * + * Note: This is defined as a macro rather than an inline function to + * avoid including rel.h. + */ +#define BTreeTupleGetNAtts(itup, rel) \ + ( \ + (BTreeTupleIsPivot(itup)) ? \ + ( \ + ItemPointerGetOffsetNumberNoCheck(&(itup)->t_tid) & BT_OFFSET_MASK \ + ) \ + : \ + IndexRelationGetNumberOfAttributes(rel) \ + ) + +/* + * Set number of key attributes in tuple. + * + * The heap TID tiebreaker attribute bit may also be set here, indicating that + * a heap TID value will be stored at the end of the tuple (i.e. using the + * special pivot tuple representation). + */ +static inline void +BTreeTupleSetNAtts(IndexTuple itup, uint16 nkeyatts, bool heaptid) +{ + Assert(nkeyatts <= INDEX_MAX_KEYS); + Assert((nkeyatts & BT_STATUS_OFFSET_MASK) == 0); + Assert(!heaptid || nkeyatts > 0); + Assert(!BTreeTupleIsPivot(itup) || nkeyatts == 0); + + itup->t_info |= INDEX_ALT_TID_MASK; + + if (heaptid) + nkeyatts |= BT_PIVOT_HEAP_TID_ATTR; + + /* BT_IS_POSTING bit is deliberately unset here */ + ItemPointerSetOffsetNumber(&itup->t_tid, nkeyatts); + Assert(BTreeTupleIsPivot(itup)); +} + +/* + * Get/set leaf page's "top parent" link from its high key. Used during page + * deletion. + * + * Note: Cannot assert that tuple is a pivot tuple. If we did so then + * !heapkeyspace indexes would exhibit false positive assertion failures. + */ +static inline BlockNumber +BTreeTupleGetTopParent(IndexTuple leafhikey) +{ + return ItemPointerGetBlockNumberNoCheck(&leafhikey->t_tid); +} + +static inline void +BTreeTupleSetTopParent(IndexTuple leafhikey, BlockNumber blkno) +{ + ItemPointerSetBlockNumber(&leafhikey->t_tid, blkno); + BTreeTupleSetNAtts(leafhikey, 0, false); +} + +/* + * Get tiebreaker heap TID attribute, if any. + * + * This returns the first/lowest heap TID in the case of a posting list tuple. + */ +static inline ItemPointer +BTreeTupleGetHeapTID(IndexTuple itup) +{ + if (BTreeTupleIsPivot(itup)) + { + /* Pivot tuple heap TID representation? */ + if ((ItemPointerGetOffsetNumberNoCheck(&itup->t_tid) & + BT_PIVOT_HEAP_TID_ATTR) != 0) + return (ItemPointer) ((char *) itup + IndexTupleSize(itup) - + sizeof(ItemPointerData)); + + /* Heap TID attribute was truncated */ + return NULL; + } + else if (BTreeTupleIsPosting(itup)) + return BTreeTupleGetPosting(itup); + + return &itup->t_tid; +} + +/* + * Get maximum heap TID attribute, which could be the only TID in the case of + * a non-pivot tuple that does not have a posting list tuple. + * + * Works with non-pivot tuples only. + */ +static inline ItemPointer +BTreeTupleGetMaxHeapTID(IndexTuple itup) +{ + Assert(!BTreeTupleIsPivot(itup)); + + if (BTreeTupleIsPosting(itup)) + { + uint16 nposting = BTreeTupleGetNPosting(itup); + + return BTreeTupleGetPostingN(itup, nposting - 1); + } + + return &itup->t_tid; +} + +/* + * Operator strategy numbers for B-tree have been moved to access/stratnum.h, + * because many places need to use them in ScanKeyInit() calls. + * + * The strategy numbers are chosen so that we can commute them by + * subtraction, thus: + */ +#define BTCommuteStrategyNumber(strat) (BTMaxStrategyNumber + 1 - (strat)) + +/* + * When a new operator class is declared, we require that the user + * supply us with an amproc procedure (BTORDER_PROC) for determining + * whether, for two keys a and b, a < b, a = b, or a > b. This routine + * must return < 0, 0, > 0, respectively, in these three cases. + * + * To facilitate accelerated sorting, an operator class may choose to + * offer a second procedure (BTSORTSUPPORT_PROC). For full details, see + * src/include/utils/sortsupport.h. + * + * To support window frames defined by "RANGE offset PRECEDING/FOLLOWING", + * an operator class may choose to offer a third amproc procedure + * (BTINRANGE_PROC), independently of whether it offers sortsupport. + * For full details, see doc/src/sgml/btree.sgml. + * + * To facilitate B-Tree deduplication, an operator class may choose to + * offer a forth amproc procedure (BTEQUALIMAGE_PROC). For full details, + * see doc/src/sgml/btree.sgml. + */ + +#define BTORDER_PROC 1 +#define BTSORTSUPPORT_PROC 2 +#define BTINRANGE_PROC 3 +#define BTEQUALIMAGE_PROC 4 +#define BTOPTIONS_PROC 5 +#define BTNProcs 5 + +/* + * We need to be able to tell the difference between read and write + * requests for pages, in order to do locking correctly. + */ + +#define BT_READ BUFFER_LOCK_SHARE +#define BT_WRITE BUFFER_LOCK_EXCLUSIVE + +/* + * BTStackData -- As we descend a tree, we push the location of pivot + * tuples whose downlink we are about to follow onto a private stack. If + * we split a leaf, we use this stack to walk back up the tree and insert + * data into its parent page at the correct location. We also have to + * recursively insert into the grandparent page if and when the parent page + * splits. Our private stack can become stale due to concurrent page + * splits and page deletions, but it should never give us an irredeemably + * bad picture. + */ +typedef struct BTStackData +{ + BlockNumber bts_blkno; + OffsetNumber bts_offset; + struct BTStackData *bts_parent; +} BTStackData; + +typedef BTStackData *BTStack; + +/* + * BTScanInsertData is the btree-private state needed to find an initial + * position for an indexscan, or to insert new tuples -- an "insertion + * scankey" (not to be confused with a search scankey). It's used to descend + * a B-Tree using _bt_search. + * + * heapkeyspace indicates if we expect all keys in the index to be physically + * unique because heap TID is used as a tiebreaker attribute, and if index may + * have truncated key attributes in pivot tuples. This is actually a property + * of the index relation itself (not an indexscan). heapkeyspace indexes are + * indexes whose version is >= version 4. It's convenient to keep this close + * by, rather than accessing the metapage repeatedly. + * + * allequalimage is set to indicate that deduplication is safe for the index. + * This is also a property of the index relation rather than an indexscan. + * + * anynullkeys indicates if any of the keys had NULL value when scankey was + * built from index tuple (note that already-truncated tuple key attributes + * set NULL as a placeholder key value, which also affects value of + * anynullkeys). This is a convenience for unique index non-pivot tuple + * insertion, which usually temporarily unsets scantid, but shouldn't iff + * anynullkeys is true. Value generally matches non-pivot tuple's HasNulls + * bit, but may not when inserting into an INCLUDE index (tuple header value + * is affected by the NULL-ness of both key and non-key attributes). + * + * When nextkey is false (the usual case), _bt_search and _bt_binsrch will + * locate the first item >= scankey. When nextkey is true, they will locate + * the first item > scan key. + * + * pivotsearch is set to true by callers that want to re-find a leaf page + * using a scankey built from a leaf page's high key. Most callers set this + * to false. + * + * scantid is the heap TID that is used as a final tiebreaker attribute. It + * is set to NULL when index scan doesn't need to find a position for a + * specific physical tuple. Must be set when inserting new tuples into + * heapkeyspace indexes, since every tuple in the tree unambiguously belongs + * in one exact position (it's never set with !heapkeyspace indexes, though). + * Despite the representational difference, nbtree search code considers + * scantid to be just another insertion scankey attribute. + * + * scankeys is an array of scan key entries for attributes that are compared + * before scantid (user-visible attributes). keysz is the size of the array. + * During insertion, there must be a scan key for every attribute, but when + * starting a regular index scan some can be omitted. The array is used as a + * flexible array member, though it's sized in a way that makes it possible to + * use stack allocations. See nbtree/README for full details. + */ +typedef struct BTScanInsertData +{ + bool heapkeyspace; + bool allequalimage; + bool anynullkeys; + bool nextkey; + bool pivotsearch; + ItemPointer scantid; /* tiebreaker for scankeys */ + int keysz; /* Size of scankeys array */ + ScanKeyData scankeys[INDEX_MAX_KEYS]; /* Must appear last */ +} BTScanInsertData; + +typedef BTScanInsertData *BTScanInsert; + +/* + * BTInsertStateData is a working area used during insertion. + * + * This is filled in after descending the tree to the first leaf page the new + * tuple might belong on. Tracks the current position while performing + * uniqueness check, before we have determined which exact page to insert + * to. + * + * (This should be private to nbtinsert.c, but it's also used by + * _bt_binsrch_insert) + */ +typedef struct BTInsertStateData +{ + IndexTuple itup; /* Item we're inserting */ + Size itemsz; /* Size of itup -- should be MAXALIGN()'d */ + BTScanInsert itup_key; /* Insertion scankey */ + + /* Buffer containing leaf page we're likely to insert itup on */ + Buffer buf; + + /* + * Cache of bounds within the current buffer. Only used for insertions + * where _bt_check_unique is called. See _bt_binsrch_insert and + * _bt_findinsertloc for details. + */ + bool bounds_valid; + OffsetNumber low; + OffsetNumber stricthigh; + + /* + * if _bt_binsrch_insert found the location inside existing posting list, + * save the position inside the list. -1 sentinel value indicates overlap + * with an existing posting list tuple that has its LP_DEAD bit set. + */ + int postingoff; +} BTInsertStateData; + +typedef BTInsertStateData *BTInsertState; + +/* + * State used to representing an individual pending tuple during + * deduplication. + */ +typedef struct BTDedupInterval +{ + OffsetNumber baseoff; + uint16 nitems; +} BTDedupInterval; + +/* + * BTDedupStateData is a working area used during deduplication. + * + * The status info fields track the state of a whole-page deduplication pass. + * State about the current pending posting list is also tracked. + * + * A pending posting list is comprised of a contiguous group of equal items + * from the page, starting from page offset number 'baseoff'. This is the + * offset number of the "base" tuple for new posting list. 'nitems' is the + * current total number of existing items from the page that will be merged to + * make a new posting list tuple, including the base tuple item. (Existing + * items may themselves be posting list tuples, or regular non-pivot tuples.) + * + * The total size of the existing tuples to be freed when pending posting list + * is processed gets tracked by 'phystupsize'. This information allows + * deduplication to calculate the space saving for each new posting list + * tuple, and for the entire pass over the page as a whole. + */ +typedef struct BTDedupStateData +{ + /* Deduplication status info for entire pass over page */ + bool deduplicate; /* Still deduplicating page? */ + int nmaxitems; /* Number of max-sized tuples so far */ + Size maxpostingsize; /* Limit on size of final tuple */ + + /* Metadata about base tuple of current pending posting list */ + IndexTuple base; /* Use to form new posting list */ + OffsetNumber baseoff; /* page offset of base */ + Size basetupsize; /* base size without original posting list */ + + /* Other metadata about pending posting list */ + ItemPointer htids; /* Heap TIDs in pending posting list */ + int nhtids; /* Number of heap TIDs in htids array */ + int nitems; /* Number of existing tuples/line pointers */ + Size phystupsize; /* Includes line pointer overhead */ + + /* + * Array of tuples to go on new version of the page. Contains one entry + * for each group of consecutive items. Note that existing tuples that + * will not become posting list tuples do not appear in the array (they + * are implicitly unchanged by deduplication pass). + */ + int nintervals; /* current number of intervals in array */ + BTDedupInterval intervals[MaxIndexTuplesPerPage]; +} BTDedupStateData; + +typedef BTDedupStateData *BTDedupState; + +/* + * BTVacuumPostingData is state that represents how to VACUUM (or delete) a + * posting list tuple when some (though not all) of its TIDs are to be + * deleted. + * + * Convention is that itup field is the original posting list tuple on input, + * and palloc()'d final tuple used to overwrite existing tuple on output. + */ +typedef struct BTVacuumPostingData +{ + /* Tuple that will be/was updated */ + IndexTuple itup; + OffsetNumber updatedoffset; + + /* State needed to describe final itup in WAL */ + uint16 ndeletedtids; + uint16 deletetids[FLEXIBLE_ARRAY_MEMBER]; +} BTVacuumPostingData; + +typedef BTVacuumPostingData *BTVacuumPosting; + +/* + * BTScanOpaqueData is the btree-private state needed for an indexscan. + * This consists of preprocessed scan keys (see _bt_preprocess_keys() for + * details of the preprocessing), information about the current location + * of the scan, and information about the marked location, if any. (We use + * BTScanPosData to represent the data needed for each of current and marked + * locations.) In addition we can remember some known-killed index entries + * that must be marked before we can move off the current page. + * + * Index scans work a page at a time: we pin and read-lock the page, identify + * all the matching items on the page and save them in BTScanPosData, then + * release the read-lock while returning the items to the caller for + * processing. This approach minimizes lock/unlock traffic. Note that we + * keep the pin on the index page until the caller is done with all the items + * (this is needed for VACUUM synchronization, see nbtree/README). When we + * are ready to step to the next page, if the caller has told us any of the + * items were killed, we re-lock the page to mark them killed, then unlock. + * Finally we drop the pin and step to the next page in the appropriate + * direction. + * + * If we are doing an index-only scan, we save the entire IndexTuple for each + * matched item, otherwise only its heap TID and offset. The IndexTuples go + * into a separate workspace array; each BTScanPosItem stores its tuple's + * offset within that array. Posting list tuples store a "base" tuple once, + * allowing the same key to be returned for each TID in the posting list + * tuple. + */ + +typedef struct BTScanPosItem /* what we remember about each match */ +{ + ItemPointerData heapTid; /* TID of referenced heap item */ + OffsetNumber indexOffset; /* index item's location within page */ + LocationIndex tupleOffset; /* IndexTuple's offset in workspace, if any */ +} BTScanPosItem; + +typedef struct BTScanPosData +{ + Buffer buf; /* if valid, the buffer is pinned */ + + XLogRecPtr lsn; /* pos in the WAL stream when page was read */ + BlockNumber currPage; /* page referenced by items array */ + BlockNumber nextPage; /* page's right link when we scanned it */ + + /* + * moreLeft and moreRight track whether we think there may be matching + * index entries to the left and right of the current page, respectively. + * We can clear the appropriate one of these flags when _bt_checkkeys() + * returns continuescan = false. + */ + bool moreLeft; + bool moreRight; + + /* + * If we are doing an index-only scan, nextTupleOffset is the first free + * location in the associated tuple storage workspace. + */ + int nextTupleOffset; + + /* + * The items array is always ordered in index order (ie, increasing + * indexoffset). When scanning backwards it is convenient to fill the + * array back-to-front, so we start at the last slot and fill downwards. + * Hence we need both a first-valid-entry and a last-valid-entry counter. + * itemIndex is a cursor showing which entry was last returned to caller. + */ + int firstItem; /* first valid index in items[] */ + int lastItem; /* last valid index in items[] */ + int itemIndex; /* current index in items[] */ + + BTScanPosItem items[MaxTIDsPerBTreePage]; /* MUST BE LAST */ +} BTScanPosData; + +typedef BTScanPosData *BTScanPos; + +#define BTScanPosIsPinned(scanpos) \ +( \ + AssertMacro(BlockNumberIsValid((scanpos).currPage) || \ + !BufferIsValid((scanpos).buf)), \ + BufferIsValid((scanpos).buf) \ +) +#define BTScanPosUnpin(scanpos) \ + do { \ + ReleaseBuffer((scanpos).buf); \ + (scanpos).buf = InvalidBuffer; \ + } while (0) +#define BTScanPosUnpinIfPinned(scanpos) \ + do { \ + if (BTScanPosIsPinned(scanpos)) \ + BTScanPosUnpin(scanpos); \ + } while (0) + +#define BTScanPosIsValid(scanpos) \ +( \ + AssertMacro(BlockNumberIsValid((scanpos).currPage) || \ + !BufferIsValid((scanpos).buf)), \ + BlockNumberIsValid((scanpos).currPage) \ +) +#define BTScanPosInvalidate(scanpos) \ + do { \ + (scanpos).currPage = InvalidBlockNumber; \ + (scanpos).nextPage = InvalidBlockNumber; \ + (scanpos).buf = InvalidBuffer; \ + (scanpos).lsn = InvalidXLogRecPtr; \ + (scanpos).nextTupleOffset = 0; \ + } while (0) + +/* We need one of these for each equality-type SK_SEARCHARRAY scan key */ +typedef struct BTArrayKeyInfo +{ + int scan_key; /* index of associated key in arrayKeyData */ + int cur_elem; /* index of current element in elem_values */ + int mark_elem; /* index of marked element in elem_values */ + int num_elems; /* number of elems in current array value */ + Datum *elem_values; /* array of num_elems Datums */ +} BTArrayKeyInfo; + +typedef struct BTScanOpaqueData +{ + /* all fields (except arraysStarted) are set by _bt_preprocess_keys(): */ + bool qual_ok; /* false if qual can never be satisfied */ + bool arraysStarted; /* Started array keys, but have yet to "reach + * past the end" of all arrays? */ + int numberOfKeys; /* number of preprocessed scan keys */ + ScanKey keyData; /* array of preprocessed scan keys */ + + /* workspace for SK_SEARCHARRAY support */ + ScanKey arrayKeyData; /* modified copy of scan->keyData */ + int numArrayKeys; /* number of equality-type array keys (-1 if + * there are any unsatisfiable array keys) */ + int arrayKeyCount; /* count indicating number of array scan keys + * processed */ + BTArrayKeyInfo *arrayKeys; /* info about each equality-type array key */ + MemoryContext arrayContext; /* scan-lifespan context for array data */ + + /* info about killed items if any (killedItems is NULL if never used) */ + int *killedItems; /* currPos.items indexes of killed items */ + int numKilled; /* number of currently stored items */ + + /* + * If we are doing an index-only scan, these are the tuple storage + * workspaces for the currPos and markPos respectively. Each is of size + * BLCKSZ, so it can hold as much as a full page's worth of tuples. + */ + char *currTuples; /* tuple storage for currPos */ + char *markTuples; /* tuple storage for markPos */ + + /* + * If the marked position is on the same page as current position, we + * don't use markPos, but just keep the marked itemIndex in markItemIndex + * (all the rest of currPos is valid for the mark position). Hence, to + * determine if there is a mark, first look at markItemIndex, then at + * markPos. + */ + int markItemIndex; /* itemIndex, or -1 if not valid */ + + /* keep these last in struct for efficiency */ + BTScanPosData currPos; /* current position data */ + BTScanPosData markPos; /* marked position, if any */ +} BTScanOpaqueData; + +typedef BTScanOpaqueData *BTScanOpaque; + +/* + * We use some private sk_flags bits in preprocessed scan keys. We're allowed + * to use bits 16-31 (see skey.h). The uppermost bits are copied from the + * index's indoption[] array entry for the index attribute. + */ +#define SK_BT_REQFWD 0x00010000 /* required to continue forward scan */ +#define SK_BT_REQBKWD 0x00020000 /* required to continue backward scan */ +#define SK_BT_INDOPTION_SHIFT 24 /* must clear the above bits */ +#define SK_BT_DESC (INDOPTION_DESC << SK_BT_INDOPTION_SHIFT) +#define SK_BT_NULLS_FIRST (INDOPTION_NULLS_FIRST << SK_BT_INDOPTION_SHIFT) + +typedef struct BTOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ + float8 vacuum_cleanup_index_scale_factor; /* deprecated */ + bool deduplicate_items; /* Try to deduplicate items? */ +} BTOptions; + +#define BTGetFillFactor(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == BTREE_AM_OID), \ + (relation)->rd_options ? \ + ((BTOptions *) (relation)->rd_options)->fillfactor : \ + BTREE_DEFAULT_FILLFACTOR) +#define BTGetTargetPageFreeSpace(relation) \ + (BLCKSZ * (100 - BTGetFillFactor(relation)) / 100) +#define BTGetDeduplicateItems(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == BTREE_AM_OID), \ + ((relation)->rd_options ? \ + ((BTOptions *) (relation)->rd_options)->deduplicate_items : true)) + +/* + * Constant definition for progress reporting. Phase numbers must match + * btbuildphasename. + */ +/* PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE is 1 (see progress.h) */ +#define PROGRESS_BTREE_PHASE_INDEXBUILD_TABLESCAN 2 +#define PROGRESS_BTREE_PHASE_PERFORMSORT_1 3 +#define PROGRESS_BTREE_PHASE_PERFORMSORT_2 4 +#define PROGRESS_BTREE_PHASE_LEAF_LOAD 5 + +/* + * external entry points for btree, in nbtree.c + */ +extern void btbuildempty(Relation index); +extern bool btinsert(Relation rel, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); +extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys); +extern Size btestimateparallelscan(void); +extern void btinitparallelscan(void *target); +extern bool btgettuple(IndexScanDesc scan, ScanDirection dir); +extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern void btrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern void btparallelrescan(IndexScanDesc scan); +extern void btendscan(IndexScanDesc scan); +extern void btmarkpos(IndexScanDesc scan); +extern void btrestrpos(IndexScanDesc scan); +extern IndexBulkDeleteResult *btbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); +extern bool btcanreturn(Relation index, int attno); + +/* + * prototypes for internal functions in nbtree.c + */ +extern bool _bt_parallel_seize(IndexScanDesc scan, BlockNumber *pageno); +extern void _bt_parallel_release(IndexScanDesc scan, BlockNumber scan_page); +extern void _bt_parallel_done(IndexScanDesc scan); +extern void _bt_parallel_advance_array_keys(IndexScanDesc scan); + +/* + * prototypes for functions in nbtdedup.c + */ +extern void _bt_dedup_pass(Relation rel, Buffer buf, Relation heapRel, + IndexTuple newitem, Size newitemsz, + bool bottomupdedup); +extern bool _bt_bottomupdel_pass(Relation rel, Buffer buf, Relation heapRel, + Size newitemsz); +extern void _bt_dedup_start_pending(BTDedupState state, IndexTuple base, + OffsetNumber baseoff); +extern bool _bt_dedup_save_htid(BTDedupState state, IndexTuple itup); +extern Size _bt_dedup_finish_pending(Page newpage, BTDedupState state); +extern IndexTuple _bt_form_posting(IndexTuple base, ItemPointer htids, + int nhtids); +extern void _bt_update_posting(BTVacuumPosting vacposting); +extern IndexTuple _bt_swap_posting(IndexTuple newitem, IndexTuple oposting, + int postingoff); + +/* + * prototypes for functions in nbtinsert.c + */ +extern bool _bt_doinsert(Relation rel, IndexTuple itup, + IndexUniqueCheck checkUnique, bool indexUnchanged, + Relation heapRel); +extern void _bt_finish_split(Relation rel, Buffer lbuf, BTStack stack); +extern Buffer _bt_getstackbuf(Relation rel, BTStack stack, BlockNumber child); + +/* + * prototypes for functions in nbtsplitloc.c + */ +extern OffsetNumber _bt_findsplitloc(Relation rel, Page origpage, + OffsetNumber newitemoff, Size newitemsz, IndexTuple newitem, + bool *newitemonleft); + +/* + * prototypes for functions in nbtpage.c + */ +extern void _bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level, + bool allequalimage); +extern bool _bt_vacuum_needs_cleanup(Relation rel); +extern void _bt_set_cleanup_info(Relation rel, BlockNumber num_delpages); +extern void _bt_upgrademetapage(Page page); +extern Buffer _bt_getroot(Relation rel, int access); +extern Buffer _bt_gettrueroot(Relation rel); +extern int _bt_getrootheight(Relation rel); +extern void _bt_metaversion(Relation rel, bool *heapkeyspace, + bool *allequalimage); +extern void _bt_checkpage(Relation rel, Buffer buf); +extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access); +extern Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, + BlockNumber blkno, int access); +extern void _bt_relbuf(Relation rel, Buffer buf); +extern void _bt_lockbuf(Relation rel, Buffer buf, int access); +extern void _bt_unlockbuf(Relation rel, Buffer buf); +extern bool _bt_conditionallockbuf(Relation rel, Buffer buf); +extern void _bt_upgradelockbufcleanup(Relation rel, Buffer buf); +extern void _bt_pageinit(Page page, Size size); +extern void _bt_delitems_vacuum(Relation rel, Buffer buf, + OffsetNumber *deletable, int ndeletable, + BTVacuumPosting *updatable, int nupdatable); +extern void _bt_delitems_delete_check(Relation rel, Buffer buf, + Relation heapRel, + TM_IndexDeleteOp *delstate); +extern void _bt_pagedel(Relation rel, Buffer leafbuf, BTVacState *vstate); +extern void _bt_pendingfsm_init(Relation rel, BTVacState *vstate, + bool cleanuponly); +extern void _bt_pendingfsm_finalize(Relation rel, BTVacState *vstate); + +/* + * prototypes for functions in nbtsearch.c + */ +extern BTStack _bt_search(Relation rel, BTScanInsert key, Buffer *bufP, + int access, Snapshot snapshot); +extern Buffer _bt_moveright(Relation rel, BTScanInsert key, Buffer buf, + bool forupdate, BTStack stack, int access, Snapshot snapshot); +extern OffsetNumber _bt_binsrch_insert(Relation rel, BTInsertState insertstate); +extern int32 _bt_compare(Relation rel, BTScanInsert key, Page page, OffsetNumber offnum); +extern bool _bt_first(IndexScanDesc scan, ScanDirection dir); +extern bool _bt_next(IndexScanDesc scan, ScanDirection dir); +extern Buffer _bt_get_endpoint(Relation rel, uint32 level, bool rightmost, + Snapshot snapshot); + +/* + * prototypes for functions in nbtutils.c + */ +extern BTScanInsert _bt_mkscankey(Relation rel, IndexTuple itup); +extern void _bt_freestack(BTStack stack); +extern void _bt_preprocess_array_keys(IndexScanDesc scan); +extern void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir); +extern bool _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir); +extern void _bt_mark_array_keys(IndexScanDesc scan); +extern void _bt_restore_array_keys(IndexScanDesc scan); +extern void _bt_preprocess_keys(IndexScanDesc scan); +extern bool _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple, + int tupnatts, ScanDirection dir, bool *continuescan); +extern void _bt_killitems(IndexScanDesc scan); +extern BTCycleId _bt_vacuum_cycleid(Relation rel); +extern BTCycleId _bt_start_vacuum(Relation rel); +extern void _bt_end_vacuum(Relation rel); +extern void _bt_end_vacuum_callback(int code, Datum arg); +extern Size BTreeShmemSize(void); +extern void BTreeShmemInit(void); +extern bytea *btoptions(Datum reloptions, bool validate); +extern bool btproperty(Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull); +extern char *btbuildphasename(int64 phasenum); +extern IndexTuple _bt_truncate(Relation rel, IndexTuple lastleft, + IndexTuple firstright, BTScanInsert itup_key); +extern int _bt_keep_natts_fast(Relation rel, IndexTuple lastleft, + IndexTuple firstright); +extern bool _bt_check_natts(Relation rel, bool heapkeyspace, Page page, + OffsetNumber offnum); +extern void _bt_check_third_page(Relation rel, Relation heap, + bool needheaptidspace, Page page, IndexTuple newtup); +extern bool _bt_allequalimage(Relation rel, bool debugmessage); + +/* + * prototypes for functions in nbtvalidate.c + */ +extern bool btvalidate(Oid opclassoid); +extern void btadjustmembers(Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +/* + * prototypes for functions in nbtsort.c + */ +extern IndexBuildResult *btbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc); + +#endif /* NBTREE_H */ diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h new file mode 100644 index 0000000..de362d3 --- /dev/null +++ b/src/include/access/nbtxlog.h @@ -0,0 +1,351 @@ +/*------------------------------------------------------------------------- + * + * nbtxlog.h + * header file for postgres btree xlog routines + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/nbtxlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef NBTXLOG_H +#define NBTXLOG_H + +#include "access/transam.h" +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/off.h" + +/* + * XLOG records for btree operations + * + * XLOG allows to store some information in high 4 bits of log + * record xl_info field + */ +#define XLOG_BTREE_INSERT_LEAF 0x00 /* add index tuple without split */ +#define XLOG_BTREE_INSERT_UPPER 0x10 /* same, on a non-leaf page */ +#define XLOG_BTREE_INSERT_META 0x20 /* same, plus update metapage */ +#define XLOG_BTREE_SPLIT_L 0x30 /* add index tuple with split */ +#define XLOG_BTREE_SPLIT_R 0x40 /* as above, new item on right */ +#define XLOG_BTREE_INSERT_POST 0x50 /* add index tuple with posting split */ +#define XLOG_BTREE_DEDUP 0x60 /* deduplicate tuples for a page */ +#define XLOG_BTREE_DELETE 0x70 /* delete leaf index tuples for a page */ +#define XLOG_BTREE_UNLINK_PAGE 0x80 /* delete a half-dead page */ +#define XLOG_BTREE_UNLINK_PAGE_META 0x90 /* same, and update metapage */ +#define XLOG_BTREE_NEWROOT 0xA0 /* new root page */ +#define XLOG_BTREE_MARK_PAGE_HALFDEAD 0xB0 /* mark a leaf as half-dead */ +#define XLOG_BTREE_VACUUM 0xC0 /* delete entries on a page during + * vacuum */ +#define XLOG_BTREE_REUSE_PAGE 0xD0 /* old page is about to be reused from + * FSM */ +#define XLOG_BTREE_META_CLEANUP 0xE0 /* update cleanup-related data in the + * metapage */ + +/* + * All that we need to regenerate the meta-data page + */ +typedef struct xl_btree_metadata +{ + uint32 version; + BlockNumber root; + uint32 level; + BlockNumber fastroot; + uint32 fastlevel; + uint32 last_cleanup_num_delpages; + bool allequalimage; +} xl_btree_metadata; + +/* + * This is what we need to know about simple (without split) insert. + * + * This data record is used for INSERT_LEAF, INSERT_UPPER, INSERT_META, and + * INSERT_POST. Note that INSERT_META and INSERT_UPPER implies it's not a + * leaf page, while INSERT_POST and INSERT_LEAF imply that it must be a leaf + * page. + * + * Backup Blk 0: original page + * Backup Blk 1: child's left sibling, if INSERT_UPPER or INSERT_META + * Backup Blk 2: xl_btree_metadata, if INSERT_META + * + * Note: The new tuple is actually the "original" new item in the posting + * list split insert case (i.e. the INSERT_POST case). A split offset for + * the posting list is logged before the original new item. Recovery needs + * both, since it must do an in-place update of the existing posting list + * that was split as an extra step. Also, recovery generates a "final" + * newitem. See _bt_swap_posting() for details on posting list splits. + */ +typedef struct xl_btree_insert +{ + OffsetNumber offnum; + + /* POSTING SPLIT OFFSET FOLLOWS (INSERT_POST case) */ + /* NEW TUPLE ALWAYS FOLLOWS AT THE END */ +} xl_btree_insert; + +#define SizeOfBtreeInsert (offsetof(xl_btree_insert, offnum) + sizeof(OffsetNumber)) + +/* + * On insert with split, we save all the items going into the right sibling + * so that we can restore it completely from the log record. This way takes + * less xlog space than the normal approach, because if we did it standardly, + * XLogInsert would almost always think the right page is new and store its + * whole page image. The left page, however, is handled in the normal + * incremental-update fashion. + * + * Note: XLOG_BTREE_SPLIT_L and XLOG_BTREE_SPLIT_R share this data record. + * There are two variants to indicate whether the inserted tuple went into the + * left or right split page (and thus, whether the new item is stored or not). + * We always log the left page high key because suffix truncation can generate + * a new leaf high key using user-defined code. This is also necessary on + * internal pages, since the firstright item that the left page's high key was + * based on will have been truncated to zero attributes in the right page (the + * separator key is unavailable from the right page). + * + * Backup Blk 0: original page / new left page + * + * The left page's data portion contains the new item, if it's the _L variant. + * _R variant split records generally do not have a newitem (_R variant leaf + * page split records that must deal with a posting list split will include an + * explicit newitem, though it is never used on the right page -- it is + * actually an orignewitem needed to update existing posting list). The new + * high key of the left/original page appears last of all (and must always be + * present). + * + * Page split records that need the REDO routine to deal with a posting list + * split directly will have an explicit newitem, which is actually an + * orignewitem (the newitem as it was before the posting list split, not + * after). A posting list split always has a newitem that comes immediately + * after the posting list being split (which would have overlapped with + * orignewitem prior to split). Usually REDO must deal with posting list + * splits with an _L variant page split record, and usually both the new + * posting list and the final newitem go on the left page (the existing + * posting list will be inserted instead of the old, and the final newitem + * will be inserted next to that). However, _R variant split records will + * include an orignewitem when the split point for the page happens to have a + * lastleft tuple that is also the posting list being split (leaving newitem + * as the page split's firstright tuple). The existence of this corner case + * does not change the basic fact about newitem/orignewitem for the REDO + * routine: it is always state used for the left page alone. (This is why the + * record's postingoff field isn't a reliable indicator of whether or not a + * posting list split occurred during the page split; a non-zero value merely + * indicates that the REDO routine must reconstruct a new posting list tuple + * that is needed for the left page.) + * + * This posting list split handling is equivalent to the xl_btree_insert REDO + * routine's INSERT_POST handling. While the details are more complicated + * here, the concept and goals are exactly the same. See _bt_swap_posting() + * for details on posting list splits. + * + * Backup Blk 1: new right page + * + * The right page's data portion contains the right page's tuples in the form + * used by _bt_restore_page. This includes the new item, if it's the _R + * variant. The right page's tuples also include the right page's high key + * with either variant (moved from the left/original page during the split), + * unless the split happened to be of the rightmost page on its level, where + * there is no high key for new right page. + * + * Backup Blk 2: next block (orig page's rightlink), if any + * Backup Blk 3: child's left sibling, if non-leaf split + */ +typedef struct xl_btree_split +{ + uint32 level; /* tree level of page being split */ + OffsetNumber firstrightoff; /* first origpage item on rightpage */ + OffsetNumber newitemoff; /* new item's offset */ + uint16 postingoff; /* offset inside orig posting tuple */ +} xl_btree_split; + +#define SizeOfBtreeSplit (offsetof(xl_btree_split, postingoff) + sizeof(uint16)) + +/* + * When page is deduplicated, consecutive groups of tuples with equal keys are + * merged together into posting list tuples. + * + * The WAL record represents a deduplication pass for a leaf page. An array + * of BTDedupInterval structs follows. + */ +typedef struct xl_btree_dedup +{ + uint16 nintervals; + + /* DEDUPLICATION INTERVALS FOLLOW */ +} xl_btree_dedup; + +#define SizeOfBtreeDedup (offsetof(xl_btree_dedup, nintervals) + sizeof(uint16)) + +/* + * This is what we need to know about page reuse within btree. This record + * only exists to generate a conflict point for Hot Standby. + * + * Note that we must include a RelFileNode in the record because we don't + * actually register the buffer with the record. + */ +typedef struct xl_btree_reuse_page +{ + RelFileNode node; + BlockNumber block; + FullTransactionId latestRemovedFullXid; +} xl_btree_reuse_page; + +#define SizeOfBtreeReusePage (sizeof(xl_btree_reuse_page)) + +/* + * xl_btree_vacuum and xl_btree_delete records describe deletion of index + * tuples on a leaf page. The former variant is used by VACUUM, while the + * latter variant is used by the ad-hoc deletions that sometimes take place + * when btinsert() is called. + * + * The records are very similar. The only difference is that xl_btree_delete + * has to include a latestRemovedXid field to generate recovery conflicts. + * (VACUUM operations can just rely on earlier conflicts generated during + * pruning of the table whose TIDs the to-be-deleted index tuples point to. + * There are also small differences between each REDO routine that we don't go + * into here.) + * + * xl_btree_vacuum and xl_btree_delete both represent deletion of any number + * of index tuples on a single leaf page using page offset numbers. Both also + * support "updates" of index tuples, which is how deletes of a subset of TIDs + * contained in an existing posting list tuple are implemented. + * + * Updated posting list tuples are represented using xl_btree_update metadata. + * The REDO routines each use the xl_btree_update entries (plus each + * corresponding original index tuple from the target leaf page) to generate + * the final updated tuple. + * + * Updates are only used when there will be some remaining TIDs left by the + * REDO routine. Otherwise the posting list tuple just gets deleted outright. + */ +typedef struct xl_btree_vacuum +{ + uint16 ndeleted; + uint16 nupdated; + + /* DELETED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TUPLES METADATA (xl_btree_update) ARRAY FOLLOWS */ +} xl_btree_vacuum; + +#define SizeOfBtreeVacuum (offsetof(xl_btree_vacuum, nupdated) + sizeof(uint16)) + +typedef struct xl_btree_delete +{ + TransactionId latestRemovedXid; + uint16 ndeleted; + uint16 nupdated; + + /* DELETED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TARGET OFFSET NUMBERS FOLLOW */ + /* UPDATED TUPLES METADATA (xl_btree_update) ARRAY FOLLOWS */ +} xl_btree_delete; + +#define SizeOfBtreeDelete (offsetof(xl_btree_delete, nupdated) + sizeof(uint16)) + +/* + * The offsets that appear in xl_btree_update metadata are offsets into the + * original posting list from tuple, not page offset numbers. These are + * 0-based. The page offset number for the original posting list tuple comes + * from the main xl_btree_vacuum/xl_btree_delete record. + */ +typedef struct xl_btree_update +{ + uint16 ndeletedtids; + + /* POSTING LIST uint16 OFFSETS TO A DELETED TID FOLLOW */ +} xl_btree_update; + +#define SizeOfBtreeUpdate (offsetof(xl_btree_update, ndeletedtids) + sizeof(uint16)) + +/* + * This is what we need to know about marking an empty subtree for deletion. + * The target identifies the tuple removed from the parent page (note that we + * remove this tuple's downlink and the *following* tuple's key). Note that + * the leaf page is empty, so we don't need to store its content --- it is + * just reinitialized during recovery using the rest of the fields. + * + * Backup Blk 0: leaf block + * Backup Blk 1: top parent + */ +typedef struct xl_btree_mark_page_halfdead +{ + OffsetNumber poffset; /* deleted tuple id in parent page */ + + /* information needed to recreate the leaf page: */ + BlockNumber leafblk; /* leaf block ultimately being deleted */ + BlockNumber leftblk; /* leaf block's left sibling, if any */ + BlockNumber rightblk; /* leaf block's right sibling */ + BlockNumber topparent; /* topmost internal page in the subtree */ +} xl_btree_mark_page_halfdead; + +#define SizeOfBtreeMarkPageHalfDead (offsetof(xl_btree_mark_page_halfdead, topparent) + sizeof(BlockNumber)) + +/* + * This is what we need to know about deletion of a btree page. Note that we + * only leave behind a small amount of bookkeeping information in deleted + * pages (deleted pages must be kept around as tombstones for a while). It is + * convenient for the REDO routine to regenerate its target page from scratch. + * This is why WAL record describes certain details that are actually directly + * available from the target page. + * + * Backup Blk 0: target block being deleted + * Backup Blk 1: target block's left sibling, if any + * Backup Blk 2: target block's right sibling + * Backup Blk 3: leaf block (if different from target) + * Backup Blk 4: metapage (if rightsib becomes new fast root) + */ +typedef struct xl_btree_unlink_page +{ + BlockNumber leftsib; /* target block's left sibling, if any */ + BlockNumber rightsib; /* target block's right sibling */ + uint32 level; /* target block's level */ + FullTransactionId safexid; /* target block's BTPageSetDeleted() XID */ + + /* + * Information needed to recreate a half-dead leaf page with correct + * topparent link. The fields are only used when deletion operation's + * target page is an internal page. REDO routine creates half-dead page + * from scratch to keep things simple (this is the same convenient + * approach used for the target page itself). + */ + BlockNumber leafleftsib; + BlockNumber leafrightsib; + BlockNumber leaftopparent; /* next child down in the subtree */ + + /* xl_btree_metadata FOLLOWS IF XLOG_BTREE_UNLINK_PAGE_META */ +} xl_btree_unlink_page; + +#define SizeOfBtreeUnlinkPage (offsetof(xl_btree_unlink_page, leaftopparent) + sizeof(BlockNumber)) + +/* + * New root log record. There are zero tuples if this is to establish an + * empty root, or two if it is the result of splitting an old root. + * + * Note that although this implies rewriting the metadata page, we don't need + * an xl_btree_metadata record --- the rootblk and level are sufficient. + * + * Backup Blk 0: new root page (2 tuples as payload, if splitting old root) + * Backup Blk 1: left child (if splitting an old root) + * Backup Blk 2: metapage + */ +typedef struct xl_btree_newroot +{ + BlockNumber rootblk; /* location of new root (redundant with blk 0) */ + uint32 level; /* its tree level */ +} xl_btree_newroot; + +#define SizeOfBtreeNewroot (offsetof(xl_btree_newroot, level) + sizeof(uint32)) + + +/* + * prototypes for functions in nbtxlog.c + */ +extern void btree_redo(XLogReaderState *record); +extern void btree_desc(StringInfo buf, XLogReaderState *record); +extern const char *btree_identify(uint8 info); +extern void btree_xlog_startup(void); +extern void btree_xlog_cleanup(void); +extern void btree_mask(char *pagedata, BlockNumber blkno); + +#endif /* NBTXLOG_H */ diff --git a/src/include/access/parallel.h b/src/include/access/parallel.h new file mode 100644 index 0000000..983841d --- /dev/null +++ b/src/include/access/parallel.h @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------- + * + * parallel.h + * Infrastructure for launching parallel workers + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/parallel.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PARALLEL_H +#define PARALLEL_H + +#include "access/xlogdefs.h" +#include "lib/ilist.h" +#include "postmaster/bgworker.h" +#include "storage/shm_mq.h" +#include "storage/shm_toc.h" + +typedef void (*parallel_worker_main_type) (dsm_segment *seg, shm_toc *toc); + +typedef struct ParallelWorkerInfo +{ + BackgroundWorkerHandle *bgwhandle; + shm_mq_handle *error_mqh; + int32 pid; +} ParallelWorkerInfo; + +typedef struct ParallelContext +{ + dlist_node node; + SubTransactionId subid; + int nworkers; /* Maximum number of workers to launch */ + int nworkers_to_launch; /* Actual number of workers to launch */ + int nworkers_launched; + char *library_name; + char *function_name; + ErrorContextCallback *error_context_stack; + shm_toc_estimator estimator; + dsm_segment *seg; + void *private_memory; + shm_toc *toc; + ParallelWorkerInfo *worker; + int nknown_attached_workers; + bool *known_attached_workers; +} ParallelContext; + +typedef struct ParallelWorkerContext +{ + dsm_segment *seg; + shm_toc *toc; +} ParallelWorkerContext; + +extern PGDLLIMPORT volatile bool ParallelMessagePending; +extern PGDLLIMPORT int ParallelWorkerNumber; +extern PGDLLIMPORT bool InitializingParallelWorker; + +#define IsParallelWorker() (ParallelWorkerNumber >= 0) + +extern ParallelContext *CreateParallelContext(const char *library_name, + const char *function_name, int nworkers); +extern void InitializeParallelDSM(ParallelContext *pcxt); +extern void ReinitializeParallelDSM(ParallelContext *pcxt); +extern void ReinitializeParallelWorkers(ParallelContext *pcxt, int nworkers_to_launch); +extern void LaunchParallelWorkers(ParallelContext *pcxt); +extern void WaitForParallelWorkersToAttach(ParallelContext *pcxt); +extern void WaitForParallelWorkersToFinish(ParallelContext *pcxt); +extern void DestroyParallelContext(ParallelContext *pcxt); +extern bool ParallelContextActive(void); + +extern void HandleParallelMessageInterrupt(void); +extern void HandleParallelMessages(void); +extern void AtEOXact_Parallel(bool isCommit); +extern void AtEOSubXact_Parallel(bool isCommit, SubTransactionId mySubId); +extern void ParallelWorkerReportLastRecEnd(XLogRecPtr last_xlog_end); + +extern void ParallelWorkerMain(Datum main_arg); + +#endif /* PARALLEL_H */ diff --git a/src/include/access/printsimple.h b/src/include/access/printsimple.h new file mode 100644 index 0000000..010a7f2 --- /dev/null +++ b/src/include/access/printsimple.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * printsimple.h + * print simple tuples without catalog access + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/printsimple.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PRINTSIMPLE_H +#define PRINTSIMPLE_H + +#include "tcop/dest.h" + +extern bool printsimple(TupleTableSlot *slot, DestReceiver *self); +extern void printsimple_startup(DestReceiver *self, int operation, + TupleDesc tupdesc); + +#endif /* PRINTSIMPLE_H */ diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h new file mode 100644 index 0000000..971a74c --- /dev/null +++ b/src/include/access/printtup.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * printtup.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/printtup.h + * + *------------------------------------------------------------------------- + */ +#ifndef PRINTTUP_H +#define PRINTTUP_H + +#include "utils/portal.h" + +extern DestReceiver *printtup_create_DR(CommandDest dest); + +extern void SetRemoteDestReceiverParams(DestReceiver *self, Portal portal); + +extern void SendRowDescriptionMessage(StringInfo buf, + TupleDesc typeinfo, List *targetlist, int16 *formats); + +extern void debugStartup(DestReceiver *self, int operation, + TupleDesc typeinfo); +extern bool debugtup(TupleTableSlot *slot, DestReceiver *self); + +/* XXX these are really in executor/spi.c */ +extern void spi_dest_startup(DestReceiver *self, int operation, + TupleDesc typeinfo); +extern bool spi_printtup(TupleTableSlot *slot, DestReceiver *self); + +#endif /* PRINTTUP_H */ diff --git a/src/include/access/relation.h b/src/include/access/relation.h new file mode 100644 index 0000000..d362793 --- /dev/null +++ b/src/include/access/relation.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * relation.h + * Generic relation related routines. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/relation.h + * + *------------------------------------------------------------------------- + */ +#ifndef ACCESS_RELATION_H +#define ACCESS_RELATION_H + +#include "nodes/primnodes.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" + +extern Relation relation_open(Oid relationId, LOCKMODE lockmode); +extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode); +extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode); +extern Relation relation_openrv_extended(const RangeVar *relation, + LOCKMODE lockmode, bool missing_ok); +extern void relation_close(Relation relation, LOCKMODE lockmode); + +#endif /* ACCESS_RELATION_H */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h new file mode 100644 index 0000000..f740513 --- /dev/null +++ b/src/include/access/reloptions.h @@ -0,0 +1,247 @@ +/*------------------------------------------------------------------------- + * + * reloptions.h + * Core support for relation and tablespace options (pg_class.reloptions + * and pg_tablespace.spcoptions) + * + * Note: the functions dealing with text-array reloptions values declare + * them as Datum, not ArrayType *, to avoid needing to include array.h + * into a lot of low-level code. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/reloptions.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELOPTIONS_H +#define RELOPTIONS_H + +#include "access/amapi.h" +#include "access/htup.h" +#include "access/tupdesc.h" +#include "nodes/pg_list.h" +#include "storage/lock.h" + +/* types supported by reloptions */ +typedef enum relopt_type +{ + RELOPT_TYPE_BOOL, + RELOPT_TYPE_INT, + RELOPT_TYPE_REAL, + RELOPT_TYPE_ENUM, + RELOPT_TYPE_STRING +} relopt_type; + +/* kinds supported by reloptions */ +typedef enum relopt_kind +{ + RELOPT_KIND_LOCAL = 0, + RELOPT_KIND_HEAP = (1 << 0), + RELOPT_KIND_TOAST = (1 << 1), + RELOPT_KIND_BTREE = (1 << 2), + RELOPT_KIND_HASH = (1 << 3), + RELOPT_KIND_GIN = (1 << 4), + RELOPT_KIND_GIST = (1 << 5), + RELOPT_KIND_ATTRIBUTE = (1 << 6), + RELOPT_KIND_TABLESPACE = (1 << 7), + RELOPT_KIND_SPGIST = (1 << 8), + RELOPT_KIND_VIEW = (1 << 9), + RELOPT_KIND_BRIN = (1 << 10), + RELOPT_KIND_PARTITIONED = (1 << 11), + /* if you add a new kind, make sure you update "last_default" too */ + RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED, + /* some compilers treat enums as signed ints, so we can't use 1 << 31 */ + RELOPT_KIND_MAX = (1 << 30) +} relopt_kind; + +/* reloption namespaces allowed for heaps -- currently only TOAST */ +#define HEAP_RELOPT_NAMESPACES { "toast", NULL } + +/* generic struct to hold shared data */ +typedef struct relopt_gen +{ + const char *name; /* must be first (used as list termination + * marker) */ + const char *desc; + bits32 kinds; + LOCKMODE lockmode; + int namelen; + relopt_type type; +} relopt_gen; + +/* holds a parsed value */ +typedef struct relopt_value +{ + relopt_gen *gen; + bool isset; + union + { + bool bool_val; + int int_val; + double real_val; + int enum_val; + char *string_val; /* allocated separately */ + } values; +} relopt_value; + +/* reloptions records for specific variable types */ +typedef struct relopt_bool +{ + relopt_gen gen; + bool default_val; +} relopt_bool; + +typedef struct relopt_int +{ + relopt_gen gen; + int default_val; + int min; + int max; +} relopt_int; + +typedef struct relopt_real +{ + relopt_gen gen; + double default_val; + double min; + double max; +} relopt_real; + +/* + * relopt_enum_elt_def -- One member of the array of acceptable values + * of an enum reloption. + */ +typedef struct relopt_enum_elt_def +{ + const char *string_val; + int symbol_val; +} relopt_enum_elt_def; + +typedef struct relopt_enum +{ + relopt_gen gen; + relopt_enum_elt_def *members; + int default_val; + const char *detailmsg; + /* null-terminated array of members */ +} relopt_enum; + +/* validation routines for strings */ +typedef void (*validate_string_relopt) (const char *value); +typedef Size (*fill_string_relopt) (const char *value, void *ptr); + +/* validation routine for the whole option set */ +typedef void (*relopts_validator) (void *parsed_options, relopt_value *vals, int nvals); + +typedef struct relopt_string +{ + relopt_gen gen; + int default_len; + bool default_isnull; + validate_string_relopt validate_cb; + fill_string_relopt fill_cb; + char *default_val; +} relopt_string; + +/* This is the table datatype for build_reloptions() */ +typedef struct +{ + const char *optname; /* option's name */ + relopt_type opttype; /* option's datatype */ + int offset; /* offset of field in result struct */ +} relopt_parse_elt; + +/* Local reloption definition */ +typedef struct local_relopt +{ + relopt_gen *option; /* option definition */ + int offset; /* offset of parsed value in bytea structure */ +} local_relopt; + +/* Structure to hold local reloption data for build_local_reloptions() */ +typedef struct local_relopts +{ + List *options; /* list of local_relopt definitions */ + List *validators; /* list of relopts_validator callbacks */ + Size relopt_struct_size; /* size of parsed bytea structure */ +} local_relopts; + +/* + * Utility macro to get a value for a string reloption once the options + * are parsed. This gets a pointer to the string value itself. "optstruct" + * is the StdRdOptions struct or equivalent, "member" is the struct member + * corresponding to the string option. + */ +#define GET_STRING_RELOPTION(optstruct, member) \ + ((optstruct)->member == 0 ? NULL : \ + (char *)(optstruct) + (optstruct)->member) + +extern relopt_kind add_reloption_kind(void); +extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, + bool default_val, LOCKMODE lockmode); +extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, + int default_val, int min_val, int max_val, + LOCKMODE lockmode); +extern void add_real_reloption(bits32 kinds, const char *name, const char *desc, + double default_val, double min_val, double max_val, + LOCKMODE lockmode); +extern void add_enum_reloption(bits32 kinds, const char *name, const char *desc, + relopt_enum_elt_def *members, int default_val, + const char *detailmsg, LOCKMODE lockmode); +extern void add_string_reloption(bits32 kinds, const char *name, const char *desc, + const char *default_val, validate_string_relopt validator, + LOCKMODE lockmode); + +extern void init_local_reloptions(local_relopts *opts, Size relopt_struct_size); +extern void register_reloptions_validator(local_relopts *opts, + relopts_validator validator); +extern void add_local_bool_reloption(local_relopts *opts, const char *name, + const char *desc, bool default_val, + int offset); +extern void add_local_int_reloption(local_relopts *opts, const char *name, + const char *desc, int default_val, + int min_val, int max_val, int offset); +extern void add_local_real_reloption(local_relopts *opts, const char *name, + const char *desc, double default_val, + double min_val, double max_val, + int offset); +extern void add_local_enum_reloption(local_relopts *relopts, + const char *name, const char *desc, + relopt_enum_elt_def *members, + int default_val, const char *detailmsg, + int offset); +extern void add_local_string_reloption(local_relopts *opts, const char *name, + const char *desc, + const char *default_val, + validate_string_relopt validator, + fill_string_relopt filler, int offset); + +extern Datum transformRelOptions(Datum oldOptions, List *defList, + const char *namspace, char *validnsps[], + bool acceptOidsOff, bool isReset); +extern List *untransformRelOptions(Datum options); +extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, + amoptions_function amoptions); +extern void *build_reloptions(Datum reloptions, bool validate, + relopt_kind kind, + Size relopt_struct_size, + const relopt_parse_elt *relopt_elems, + int num_relopt_elems); +extern void *build_local_reloptions(local_relopts *relopts, Datum options, + bool validate); + +extern bytea *default_reloptions(Datum reloptions, bool validate, + relopt_kind kind); +extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate); +extern bytea *view_reloptions(Datum reloptions, bool validate); +extern bytea *partitioned_table_reloptions(Datum reloptions, bool validate); +extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions, + bool validate); +extern bytea *attribute_reloptions(Datum reloptions, bool validate); +extern bytea *tablespace_reloptions(Datum reloptions, bool validate); +extern LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList); + +#endif /* RELOPTIONS_H */ diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h new file mode 100644 index 0000000..53a93cc --- /dev/null +++ b/src/include/access/relscan.h @@ -0,0 +1,191 @@ +/*------------------------------------------------------------------------- + * + * relscan.h + * POSTGRES relation scan descriptor definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/relscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELSCAN_H +#define RELSCAN_H + +#include "access/htup_details.h" +#include "access/itup.h" +#include "port/atomics.h" +#include "storage/buf.h" +#include "storage/spin.h" +#include "utils/relcache.h" + + +struct ParallelTableScanDescData; + +/* + * Generic descriptor for table scans. This is the base-class for table scans, + * which needs to be embedded in the scans of individual AMs. + */ +typedef struct TableScanDescData +{ + /* scan parameters */ + Relation rs_rd; /* heap relation descriptor */ + struct SnapshotData *rs_snapshot; /* snapshot to see */ + int rs_nkeys; /* number of scan keys */ + struct ScanKeyData *rs_key; /* array of scan key descriptors */ + + /* Range of ItemPointers for table_scan_getnextslot_tidrange() to scan. */ + ItemPointerData rs_mintid; + ItemPointerData rs_maxtid; + + /* + * Information about type and behaviour of the scan, a bitmask of members + * of the ScanOptions enum (see tableam.h). + */ + uint32 rs_flags; + + struct ParallelTableScanDescData *rs_parallel; /* parallel scan + * information */ +} TableScanDescData; +typedef struct TableScanDescData *TableScanDesc; + +/* + * Shared state for parallel table scan. + * + * Each backend participating in a parallel table scan has its own + * TableScanDesc in backend-private memory, and those objects all contain a + * pointer to this structure. The information here must be sufficient to + * properly initialize each new TableScanDesc as workers join the scan, and it + * must act as a information what to scan for those workers. + */ +typedef struct ParallelTableScanDescData +{ + Oid phs_relid; /* OID of relation to scan */ + bool phs_syncscan; /* report location to syncscan logic? */ + bool phs_snapshot_any; /* SnapshotAny, not phs_snapshot_data? */ + Size phs_snapshot_off; /* data for snapshot */ +} ParallelTableScanDescData; +typedef struct ParallelTableScanDescData *ParallelTableScanDesc; + +/* + * Shared state for parallel table scans, for block oriented storage. + */ +typedef struct ParallelBlockTableScanDescData +{ + ParallelTableScanDescData base; + + BlockNumber phs_nblocks; /* # blocks in relation at start of scan */ + slock_t phs_mutex; /* mutual exclusion for setting startblock */ + BlockNumber phs_startblock; /* starting block number */ + pg_atomic_uint64 phs_nallocated; /* number of blocks allocated to + * workers so far. */ +} ParallelBlockTableScanDescData; +typedef struct ParallelBlockTableScanDescData *ParallelBlockTableScanDesc; + +/* + * Per backend state for parallel table scan, for block-oriented storage. + */ +typedef struct ParallelBlockTableScanWorkerData +{ + uint64 phsw_nallocated; /* Current # of blocks into the scan */ + uint32 phsw_chunk_remaining; /* # blocks left in this chunk */ + uint32 phsw_chunk_size; /* The number of blocks to allocate in + * each I/O chunk for the scan */ +} ParallelBlockTableScanWorkerData; +typedef struct ParallelBlockTableScanWorkerData *ParallelBlockTableScanWorker; + +/* + * Base class for fetches from a table via an index. This is the base-class + * for such scans, which needs to be embedded in the respective struct for + * individual AMs. + */ +typedef struct IndexFetchTableData +{ + Relation rel; +} IndexFetchTableData; + +/* + * We use the same IndexScanDescData structure for both amgettuple-based + * and amgetbitmap-based index scans. Some fields are only relevant in + * amgettuple-based scans. + */ +typedef struct IndexScanDescData +{ + /* scan parameters */ + Relation heapRelation; /* heap relation descriptor, or NULL */ + Relation indexRelation; /* index relation descriptor */ + struct SnapshotData *xs_snapshot; /* snapshot to see */ + int numberOfKeys; /* number of index qualifier conditions */ + int numberOfOrderBys; /* number of ordering operators */ + struct ScanKeyData *keyData; /* array of index qualifier descriptors */ + struct ScanKeyData *orderByData; /* array of ordering op descriptors */ + bool xs_want_itup; /* caller requests index tuples */ + bool xs_temp_snap; /* unregister snapshot at scan end? */ + + /* signaling to index AM about killing index tuples */ + bool kill_prior_tuple; /* last-returned tuple is dead */ + bool ignore_killed_tuples; /* do not return killed entries */ + bool xactStartedInRecovery; /* prevents killing/seeing killed + * tuples */ + + /* index access method's private state */ + void *opaque; /* access-method-specific info */ + + /* + * In an index-only scan, a successful amgettuple call must fill either + * xs_itup (and xs_itupdesc) or xs_hitup (and xs_hitupdesc) to provide the + * data returned by the scan. It can fill both, in which case the heap + * format will be used. + */ + IndexTuple xs_itup; /* index tuple returned by AM */ + struct TupleDescData *xs_itupdesc; /* rowtype descriptor of xs_itup */ + HeapTuple xs_hitup; /* index data returned by AM, as HeapTuple */ + struct TupleDescData *xs_hitupdesc; /* rowtype descriptor of xs_hitup */ + + ItemPointerData xs_heaptid; /* result */ + bool xs_heap_continue; /* T if must keep walking, potential + * further results */ + IndexFetchTableData *xs_heapfetch; + + bool xs_recheck; /* T means scan keys must be rechecked */ + + /* + * When fetching with an ordering operator, the values of the ORDER BY + * expressions of the last returned tuple, according to the index. If + * xs_recheckorderby is true, these need to be rechecked just like the + * scan keys, and the values returned here are a lower-bound on the actual + * values. + */ + Datum *xs_orderbyvals; + bool *xs_orderbynulls; + bool xs_recheckorderby; + + /* parallel index scan information, in shared memory */ + struct ParallelIndexScanDescData *parallel_scan; +} IndexScanDescData; + +/* Generic structure for parallel scans */ +typedef struct ParallelIndexScanDescData +{ + Oid ps_relid; + Oid ps_indexid; + Size ps_offset; /* Offset in bytes of am specific structure */ + char ps_snapshot_data[FLEXIBLE_ARRAY_MEMBER]; +} ParallelIndexScanDescData; + +struct TupleTableSlot; + +/* Struct for storage-or-index scans of system tables */ +typedef struct SysScanDescData +{ + Relation heap_rel; /* catalog being scanned */ + Relation irel; /* NULL if doing heap scan */ + struct TableScanDescData *scan; /* only valid in storage-scan case */ + struct IndexScanDescData *iscan; /* only valid in index-scan case */ + struct SnapshotData *snapshot; /* snapshot to unregister at end of scan */ + struct TupleTableSlot *slot; +} SysScanDescData; + +#endif /* RELSCAN_H */ diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h new file mode 100644 index 0000000..3e27790 --- /dev/null +++ b/src/include/access/rewriteheap.h @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * rewriteheap.h + * Declarations for heap rewrite support functions + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994-5, Regents of the University of California + * + * src/include/access/rewriteheap.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITE_HEAP_H +#define REWRITE_HEAP_H + +#include "access/htup.h" +#include "storage/itemptr.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + +/* struct definition is private to rewriteheap.c */ +typedef struct RewriteStateData *RewriteState; + +extern RewriteState begin_heap_rewrite(Relation OldHeap, Relation NewHeap, + TransactionId OldestXmin, TransactionId FreezeXid, + MultiXactId MultiXactCutoff); +extern void end_heap_rewrite(RewriteState state); +extern void rewrite_heap_tuple(RewriteState state, HeapTuple oldTuple, + HeapTuple newTuple); +extern bool rewrite_heap_dead_tuple(RewriteState state, HeapTuple oldTuple); + +/* + * On-Disk data format for an individual logical rewrite mapping. + */ +typedef struct LogicalRewriteMappingData +{ + RelFileNode old_node; + RelFileNode new_node; + ItemPointerData old_tid; + ItemPointerData new_tid; +} LogicalRewriteMappingData; + +/* --- + * The filename consists of the following, dash separated, + * components: + * 1) database oid or InvalidOid for shared relations + * 2) the oid of the relation + * 3) upper 32bit of the LSN at which a rewrite started + * 4) lower 32bit of the LSN at which a rewrite started + * 5) xid we are mapping for + * 6) xid of the xact performing the mapping + * --- + */ +#define LOGICAL_REWRITE_FORMAT "map-%x-%x-%X_%X-%x-%x" +extern void CheckPointLogicalRewriteHeap(void); + +#endif /* REWRITE_HEAP_H */ diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h new file mode 100644 index 0000000..3b6a497 --- /dev/null +++ b/src/include/access/rmgr.h @@ -0,0 +1,62 @@ +/* + * rmgr.h + * + * Resource managers definition + * + * src/include/access/rmgr.h + */ +#ifndef RMGR_H +#define RMGR_H + +typedef uint8 RmgrId; + +/* + * Built-in resource managers + * + * The actual numerical values for each rmgr ID are defined by the order + * of entries in rmgrlist.h. + * + * Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG + * file format. + */ +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \ + symname, + +typedef enum RmgrIds +{ +#include "access/rmgrlist.h" + RM_NEXT_ID +} RmgrIds; + +#undef PG_RMGR + +#define RM_MAX_ID UINT8_MAX +#define RM_MAX_BUILTIN_ID (RM_NEXT_ID - 1) +#define RM_MIN_CUSTOM_ID 128 +#define RM_MAX_CUSTOM_ID UINT8_MAX +#define RM_N_IDS (UINT8_MAX + 1) +#define RM_N_BUILTIN_IDS (RM_MAX_BUILTIN_ID + 1) +#define RM_N_CUSTOM_IDS (RM_MAX_CUSTOM_ID - RM_MIN_CUSTOM_ID + 1) + +static inline bool +RmgrIdIsBuiltin(int rmid) +{ + return rmid <= RM_MAX_BUILTIN_ID; +} + +static inline bool +RmgrIdIsCustom(int rmid) +{ + return rmid >= RM_MIN_CUSTOM_ID && rmid <= RM_MAX_CUSTOM_ID; +} + +#define RmgrIdIsValid(rmid) (RmgrIdIsBuiltin((rmid)) || RmgrIdIsCustom((rmid))) + +/* + * RmgrId to use for extensions that require an RmgrId, but are still in + * development and have not reserved their own unique RmgrId yet. See: + * https://wiki.postgresql.org/wiki/CustomWALResourceManagers + */ +#define RM_EXPERIMENTAL_ID 128 + +#endif /* RMGR_H */ diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h new file mode 100644 index 0000000..9a74721 --- /dev/null +++ b/src/include/access/rmgrlist.h @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------- + * rmgrlist.h + * + * The resource manager list is kept in its own source file for possible + * use by automatic tools. The exact representation of a rmgr is determined + * by the PG_RMGR macro, which is not defined in this file; it can be + * defined by the caller for special purposes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/rmgrlist.h + *--------------------------------------------------------------------------- + */ + +/* there is deliberately not an #ifndef RMGRLIST_H here */ + +/* + * List of resource manager entries. Note that order of entries defines the + * numerical values of each rmgr's ID, which is stored in WAL records. New + * entries should be added at the end, to avoid changing IDs of existing + * entries. + * + * Changes to this list possibly need an XLOG_PAGE_MAGIC bump. + */ + +/* symbol name, textual name, redo, desc, identify, startup, cleanup */ +PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL, NULL, xlog_decode) +PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL, NULL, xact_decode) +PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL, NULL, standby_decode) +PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL, heap_mask, heap2_decode) +PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL, heap_mask, heap_decode) +PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, btree_xlog_startup, btree_xlog_cleanup, btree_mask, NULL) +PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL, hash_mask, NULL) +PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup, gin_mask, NULL) +PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup, gist_mask, NULL) +PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL, seq_mask, NULL) +PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup, spg_mask, NULL) +PG_RMGR(RM_BRIN_ID, "BRIN", brin_redo, brin_desc, brin_identify, NULL, NULL, brin_mask, NULL) +PG_RMGR(RM_COMMIT_TS_ID, "CommitTs", commit_ts_redo, commit_ts_desc, commit_ts_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_REPLORIGIN_ID, "ReplicationOrigin", replorigin_redo, replorigin_desc, replorigin_identify, NULL, NULL, NULL, NULL) +PG_RMGR(RM_GENERIC_ID, "Generic", generic_redo, generic_desc, generic_identify, NULL, NULL, generic_mask, NULL) +PG_RMGR(RM_LOGICALMSG_ID, "LogicalMessage", logicalmsg_redo, logicalmsg_desc, logicalmsg_identify, NULL, NULL, NULL, logicalmsg_decode) diff --git a/src/include/access/sdir.h b/src/include/access/sdir.h new file mode 100644 index 0000000..1ab4d5e --- /dev/null +++ b/src/include/access/sdir.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * sdir.h + * POSTGRES scan direction definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/sdir.h + * + *------------------------------------------------------------------------- + */ +#ifndef SDIR_H +#define SDIR_H + + +/* + * ScanDirection was an int8 for no apparent reason. I kept the original + * values because I'm not sure if I'll break anything otherwise. -ay 2/95 + */ +typedef enum ScanDirection +{ + BackwardScanDirection = -1, + NoMovementScanDirection = 0, + ForwardScanDirection = 1 +} ScanDirection; + +/* + * ScanDirectionIsValid + * True iff scan direction is valid. + */ +#define ScanDirectionIsValid(direction) \ + ((bool) (BackwardScanDirection <= (direction) && \ + (direction) <= ForwardScanDirection)) + +/* + * ScanDirectionIsBackward + * True iff scan direction is backward. + */ +#define ScanDirectionIsBackward(direction) \ + ((bool) ((direction) == BackwardScanDirection)) + +/* + * ScanDirectionIsNoMovement + * True iff scan direction indicates no movement. + */ +#define ScanDirectionIsNoMovement(direction) \ + ((bool) ((direction) == NoMovementScanDirection)) + +/* + * ScanDirectionIsForward + * True iff scan direction is forward. + */ +#define ScanDirectionIsForward(direction) \ + ((bool) ((direction) == ForwardScanDirection)) + +#endif /* SDIR_H */ diff --git a/src/include/access/session.h b/src/include/access/session.h new file mode 100644 index 0000000..775888b --- /dev/null +++ b/src/include/access/session.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * session.h + * Encapsulation of user session. + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/access/session.h + * + *------------------------------------------------------------------------- + */ +#ifndef SESSION_H +#define SESSION_H + +#include "lib/dshash.h" + +/* Avoid including typcache.h */ +struct SharedRecordTypmodRegistry; + +/* + * A struct encapsulating some elements of a user's session. For now this + * manages state that applies to parallel query, but in principle it could + * include other things that are currently global variables. + */ +typedef struct Session +{ + dsm_segment *segment; /* The session-scoped DSM segment. */ + dsa_area *area; /* The session-scoped DSA area. */ + + /* State managed by typcache.c. */ + struct SharedRecordTypmodRegistry *shared_typmod_registry; + dshash_table *shared_record_table; + dshash_table *shared_typmod_table; +} Session; + +extern void InitializeSession(void); +extern dsm_handle GetSessionDsmHandle(void); +extern void AttachSession(dsm_handle handle); +extern void DetachSession(void); + +/* The current session, or NULL for none. */ +extern PGDLLIMPORT Session *CurrentSession; + +#endif /* SESSION_H */ diff --git a/src/include/access/skey.h b/src/include/access/skey.h new file mode 100644 index 0000000..b5ab17f --- /dev/null +++ b/src/include/access/skey.h @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * skey.h + * POSTGRES scan key definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/skey.h + * + *------------------------------------------------------------------------- + */ +#ifndef SKEY_H +#define SKEY_H + +#include "access/attnum.h" +#include "access/stratnum.h" +#include "fmgr.h" + + +/* + * A ScanKey represents the application of a comparison operator between + * a table or index column and a constant. When it's part of an array of + * ScanKeys, the comparison conditions are implicitly ANDed. The index + * column is the left argument of the operator, if it's a binary operator. + * (The data structure can support unary indexable operators too; in that + * case sk_argument would go unused. This is not currently implemented.) + * + * For an index scan, sk_strategy and sk_subtype must be set correctly for + * the operator. When using a ScanKey in a heap scan, these fields are not + * used and may be set to InvalidStrategy/InvalidOid. + * + * If the operator is collation-sensitive, sk_collation must be set + * correctly as well. + * + * A ScanKey can also represent a ScalarArrayOpExpr, that is a condition + * "column op ANY(ARRAY[...])". This is signaled by the SK_SEARCHARRAY + * flag bit. The sk_argument is not a value of the operator's right-hand + * argument type, but rather an array of such values, and the per-element + * comparisons are to be ORed together. + * + * A ScanKey can also represent a condition "column IS NULL" or "column + * IS NOT NULL"; these cases are signaled by the SK_SEARCHNULL and + * SK_SEARCHNOTNULL flag bits respectively. The argument is always NULL, + * and the sk_strategy, sk_subtype, sk_collation, and sk_func fields are + * not used (unless set by the index AM). + * + * SK_SEARCHARRAY, SK_SEARCHNULL and SK_SEARCHNOTNULL are supported only + * for index scans, not heap scans; and not all index AMs support them, + * only those that set amsearcharray or amsearchnulls respectively. + * + * A ScanKey can also represent an ordering operator invocation, that is + * an ordering requirement "ORDER BY indexedcol op constant". This looks + * the same as a comparison operator, except that the operator doesn't + * (usually) yield boolean. We mark such ScanKeys with SK_ORDER_BY. + * SK_SEARCHARRAY, SK_SEARCHNULL, SK_SEARCHNOTNULL cannot be used here. + * + * Note: in some places, ScanKeys are used as a convenient representation + * for the invocation of an access method support procedure. In this case + * sk_strategy/sk_subtype are not meaningful (but sk_collation can be); and + * sk_func may refer to a function that returns something other than boolean. + */ +typedef struct ScanKeyData +{ + int sk_flags; /* flags, see below */ + AttrNumber sk_attno; /* table or index column number */ + StrategyNumber sk_strategy; /* operator strategy number */ + Oid sk_subtype; /* strategy subtype */ + Oid sk_collation; /* collation to use, if needed */ + FmgrInfo sk_func; /* lookup info for function to call */ + Datum sk_argument; /* data to compare */ +} ScanKeyData; + +typedef ScanKeyData *ScanKey; + +/* + * About row comparisons: + * + * The ScanKey data structure also supports row comparisons, that is ordered + * tuple comparisons like (x, y) > (c1, c2), having the SQL-spec semantics + * "x > c1 OR (x = c1 AND y > c2)". Note that this is currently only + * implemented for btree index searches, not for heapscans or any other index + * type. A row comparison is represented by a "header" ScanKey entry plus + * a separate array of ScanKeys, one for each column of the row comparison. + * The header entry has these properties: + * sk_flags = SK_ROW_HEADER + * sk_attno = index column number for leading column of row comparison + * sk_strategy = btree strategy code for semantics of row comparison + * (ie, < <= > or >=) + * sk_subtype, sk_collation, sk_func: not used + * sk_argument: pointer to subsidiary ScanKey array + * If the header is part of a ScanKey array that's sorted by attno, it + * must be sorted according to the leading column number. + * + * The subsidiary ScanKey array appears in logical column order of the row + * comparison, which may be different from index column order. The array + * elements are like a normal ScanKey array except that: + * sk_flags must include SK_ROW_MEMBER, plus SK_ROW_END in the last + * element (needed since row header does not include a count) + * sk_func points to the btree comparison support function for the + * opclass, NOT the operator's implementation function. + * sk_strategy must be the same in all elements of the subsidiary array, + * that is, the same as in the header entry. + * SK_SEARCHARRAY, SK_SEARCHNULL, SK_SEARCHNOTNULL cannot be used here. + */ + +/* + * ScanKeyData sk_flags + * + * sk_flags bits 0-15 are reserved for system-wide use (symbols for those + * bits should be defined here). Bits 16-31 are reserved for use within + * individual index access methods. + */ +#define SK_ISNULL 0x0001 /* sk_argument is NULL */ +#define SK_UNARY 0x0002 /* unary operator (not supported!) */ +#define SK_ROW_HEADER 0x0004 /* row comparison header (see above) */ +#define SK_ROW_MEMBER 0x0008 /* row comparison member (see above) */ +#define SK_ROW_END 0x0010 /* last row comparison member */ +#define SK_SEARCHARRAY 0x0020 /* scankey represents ScalarArrayOp */ +#define SK_SEARCHNULL 0x0040 /* scankey represents "col IS NULL" */ +#define SK_SEARCHNOTNULL 0x0080 /* scankey represents "col IS NOT NULL" */ +#define SK_ORDER_BY 0x0100 /* scankey is for ORDER BY op */ + + +/* + * prototypes for functions in access/common/scankey.c + */ +extern void ScanKeyInit(ScanKey entry, + AttrNumber attributeNumber, + StrategyNumber strategy, + RegProcedure procedure, + Datum argument); +extern void ScanKeyEntryInitialize(ScanKey entry, + int flags, + AttrNumber attributeNumber, + StrategyNumber strategy, + Oid subtype, + Oid collation, + RegProcedure procedure, + Datum argument); +extern void ScanKeyEntryInitializeWithInfo(ScanKey entry, + int flags, + AttrNumber attributeNumber, + StrategyNumber strategy, + Oid subtype, + Oid collation, + FmgrInfo *finfo, + Datum argument); + +#endif /* SKEY_H */ diff --git a/src/include/access/slru.h b/src/include/access/slru.h new file mode 100644 index 0000000..130c41c --- /dev/null +++ b/src/include/access/slru.h @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------- + * + * slru.h + * Simple LRU buffering for transaction status logfiles + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/slru.h + * + *------------------------------------------------------------------------- + */ +#ifndef SLRU_H +#define SLRU_H + +#include "access/xlogdefs.h" +#include "storage/lwlock.h" +#include "storage/sync.h" + + +/* + * Define SLRU segment size. A page is the same BLCKSZ as is used everywhere + * else in Postgres. The segment size can be chosen somewhat arbitrarily; + * we make it 32 pages by default, or 256Kb, i.e. 1M transactions for CLOG + * or 64K transactions for SUBTRANS. + * + * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF, + * page numbering also wraps around at 0xFFFFFFFF/xxxx_XACTS_PER_PAGE (where + * xxxx is CLOG or SUBTRANS, respectively), and segment numbering at + * 0xFFFFFFFF/xxxx_XACTS_PER_PAGE/SLRU_PAGES_PER_SEGMENT. We need + * take no explicit notice of that fact in slru.c, except when comparing + * segment and page numbers in SimpleLruTruncate (see PagePrecedes()). + */ +#define SLRU_PAGES_PER_SEGMENT 32 + +/* + * Page status codes. Note that these do not include the "dirty" bit. + * page_dirty can be true only in the VALID or WRITE_IN_PROGRESS states; + * in the latter case it implies that the page has been re-dirtied since + * the write started. + */ +typedef enum +{ + SLRU_PAGE_EMPTY, /* buffer is not in use */ + SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */ + SLRU_PAGE_VALID, /* page is valid and not being written */ + SLRU_PAGE_WRITE_IN_PROGRESS /* page is being written out */ +} SlruPageStatus; + +/* + * Shared-memory state + */ +typedef struct SlruSharedData +{ + LWLock *ControlLock; + + /* Number of buffers managed by this SLRU structure */ + int num_slots; + + /* + * Arrays holding info for each buffer slot. Page number is undefined + * when status is EMPTY, as is page_lru_count. + */ + char **page_buffer; + SlruPageStatus *page_status; + bool *page_dirty; + int *page_number; + int *page_lru_count; + LWLockPadded *buffer_locks; + + /* + * Optional array of WAL flush LSNs associated with entries in the SLRU + * pages. If not zero/NULL, we must flush WAL before writing pages (true + * for pg_xact, false for multixact, pg_subtrans, pg_notify). group_lsn[] + * has lsn_groups_per_page entries per buffer slot, each containing the + * highest LSN known for a contiguous group of SLRU entries on that slot's + * page. + */ + XLogRecPtr *group_lsn; + int lsn_groups_per_page; + + /*---------- + * We mark a page "most recently used" by setting + * page_lru_count[slotno] = ++cur_lru_count; + * The oldest page is therefore the one with the highest value of + * cur_lru_count - page_lru_count[slotno] + * The counts will eventually wrap around, but this calculation still + * works as long as no page's age exceeds INT_MAX counts. + *---------- + */ + int cur_lru_count; + + /* + * latest_page_number is the page number of the current end of the log; + * this is not critical data, since we use it only to avoid swapping out + * the latest page. + */ + int latest_page_number; + + /* SLRU's index for statistics purposes (might not be unique) */ + int slru_stats_idx; +} SlruSharedData; + +typedef SlruSharedData *SlruShared; + +/* + * SlruCtlData is an unshared structure that points to the active information + * in shared memory. + */ +typedef struct SlruCtlData +{ + SlruShared shared; + + /* + * Which sync handler function to use when handing sync requests over to + * the checkpointer. SYNC_HANDLER_NONE to disable fsync (eg pg_notify). + */ + SyncRequestHandler sync_handler; + + /* + * Decide whether a page is "older" for truncation and as a hint for + * evicting pages in LRU order. Return true if every entry of the first + * argument is older than every entry of the second argument. Note that + * !PagePrecedes(a,b) && !PagePrecedes(b,a) need not imply a==b; it also + * arises when some entries are older and some are not. For SLRUs using + * SimpleLruTruncate(), this must use modular arithmetic. (For others, + * the behavior of this callback has no functional implications.) Use + * SlruPagePrecedesUnitTests() in SLRUs meeting its criteria. + */ + bool (*PagePrecedes) (int, int); + + /* + * Dir is set during SimpleLruInit and does not change thereafter. Since + * it's always the same, it doesn't need to be in shared memory. + */ + char Dir[64]; +} SlruCtlData; + +typedef SlruCtlData *SlruCtl; + + +extern Size SimpleLruShmemSize(int nslots, int nlsns); +extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, + LWLock *ctllock, const char *subdir, int tranche_id, + SyncRequestHandler sync_handler); +extern int SimpleLruZeroPage(SlruCtl ctl, int pageno); +extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, + TransactionId xid); +extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, + TransactionId xid); +extern void SimpleLruWritePage(SlruCtl ctl, int slotno); +extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied); +#ifdef USE_ASSERT_CHECKING +extern void SlruPagePrecedesUnitTests(SlruCtl ctl, int per_page); +#else +#define SlruPagePrecedesUnitTests(ctl, per_page) do {} while (0) +#endif +extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage); +extern bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno); + +typedef bool (*SlruScanCallback) (SlruCtl ctl, char *filename, int segpage, + void *data); +extern bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data); +extern void SlruDeleteSegment(SlruCtl ctl, int segno); + +extern int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path); + +/* SlruScanDirectory public callbacks */ +extern bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename, + int segpage, void *data); +extern bool SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int segpage, + void *data); + +#endif /* SLRU_H */ diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h new file mode 100644 index 0000000..5ad4f85 --- /dev/null +++ b/src/include/access/spgist.h @@ -0,0 +1,229 @@ +/*------------------------------------------------------------------------- + * + * spgist.h + * Public header file for SP-GiST access method. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/spgist.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPGIST_H +#define SPGIST_H + +#include "access/amapi.h" +#include "access/xlogreader.h" +#include "lib/stringinfo.h" + + +/* SPGiST opclass support function numbers */ +#define SPGIST_CONFIG_PROC 1 +#define SPGIST_CHOOSE_PROC 2 +#define SPGIST_PICKSPLIT_PROC 3 +#define SPGIST_INNER_CONSISTENT_PROC 4 +#define SPGIST_LEAF_CONSISTENT_PROC 5 +#define SPGIST_COMPRESS_PROC 6 +#define SPGIST_OPTIONS_PROC 7 +#define SPGISTNRequiredProc 5 +#define SPGISTNProc 7 + +/* + * Argument structs for spg_config method + */ +typedef struct spgConfigIn +{ + Oid attType; /* Data type to be indexed */ +} spgConfigIn; + +typedef struct spgConfigOut +{ + Oid prefixType; /* Data type of inner-tuple prefixes */ + Oid labelType; /* Data type of inner-tuple node labels */ + Oid leafType; /* Data type of leaf-tuple values */ + bool canReturnData; /* Opclass can reconstruct original data */ + bool longValuesOK; /* Opclass can cope with values > 1 page */ +} spgConfigOut; + +/* + * Argument structs for spg_choose method + */ +typedef struct spgChooseIn +{ + Datum datum; /* original datum to be indexed */ + Datum leafDatum; /* current datum to be stored at leaf */ + int level; /* current level (counting from zero) */ + + /* Data from current inner tuple */ + bool allTheSame; /* tuple is marked all-the-same? */ + bool hasPrefix; /* tuple has a prefix? */ + Datum prefixDatum; /* if so, the prefix value */ + int nNodes; /* number of nodes in the inner tuple */ + Datum *nodeLabels; /* node label values (NULL if none) */ +} spgChooseIn; + +typedef enum spgChooseResultType +{ + spgMatchNode = 1, /* descend into existing node */ + spgAddNode, /* add a node to the inner tuple */ + spgSplitTuple /* split inner tuple (change its prefix) */ +} spgChooseResultType; + +typedef struct spgChooseOut +{ + spgChooseResultType resultType; /* action code, see above */ + union + { + struct /* results for spgMatchNode */ + { + int nodeN; /* descend to this node (index from 0) */ + int levelAdd; /* increment level by this much */ + Datum restDatum; /* new leaf datum */ + } matchNode; + struct /* results for spgAddNode */ + { + Datum nodeLabel; /* new node's label */ + int nodeN; /* where to insert it (index from 0) */ + } addNode; + struct /* results for spgSplitTuple */ + { + /* Info to form new upper-level inner tuple with one child tuple */ + bool prefixHasPrefix; /* tuple should have a prefix? */ + Datum prefixPrefixDatum; /* if so, its value */ + int prefixNNodes; /* number of nodes */ + Datum *prefixNodeLabels; /* their labels (or NULL for no + * labels) */ + int childNodeN; /* which node gets child tuple */ + + /* Info to form new lower-level inner tuple with all old nodes */ + bool postfixHasPrefix; /* tuple should have a prefix? */ + Datum postfixPrefixDatum; /* if so, its value */ + } splitTuple; + } result; +} spgChooseOut; + +/* + * Argument structs for spg_picksplit method + */ +typedef struct spgPickSplitIn +{ + int nTuples; /* number of leaf tuples */ + Datum *datums; /* their datums (array of length nTuples) */ + int level; /* current level (counting from zero) */ +} spgPickSplitIn; + +typedef struct spgPickSplitOut +{ + bool hasPrefix; /* new inner tuple should have a prefix? */ + Datum prefixDatum; /* if so, its value */ + + int nNodes; /* number of nodes for new inner tuple */ + Datum *nodeLabels; /* their labels (or NULL for no labels) */ + + int *mapTuplesToNodes; /* node index for each leaf tuple */ + Datum *leafTupleDatums; /* datum to store in each new leaf tuple */ +} spgPickSplitOut; + +/* + * Argument structs for spg_inner_consistent method + */ +typedef struct spgInnerConsistentIn +{ + ScanKey scankeys; /* array of operators and comparison values */ + ScanKey orderbys; /* array of ordering operators and comparison + * values */ + int nkeys; /* length of scankeys array */ + int norderbys; /* length of orderbys array */ + + Datum reconstructedValue; /* value reconstructed at parent */ + void *traversalValue; /* opclass-specific traverse value */ + MemoryContext traversalMemoryContext; /* put new traverse values here */ + int level; /* current level (counting from zero) */ + bool returnData; /* original data must be returned? */ + + /* Data from current inner tuple */ + bool allTheSame; /* tuple is marked all-the-same? */ + bool hasPrefix; /* tuple has a prefix? */ + Datum prefixDatum; /* if so, the prefix value */ + int nNodes; /* number of nodes in the inner tuple */ + Datum *nodeLabels; /* node label values (NULL if none) */ +} spgInnerConsistentIn; + +typedef struct spgInnerConsistentOut +{ + int nNodes; /* number of child nodes to be visited */ + int *nodeNumbers; /* their indexes in the node array */ + int *levelAdds; /* increment level by this much for each */ + Datum *reconstructedValues; /* associated reconstructed values */ + void **traversalValues; /* opclass-specific traverse values */ + double **distances; /* associated distances */ +} spgInnerConsistentOut; + +/* + * Argument structs for spg_leaf_consistent method + */ +typedef struct spgLeafConsistentIn +{ + ScanKey scankeys; /* array of operators and comparison values */ + ScanKey orderbys; /* array of ordering operators and comparison + * values */ + int nkeys; /* length of scankeys array */ + int norderbys; /* length of orderbys array */ + + Datum reconstructedValue; /* value reconstructed at parent */ + void *traversalValue; /* opclass-specific traverse value */ + int level; /* current level (counting from zero) */ + bool returnData; /* original data must be returned? */ + + Datum leafDatum; /* datum in leaf tuple */ +} spgLeafConsistentIn; + +typedef struct spgLeafConsistentOut +{ + Datum leafValue; /* reconstructed original data, if any */ + bool recheck; /* set true if operator must be rechecked */ + bool recheckDistances; /* set true if distances must be rechecked */ + double *distances; /* associated distances */ +} spgLeafConsistentOut; + + +/* spgutils.c */ +extern bytea *spgoptions(Datum reloptions, bool validate); + +/* spginsert.c */ +extern IndexBuildResult *spgbuild(Relation heap, Relation index, + struct IndexInfo *indexInfo); +extern void spgbuildempty(Relation index); +extern bool spginsert(Relation index, Datum *values, bool *isnull, + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + bool indexUnchanged, + struct IndexInfo *indexInfo); + +/* spgscan.c */ +extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz); +extern void spgendscan(IndexScanDesc scan); +extern void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, + ScanKey orderbys, int norderbys); +extern int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm); +extern bool spggettuple(IndexScanDesc scan, ScanDirection dir); +extern bool spgcanreturn(Relation index, int attno); + +/* spgvacuum.c */ +extern IndexBulkDeleteResult *spgbulkdelete(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats, + IndexBulkDeleteCallback callback, + void *callback_state); +extern IndexBulkDeleteResult *spgvacuumcleanup(IndexVacuumInfo *info, + IndexBulkDeleteResult *stats); + +/* spgvalidate.c */ +extern bool spgvalidate(Oid opclassoid); +extern void spgadjustmembers(Oid opfamilyoid, + Oid opclassoid, + List *operators, + List *functions); + +#endif /* SPGIST_H */ diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h new file mode 100644 index 0000000..eb56b1c --- /dev/null +++ b/src/include/access/spgist_private.h @@ -0,0 +1,548 @@ +/*------------------------------------------------------------------------- + * + * spgist_private.h + * Private declarations for SP-GiST access method. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/spgist_private.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPGIST_PRIVATE_H +#define SPGIST_PRIVATE_H + +#include "access/itup.h" +#include "access/spgist.h" +#include "catalog/pg_am_d.h" +#include "nodes/tidbitmap.h" +#include "storage/buf.h" +#include "utils/geo_decls.h" +#include "utils/relcache.h" + + +typedef struct SpGistOptions +{ + int32 varlena_header_; /* varlena header (do not touch directly!) */ + int fillfactor; /* page fill factor in percent (0..100) */ +} SpGistOptions; + +#define SpGistGetFillFactor(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \ + relation->rd_rel->relam == SPGIST_AM_OID), \ + (relation)->rd_options ? \ + ((SpGistOptions *) (relation)->rd_options)->fillfactor : \ + SPGIST_DEFAULT_FILLFACTOR) +#define SpGistGetTargetPageFreeSpace(relation) \ + (BLCKSZ * (100 - SpGistGetFillFactor(relation)) / 100) + + +/* SPGiST leaf tuples have one key column, optionally have included columns */ +#define spgKeyColumn 0 +#define spgFirstIncludeColumn 1 + +/* Page numbers of fixed-location pages */ +#define SPGIST_METAPAGE_BLKNO (0) /* metapage */ +#define SPGIST_ROOT_BLKNO (1) /* root for normal entries */ +#define SPGIST_NULL_BLKNO (2) /* root for null-value entries */ +#define SPGIST_LAST_FIXED_BLKNO SPGIST_NULL_BLKNO + +#define SpGistBlockIsRoot(blkno) \ + ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO) +#define SpGistBlockIsFixed(blkno) \ + ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO) + +/* + * Contents of page special space on SPGiST index pages + */ +typedef struct SpGistPageOpaqueData +{ + uint16 flags; /* see bit definitions below */ + uint16 nRedirection; /* number of redirection tuples on page */ + uint16 nPlaceholder; /* number of placeholder tuples on page */ + /* note there's no count of either LIVE or DEAD tuples ... */ + uint16 spgist_page_id; /* for identification of SP-GiST indexes */ +} SpGistPageOpaqueData; + +typedef SpGistPageOpaqueData *SpGistPageOpaque; + +/* Flag bits in page special space */ +#define SPGIST_META (1<<0) +#define SPGIST_DELETED (1<<1) /* never set, but keep for backwards + * compatibility */ +#define SPGIST_LEAF (1<<2) +#define SPGIST_NULLS (1<<3) + +#define SpGistPageGetOpaque(page) ((SpGistPageOpaque) PageGetSpecialPointer(page)) +#define SpGistPageIsMeta(page) (SpGistPageGetOpaque(page)->flags & SPGIST_META) +#define SpGistPageIsDeleted(page) (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED) +#define SpGistPageIsLeaf(page) (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF) +#define SpGistPageStoresNulls(page) (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS) + +/* + * The page ID is for the convenience of pg_filedump and similar utilities, + * which otherwise would have a hard time telling pages of different index + * types apart. It should be the last 2 bytes on the page. This is more or + * less "free" due to alignment considerations. + * + * See comments above GinPageOpaqueData. + */ +#define SPGIST_PAGE_ID 0xFF82 + +/* + * Each backend keeps a cache of last-used page info in its index->rd_amcache + * area. This is initialized from, and occasionally written back to, + * shared storage in the index metapage. + */ +typedef struct SpGistLastUsedPage +{ + BlockNumber blkno; /* block number, or InvalidBlockNumber */ + int freeSpace; /* page's free space (could be obsolete!) */ +} SpGistLastUsedPage; + +/* Note: indexes in cachedPage[] match flag assignments for SpGistGetBuffer */ +#define SPGIST_CACHED_PAGES 8 + +typedef struct SpGistLUPCache +{ + SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]; +} SpGistLUPCache; + +/* + * metapage + */ +typedef struct SpGistMetaPageData +{ + uint32 magicNumber; /* for identity cross-check */ + SpGistLUPCache lastUsedPages; /* shared storage of last-used info */ +} SpGistMetaPageData; + +#define SPGIST_MAGIC_NUMBER (0xBA0BABEE) + +#define SpGistPageGetMeta(p) \ + ((SpGistMetaPageData *) PageGetContents(p)) + +/* + * Private state of index AM. SpGistState is common to both insert and + * search code; SpGistScanOpaque is for searches only. + */ + +typedef struct SpGistLeafTupleData *SpGistLeafTuple; /* forward reference */ + +/* Per-datatype info needed in SpGistState */ +typedef struct SpGistTypeDesc +{ + Oid type; + int16 attlen; + bool attbyval; + char attalign; + char attstorage; +} SpGistTypeDesc; + +typedef struct SpGistState +{ + Relation index; /* index we're working with */ + + spgConfigOut config; /* filled in by opclass config method */ + + SpGistTypeDesc attType; /* type of values to be indexed/restored */ + SpGistTypeDesc attLeafType; /* type of leaf-tuple values */ + SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */ + SpGistTypeDesc attLabelType; /* type of node label values */ + + /* leafTupDesc typically points to index's tupdesc, but not always */ + TupleDesc leafTupDesc; /* descriptor for leaf-level tuples */ + + char *deadTupleStorage; /* workspace for spgFormDeadTuple */ + + TransactionId myXid; /* XID to use when creating a redirect tuple */ + bool isBuild; /* true if doing index build */ +} SpGistState; + +/* Item to be re-examined later during a search */ +typedef struct SpGistSearchItem +{ + pairingheap_node phNode; /* pairing heap node */ + Datum value; /* value reconstructed from parent, or + * leafValue if isLeaf */ + SpGistLeafTuple leafTuple; /* whole leaf tuple, if needed */ + void *traversalValue; /* opclass-specific traverse value */ + int level; /* level of items on this page */ + ItemPointerData heapPtr; /* heap info, if heap tuple */ + bool isNull; /* SearchItem is NULL item */ + bool isLeaf; /* SearchItem is heap item */ + bool recheck; /* qual recheck is needed */ + bool recheckDistances; /* distance recheck is needed */ + + /* array with numberOfOrderBys entries */ + double distances[FLEXIBLE_ARRAY_MEMBER]; +} SpGistSearchItem; + +#define SizeOfSpGistSearchItem(n_distances) \ + (offsetof(SpGistSearchItem, distances) + sizeof(double) * (n_distances)) + +/* + * Private state of an index scan + */ +typedef struct SpGistScanOpaqueData +{ + SpGistState state; /* see above */ + pairingheap *scanQueue; /* queue of to be visited items */ + MemoryContext tempCxt; /* short-lived memory context */ + MemoryContext traversalCxt; /* single scan lifetime memory context */ + + /* Control flags showing whether to search nulls and/or non-nulls */ + bool searchNulls; /* scan matches (all) null entries */ + bool searchNonNulls; /* scan matches (some) non-null entries */ + + /* Index quals to be passed to opclass (null-related quals removed) */ + int numberOfKeys; /* number of index qualifier conditions */ + ScanKey keyData; /* array of index qualifier descriptors */ + int numberOfOrderBys; /* number of ordering operators */ + int numberOfNonNullOrderBys; /* number of ordering operators + * with non-NULL arguments */ + ScanKey orderByData; /* array of ordering op descriptors */ + Oid *orderByTypes; /* array of ordering op return types */ + int *nonNullOrderByOffsets; /* array of offset of non-NULL + * ordering keys in the original array */ + Oid indexCollation; /* collation of index column */ + + /* Opclass defined functions: */ + FmgrInfo innerConsistentFn; + FmgrInfo leafConsistentFn; + + /* Pre-allocated workspace arrays: */ + double *zeroDistances; + double *infDistances; + + /* These fields are only used in amgetbitmap scans: */ + TIDBitmap *tbm; /* bitmap being filled */ + int64 ntids; /* number of TIDs passed to bitmap */ + + /* These fields are only used in amgettuple scans: */ + bool want_itup; /* are we reconstructing tuples? */ + TupleDesc reconTupDesc; /* if so, descriptor for reconstructed tuples */ + int nPtrs; /* number of TIDs found on current page */ + int iPtr; /* index for scanning through same */ + ItemPointerData heapPtrs[MaxIndexTuplesPerPage]; /* TIDs from cur page */ + bool recheck[MaxIndexTuplesPerPage]; /* their recheck flags */ + bool recheckDistances[MaxIndexTuplesPerPage]; /* distance recheck + * flags */ + HeapTuple reconTups[MaxIndexTuplesPerPage]; /* reconstructed tuples */ + + /* distances (for recheck) */ + IndexOrderByDistance *distances[MaxIndexTuplesPerPage]; + + /* + * Note: using MaxIndexTuplesPerPage above is a bit hokey since + * SpGistLeafTuples aren't exactly IndexTuples; however, they are larger, + * so this is safe. + */ +} SpGistScanOpaqueData; + +typedef SpGistScanOpaqueData *SpGistScanOpaque; + +/* + * This struct is what we actually keep in index->rd_amcache. It includes + * static configuration information as well as the lastUsedPages cache. + */ +typedef struct SpGistCache +{ + spgConfigOut config; /* filled in by opclass config method */ + + SpGistTypeDesc attType; /* type of values to be indexed/restored */ + SpGistTypeDesc attLeafType; /* type of leaf-tuple values */ + SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */ + SpGistTypeDesc attLabelType; /* type of node label values */ + + SpGistLUPCache lastUsedPages; /* local storage of last-used info */ +} SpGistCache; + + +/* + * SPGiST tuple types. Note: inner, leaf, and dead tuple structs + * must have the same tupstate field in the same position! Real inner and + * leaf tuples always have tupstate = LIVE; if the state is something else, + * use the SpGistDeadTuple struct to inspect the tuple. + */ + +/* values of tupstate (see README for more info) */ +#define SPGIST_LIVE 0 /* normal live tuple (either inner or leaf) */ +#define SPGIST_REDIRECT 1 /* temporary redirection placeholder */ +#define SPGIST_DEAD 2 /* dead, cannot be removed because of links */ +#define SPGIST_PLACEHOLDER 3 /* placeholder, used to preserve offsets */ + +/* + * SPGiST inner tuple: list of "nodes" that subdivide a set of tuples + * + * Inner tuple layout: + * header/optional prefix/array of nodes, which are SpGistNodeTuples + * + * size and prefixSize must be multiples of MAXALIGN + * + * If the prefix datum is of a pass-by-value type, it is stored in its + * Datum representation, that is its on-disk representation is of length + * sizeof(Datum). This is a fairly unfortunate choice, because in no other + * place does Postgres use Datum as an on-disk representation; it creates + * an unnecessary incompatibility between 32-bit and 64-bit builds. But the + * compatibility loss is mostly theoretical since MAXIMUM_ALIGNOF typically + * differs between such builds, too. Anyway we're stuck with it now. + */ +typedef struct SpGistInnerTupleData +{ + unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ + allTheSame:1, /* all nodes in tuple are equivalent */ + nNodes:13, /* number of nodes within inner tuple */ + prefixSize:16; /* size of prefix, or 0 if none */ + uint16 size; /* total size of inner tuple */ + /* On most machines there will be a couple of wasted bytes here */ + /* prefix datum follows, then nodes */ +} SpGistInnerTupleData; + +typedef SpGistInnerTupleData *SpGistInnerTuple; + +/* these must match largest values that fit in bit fields declared above */ +#define SGITMAXNNODES 0x1FFF +#define SGITMAXPREFIXSIZE 0xFFFF +#define SGITMAXSIZE 0xFFFF + +#define SGITHDRSZ MAXALIGN(sizeof(SpGistInnerTupleData)) +#define _SGITDATA(x) (((char *) (x)) + SGITHDRSZ) +#define SGITDATAPTR(x) ((x)->prefixSize ? _SGITDATA(x) : NULL) +#define SGITDATUM(x, s) ((x)->prefixSize ? \ + ((s)->attPrefixType.attbyval ? \ + *(Datum *) _SGITDATA(x) : \ + PointerGetDatum(_SGITDATA(x))) \ + : (Datum) 0) +#define SGITNODEPTR(x) ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize)) + +/* Macro for iterating through the nodes of an inner tuple */ +#define SGITITERATE(x, i, nt) \ + for ((i) = 0, (nt) = SGITNODEPTR(x); \ + (i) < (x)->nNodes; \ + (i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt))) + +/* + * SPGiST node tuple: one node within an inner tuple + * + * Node tuples use the same header as ordinary Postgres IndexTuples, but + * we do not use a null bitmap, because we know there is only one column + * so the INDEX_NULL_MASK bit suffices. Also, pass-by-value datums are + * stored in Datum form, the same convention as for inner tuple prefixes. + */ + +typedef IndexTupleData SpGistNodeTupleData; + +typedef SpGistNodeTupleData *SpGistNodeTuple; + +#define SGNTHDRSZ MAXALIGN(sizeof(SpGistNodeTupleData)) +#define SGNTDATAPTR(x) (((char *) (x)) + SGNTHDRSZ) +#define SGNTDATUM(x, s) ((s)->attLabelType.attbyval ? \ + *(Datum *) SGNTDATAPTR(x) : \ + PointerGetDatum(SGNTDATAPTR(x))) + +/* + * SPGiST leaf tuple: carries a leaf datum and a heap tuple TID, + * and optionally some "included" columns. + * + * In the simplest case, the leaf datum is the same as the indexed value; + * but it could also be a suffix or some other sort of delta that permits + * reconstruction given knowledge of the prefix path traversed to get here. + * Any included columns are stored without modification. + * + * A nulls bitmap is present if there are included columns AND any of the + * datums are NULL. We do not need a nulls bitmap for the case of a null + * leaf datum without included columns, as we can infer whether the leaf + * datum is null from whether the tuple is stored on a nulls page. (This + * provision is mostly for backwards compatibility, but it does save space + * on 32-bit machines.) As with other PG index tuple designs, if the nulls + * bitmap exists then it's of size INDEX_MAX_KEYS bits regardless of the + * actual number of attributes. For the usual choice of INDEX_MAX_KEYS, + * this costs nothing because of alignment considerations. + * + * The size field is wider than could possibly be needed for an on-disk leaf + * tuple, but this allows us to form leaf tuples even when the datum is too + * wide to be stored immediately, and it costs nothing because of alignment + * considerations. + * + * t_info holds the nextOffset field (14 bits wide, enough for supported + * page sizes) plus the has-nulls-bitmap flag bit; another flag bit is free. + * + * Normally, nextOffset links to the next tuple belonging to the same parent + * node (which must be on the same page), or it's 0 if there is no next tuple. + * But when the root page is a leaf page, we don't chain its tuples, + * so nextOffset is always 0 on the root. + * + * size must be a multiple of MAXALIGN; also, it must be at least SGDTSIZE + * so that the tuple can be converted to REDIRECT status later. (This + * restriction only adds bytes for a NULL leaf datum stored on a 32-bit + * machine; otherwise alignment restrictions force it anyway.) + */ +typedef struct SpGistLeafTupleData +{ + unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ + size:30; /* large enough for any palloc'able value */ + uint16 t_info; /* nextOffset, which links to the next tuple + * in chain, plus two flag bits */ + ItemPointerData heapPtr; /* TID of represented heap tuple */ + /* nulls bitmap follows if the flag bit for it is set */ + /* leaf datum, then any included datums, follows on a MAXALIGN boundary */ +} SpGistLeafTupleData; + +/* Macros to access nextOffset and bit fields inside t_info */ +#define SGLT_GET_NEXTOFFSET(spgLeafTuple) \ + ((spgLeafTuple)->t_info & 0x3FFF) +#define SGLT_GET_HASNULLMASK(spgLeafTuple) \ + (((spgLeafTuple)->t_info & 0x8000) ? true : false) +#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber) \ + ((spgLeafTuple)->t_info = \ + ((spgLeafTuple)->t_info & 0xC000) | ((offsetNumber) & 0x3FFF)) +#define SGLT_SET_HASNULLMASK(spgLeafTuple, hasnulls) \ + ((spgLeafTuple)->t_info = \ + ((spgLeafTuple)->t_info & 0x7FFF) | ((hasnulls) ? 0x8000 : 0)) + +#define SGLTHDRSZ(hasnulls) \ + ((hasnulls) ? MAXALIGN(sizeof(SpGistLeafTupleData) + \ + sizeof(IndexAttributeBitMapData)) : \ + MAXALIGN(sizeof(SpGistLeafTupleData))) +#define SGLTDATAPTR(x) (((char *) (x)) + SGLTHDRSZ(SGLT_GET_HASNULLMASK(x))) +#define SGLTDATUM(x, s) fetch_att(SGLTDATAPTR(x), \ + (s)->attLeafType.attbyval, \ + (s)->attLeafType.attlen) + +/* + * SPGiST dead tuple: declaration for examining non-live tuples + * + * The tupstate field of this struct must match those of regular inner and + * leaf tuples, and its size field must match a leaf tuple's. + * Also, the pointer field must be in the same place as a leaf tuple's heapPtr + * field, to satisfy some Asserts that we make when replacing a leaf tuple + * with a dead tuple. + * We don't use t_info, but it's needed to align the pointer field. + * pointer and xid are only valid when tupstate = REDIRECT. + */ +typedef struct SpGistDeadTupleData +{ + unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ + size:30; + uint16 t_info; /* not used in dead tuples */ + ItemPointerData pointer; /* redirection inside index */ + TransactionId xid; /* ID of xact that inserted this tuple */ +} SpGistDeadTupleData; + +typedef SpGistDeadTupleData *SpGistDeadTuple; + +#define SGDTSIZE MAXALIGN(sizeof(SpGistDeadTupleData)) + +/* + * Macros for doing free-space calculations. Note that when adding up the + * space needed for tuples, we always consider each tuple to need the tuple's + * size plus sizeof(ItemIdData) (for the line pointer). This works correctly + * so long as tuple sizes are always maxaligned. + */ + +/* Page capacity after allowing for fixed header and special space */ +#define SPGIST_PAGE_CAPACITY \ + MAXALIGN_DOWN(BLCKSZ - \ + SizeOfPageHeaderData - \ + MAXALIGN(sizeof(SpGistPageOpaqueData))) + +/* + * Compute free space on page, assuming that up to n placeholders can be + * recycled if present (n should be the number of tuples to be inserted) + */ +#define SpGistPageGetFreeSpace(p, n) \ + (PageGetExactFreeSpace(p) + \ + Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \ + (SGDTSIZE + sizeof(ItemIdData))) + +/* + * XLOG stuff + */ + +#define STORE_STATE(s, d) \ + do { \ + (d).myXid = (s)->myXid; \ + (d).isBuild = (s)->isBuild; \ + } while(0) + +/* + * The "flags" argument for SpGistGetBuffer should be either GBUF_LEAF to + * get a leaf page, or GBUF_INNER_PARITY(blockNumber) to get an inner + * page in the same triple-parity group as the specified block number. + * (Typically, this should be GBUF_INNER_PARITY(parentBlockNumber + 1) + * to follow the rule described in spgist/README.) + * In addition, GBUF_NULLS can be OR'd in to get a page for storage of + * null-valued tuples. + * + * Note: these flag values are used as indexes into lastUsedPages. + */ +#define GBUF_LEAF 0x03 +#define GBUF_INNER_PARITY(x) ((x) % 3) +#define GBUF_NULLS 0x04 + +#define GBUF_PARITY_MASK 0x03 +#define GBUF_REQ_LEAF(flags) (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF) +#define GBUF_REQ_NULLS(flags) ((flags) & GBUF_NULLS) + +/* spgutils.c */ + +/* reloption parameters */ +#define SPGIST_MIN_FILLFACTOR 10 +#define SPGIST_DEFAULT_FILLFACTOR 80 + +extern SpGistCache *spgGetCache(Relation index); +extern TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType); +extern void initSpGistState(SpGistState *state, Relation index); +extern Buffer SpGistNewBuffer(Relation index); +extern void SpGistUpdateMetaPage(Relation index); +extern Buffer SpGistGetBuffer(Relation index, int flags, + int needSpace, bool *isNew); +extern void SpGistSetLastUsedPage(Relation index, Buffer buffer); +extern void SpGistInitPage(Page page, uint16 f); +extern void SpGistInitBuffer(Buffer b, uint16 f); +extern void SpGistInitMetapage(Page page); +extern unsigned int SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum); +extern Size SpGistGetLeafTupleSize(TupleDesc tupleDescriptor, + Datum *datums, bool *isnulls); +extern SpGistLeafTuple spgFormLeafTuple(SpGistState *state, + ItemPointer heapPtr, + Datum *datums, bool *isnulls); +extern SpGistNodeTuple spgFormNodeTuple(SpGistState *state, + Datum label, bool isnull); +extern SpGistInnerTuple spgFormInnerTuple(SpGistState *state, + bool hasPrefix, Datum prefix, + int nNodes, SpGistNodeTuple *nodes); +extern SpGistDeadTuple spgFormDeadTuple(SpGistState *state, int tupstate, + BlockNumber blkno, OffsetNumber offnum); +extern void spgDeformLeafTuple(SpGistLeafTuple tup, TupleDesc tupleDescriptor, + Datum *datums, bool *isnulls, + bool keyColumnIsNull); +extern Datum *spgExtractNodeLabels(SpGistState *state, + SpGistInnerTuple innerTuple); +extern OffsetNumber SpGistPageAddNewItem(SpGistState *state, Page page, + Item item, Size size, + OffsetNumber *startOffset, + bool errorOK); +extern bool spgproperty(Oid index_oid, int attno, + IndexAMProperty prop, const char *propname, + bool *res, bool *isnull); + +/* spgdoinsert.c */ +extern void spgUpdateNodeLink(SpGistInnerTuple tup, int nodeN, + BlockNumber blkno, OffsetNumber offset); +extern void spgPageIndexMultiDelete(SpGistState *state, Page page, + OffsetNumber *itemnos, int nitems, + int firststate, int reststate, + BlockNumber blkno, OffsetNumber offnum); +extern bool spgdoinsert(Relation index, SpGistState *state, + ItemPointer heapPtr, Datum *datums, bool *isnulls); + +/* spgproc.c */ +extern double *spg_key_orderbys_distances(Datum key, bool isLeaf, + ScanKey orderbys, int norderbys); +extern BOX *box_copy(BOX *orig); + +#endif /* SPGIST_PRIVATE_H */ diff --git a/src/include/access/spgxlog.h b/src/include/access/spgxlog.h new file mode 100644 index 0000000..930ffdd --- /dev/null +++ b/src/include/access/spgxlog.h @@ -0,0 +1,257 @@ +/*------------------------------------------------------------------------- + * + * spgxlog.h + * xlog declarations for SP-GiST access method. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/spgxlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPGXLOG_H +#define SPGXLOG_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/off.h" + +/* XLOG record types for SPGiST */ + /* #define XLOG_SPGIST_CREATE_INDEX 0x00 */ /* not used anymore */ +#define XLOG_SPGIST_ADD_LEAF 0x10 +#define XLOG_SPGIST_MOVE_LEAFS 0x20 +#define XLOG_SPGIST_ADD_NODE 0x30 +#define XLOG_SPGIST_SPLIT_TUPLE 0x40 +#define XLOG_SPGIST_PICKSPLIT 0x50 +#define XLOG_SPGIST_VACUUM_LEAF 0x60 +#define XLOG_SPGIST_VACUUM_ROOT 0x70 +#define XLOG_SPGIST_VACUUM_REDIRECT 0x80 + +/* + * Some redo functions need an SpGistState, although only a few of its fields + * need to be valid. spgxlogState carries the required info in xlog records. + * (See fillFakeState in spgxlog.c for more comments.) + */ +typedef struct spgxlogState +{ + TransactionId myXid; + bool isBuild; +} spgxlogState; + +/* + * Backup Blk 0: destination page for leaf tuple + * Backup Blk 1: parent page (if any) + */ +typedef struct spgxlogAddLeaf +{ + bool newPage; /* init dest page? */ + bool storesNulls; /* page is in the nulls tree? */ + OffsetNumber offnumLeaf; /* offset where leaf tuple gets placed */ + OffsetNumber offnumHeadLeaf; /* offset of head tuple in chain, if any */ + + OffsetNumber offnumParent; /* where the parent downlink is, if any */ + uint16 nodeI; + + /* new leaf tuple follows (unaligned!) */ +} spgxlogAddLeaf; + +/* + * Backup Blk 0: source leaf page + * Backup Blk 1: destination leaf page + * Backup Blk 2: parent page + */ +typedef struct spgxlogMoveLeafs +{ + uint16 nMoves; /* number of tuples moved from source page */ + bool newPage; /* init dest page? */ + bool replaceDead; /* are we replacing a DEAD source tuple? */ + bool storesNulls; /* pages are in the nulls tree? */ + + /* where the parent downlink is */ + OffsetNumber offnumParent; + uint16 nodeI; + + spgxlogState stateSrc; + + /*---------- + * data follows: + * array of deleted tuple numbers, length nMoves + * array of inserted tuple numbers, length nMoves + 1 or 1 + * list of leaf tuples, length nMoves + 1 or 1 (unaligned!) + * + * Note: if replaceDead is true then there is only one inserted tuple + * number and only one leaf tuple in the data, because we are not copying + * the dead tuple from the source + *---------- + */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} spgxlogMoveLeafs; + +#define SizeOfSpgxlogMoveLeafs offsetof(spgxlogMoveLeafs, offsets) + +/* + * Backup Blk 0: original page + * Backup Blk 1: where new tuple goes, if not same place + * Backup Blk 2: where parent downlink is, if updated and different from + * the old and new + */ +typedef struct spgxlogAddNode +{ + /* + * Offset of the original inner tuple, in the original page (on backup + * block 0). + */ + OffsetNumber offnum; + + /* + * Offset of the new tuple, on the new page (on backup block 1). Invalid, + * if we overwrote the old tuple in the original page). + */ + OffsetNumber offnumNew; + bool newPage; /* init new page? */ + + /*---- + * Where is the parent downlink? parentBlk indicates which page it's on, + * and offnumParent is the offset within the page. The possible values for + * parentBlk are: + * + * 0: parent == original page + * 1: parent == new page + * 2: parent == different page (blk ref 2) + * -1: parent not updated + *---- + */ + int8 parentBlk; + OffsetNumber offnumParent; /* offset within the parent page */ + + uint16 nodeI; + + spgxlogState stateSrc; + + /* + * updated inner tuple follows (unaligned!) + */ +} spgxlogAddNode; + +/* + * Backup Blk 0: where the prefix tuple goes + * Backup Blk 1: where the postfix tuple goes (if different page) + */ +typedef struct spgxlogSplitTuple +{ + /* where the prefix tuple goes */ + OffsetNumber offnumPrefix; + + /* where the postfix tuple goes */ + OffsetNumber offnumPostfix; + bool newPage; /* need to init that page? */ + bool postfixBlkSame; /* was postfix tuple put on same page as + * prefix? */ + + /* + * new prefix inner tuple follows, then new postfix inner tuple (both are + * unaligned!) + */ +} spgxlogSplitTuple; + +/* + * Buffer references in the rdata array are: + * Backup Blk 0: Src page (only if not root) + * Backup Blk 1: Dest page (if used) + * Backup Blk 2: Inner page + * Backup Blk 3: Parent page (if any, and different from Inner) + */ +typedef struct spgxlogPickSplit +{ + bool isRootSplit; + + uint16 nDelete; /* n to delete from Src */ + uint16 nInsert; /* n to insert on Src and/or Dest */ + bool initSrc; /* re-init the Src page? */ + bool initDest; /* re-init the Dest page? */ + + /* where to put new inner tuple */ + OffsetNumber offnumInner; + bool initInner; /* re-init the Inner page? */ + + bool storesNulls; /* pages are in the nulls tree? */ + + /* where the parent downlink is, if any */ + bool innerIsParent; /* is parent the same as inner page? */ + OffsetNumber offnumParent; + uint16 nodeI; + + spgxlogState stateSrc; + + /*---------- + * data follows: + * array of deleted tuple numbers, length nDelete + * array of inserted tuple numbers, length nInsert + * array of page selector bytes for inserted tuples, length nInsert + * new inner tuple (unaligned!) + * list of leaf tuples, length nInsert (unaligned!) + *---------- + */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} spgxlogPickSplit; + +#define SizeOfSpgxlogPickSplit offsetof(spgxlogPickSplit, offsets) + +typedef struct spgxlogVacuumLeaf +{ + uint16 nDead; /* number of tuples to become DEAD */ + uint16 nPlaceholder; /* number of tuples to become PLACEHOLDER */ + uint16 nMove; /* number of tuples to move */ + uint16 nChain; /* number of tuples to re-chain */ + + spgxlogState stateSrc; + + /*---------- + * data follows: + * tuple numbers to become DEAD + * tuple numbers to become PLACEHOLDER + * tuple numbers to move from (and replace with PLACEHOLDER) + * tuple numbers to move to (replacing what is there) + * tuple numbers to update nextOffset links of + * tuple numbers to insert in nextOffset links + *---------- + */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} spgxlogVacuumLeaf; + +#define SizeOfSpgxlogVacuumLeaf offsetof(spgxlogVacuumLeaf, offsets) + +typedef struct spgxlogVacuumRoot +{ + /* vacuum a root page when it is also a leaf */ + uint16 nDelete; /* number of tuples to delete */ + + spgxlogState stateSrc; + + /* offsets of tuples to delete follow */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} spgxlogVacuumRoot; + +#define SizeOfSpgxlogVacuumRoot offsetof(spgxlogVacuumRoot, offsets) + +typedef struct spgxlogVacuumRedirect +{ + uint16 nToPlaceholder; /* number of redirects to make placeholders */ + OffsetNumber firstPlaceholder; /* first placeholder tuple to remove */ + TransactionId newestRedirectXid; /* newest XID of removed redirects */ + + /* offsets of redirect tuples to make placeholders follow */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} spgxlogVacuumRedirect; + +#define SizeOfSpgxlogVacuumRedirect offsetof(spgxlogVacuumRedirect, offsets) + +extern void spg_redo(XLogReaderState *record); +extern void spg_desc(StringInfo buf, XLogReaderState *record); +extern const char *spg_identify(uint8 info); +extern void spg_xlog_startup(void); +extern void spg_xlog_cleanup(void); +extern void spg_mask(char *pagedata, BlockNumber blkno); + +#endif /* SPGXLOG_H */ diff --git a/src/include/access/stratnum.h b/src/include/access/stratnum.h new file mode 100644 index 0000000..ac15f84 --- /dev/null +++ b/src/include/access/stratnum.h @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------- + * + * stratnum.h + * POSTGRES strategy number definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/stratnum.h + * + *------------------------------------------------------------------------- + */ +#ifndef STRATNUM_H +#define STRATNUM_H + +/* + * Strategy numbers identify the semantics that particular operators have + * with respect to particular operator classes. In some cases a strategy + * subtype (an OID) is used as further information. + */ +typedef uint16 StrategyNumber; + +#define InvalidStrategy ((StrategyNumber) 0) + +/* + * Strategy numbers for B-tree indexes. + */ +#define BTLessStrategyNumber 1 +#define BTLessEqualStrategyNumber 2 +#define BTEqualStrategyNumber 3 +#define BTGreaterEqualStrategyNumber 4 +#define BTGreaterStrategyNumber 5 + +#define BTMaxStrategyNumber 5 + +/* + * Strategy numbers for hash indexes. There's only one valid strategy for + * hashing: equality. + */ +#define HTEqualStrategyNumber 1 + +#define HTMaxStrategyNumber 1 + +/* + * Strategy numbers common to (some) GiST, SP-GiST and BRIN opclasses. + * + * The first few of these come from the R-Tree indexing method (hence the + * names); the others have been added over time as they have been needed. + */ +#define RTLeftStrategyNumber 1 /* for << */ +#define RTOverLeftStrategyNumber 2 /* for &< */ +#define RTOverlapStrategyNumber 3 /* for && */ +#define RTOverRightStrategyNumber 4 /* for &> */ +#define RTRightStrategyNumber 5 /* for >> */ +#define RTSameStrategyNumber 6 /* for ~= */ +#define RTContainsStrategyNumber 7 /* for @> */ +#define RTContainedByStrategyNumber 8 /* for <@ */ +#define RTOverBelowStrategyNumber 9 /* for &<| */ +#define RTBelowStrategyNumber 10 /* for <<| */ +#define RTAboveStrategyNumber 11 /* for |>> */ +#define RTOverAboveStrategyNumber 12 /* for |&> */ +#define RTOldContainsStrategyNumber 13 /* for old spelling of @> */ +#define RTOldContainedByStrategyNumber 14 /* for old spelling of <@ */ +#define RTKNNSearchStrategyNumber 15 /* for <-> (distance) */ +#define RTContainsElemStrategyNumber 16 /* for range types @> elem */ +#define RTAdjacentStrategyNumber 17 /* for -|- */ +#define RTEqualStrategyNumber 18 /* for = */ +#define RTNotEqualStrategyNumber 19 /* for != */ +#define RTLessStrategyNumber 20 /* for < */ +#define RTLessEqualStrategyNumber 21 /* for <= */ +#define RTGreaterStrategyNumber 22 /* for > */ +#define RTGreaterEqualStrategyNumber 23 /* for >= */ +#define RTSubStrategyNumber 24 /* for inet >> */ +#define RTSubEqualStrategyNumber 25 /* for inet <<= */ +#define RTSuperStrategyNumber 26 /* for inet << */ +#define RTSuperEqualStrategyNumber 27 /* for inet >>= */ +#define RTPrefixStrategyNumber 28 /* for text ^@ */ +#define RTOldBelowStrategyNumber 29 /* for old spelling of <<| */ +#define RTOldAboveStrategyNumber 30 /* for old spelling of |>> */ + +#define RTMaxStrategyNumber 30 + + +#endif /* STRATNUM_H */ diff --git a/src/include/access/subtrans.h b/src/include/access/subtrans.h new file mode 100644 index 0000000..f94e116 --- /dev/null +++ b/src/include/access/subtrans.h @@ -0,0 +1,29 @@ +/* + * subtrans.h + * + * PostgreSQL subtransaction-log manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/subtrans.h + */ +#ifndef SUBTRANS_H +#define SUBTRANS_H + +/* Number of SLRU buffers to use for subtrans */ +#define NUM_SUBTRANS_BUFFERS 32 + +extern void SubTransSetParent(TransactionId xid, TransactionId parent); +extern TransactionId SubTransGetParent(TransactionId xid); +extern TransactionId SubTransGetTopmostTransaction(TransactionId xid); + +extern Size SUBTRANSShmemSize(void); +extern void SUBTRANSShmemInit(void); +extern void BootStrapSUBTRANS(void); +extern void StartupSUBTRANS(TransactionId oldestActiveXID); +extern void CheckPointSUBTRANS(void); +extern void ExtendSUBTRANS(TransactionId newestXact); +extern void TruncateSUBTRANS(TransactionId oldestXact); + +#endif /* SUBTRANS_H */ diff --git a/src/include/access/syncscan.h b/src/include/access/syncscan.h new file mode 100644 index 0000000..a3f0e48 --- /dev/null +++ b/src/include/access/syncscan.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * syncscan.h + * POSTGRES synchronous scan support functions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/syncscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef SYNCSCAN_H +#define SYNCSCAN_H + +#include "storage/block.h" +#include "utils/relcache.h" + +extern void ss_report_location(Relation rel, BlockNumber location); +extern BlockNumber ss_get_location(Relation rel, BlockNumber relnblocks); +extern void SyncScanShmemInit(void); +extern Size SyncScanShmemSize(void); + +#endif diff --git a/src/include/access/sysattr.h b/src/include/access/sysattr.h new file mode 100644 index 0000000..c0b1d5a --- /dev/null +++ b/src/include/access/sysattr.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * sysattr.h + * POSTGRES system attribute definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/sysattr.h + * + *------------------------------------------------------------------------- + */ +#ifndef SYSATTR_H +#define SYSATTR_H + + +/* + * Attribute numbers for the system-defined attributes + */ +#define SelfItemPointerAttributeNumber (-1) +#define MinTransactionIdAttributeNumber (-2) +#define MinCommandIdAttributeNumber (-3) +#define MaxTransactionIdAttributeNumber (-4) +#define MaxCommandIdAttributeNumber (-5) +#define TableOidAttributeNumber (-6) +#define FirstLowInvalidHeapAttributeNumber (-7) + +#endif /* SYSATTR_H */ diff --git a/src/include/access/table.h b/src/include/access/table.h new file mode 100644 index 0000000..969952d --- /dev/null +++ b/src/include/access/table.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * table.h + * Generic routines for table related code. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/table.h + * + *------------------------------------------------------------------------- + */ +#ifndef TABLE_H +#define TABLE_H + +#include "nodes/primnodes.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" + +extern Relation table_open(Oid relationId, LOCKMODE lockmode); +extern Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode); +extern Relation table_openrv_extended(const RangeVar *relation, + LOCKMODE lockmode, bool missing_ok); +extern Relation try_table_open(Oid relationId, LOCKMODE lockmode); +extern void table_close(Relation relation, LOCKMODE lockmode); + +#endif /* TABLE_H */ diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h new file mode 100644 index 0000000..fe869c6 --- /dev/null +++ b/src/include/access/tableam.h @@ -0,0 +1,2077 @@ +/*------------------------------------------------------------------------- + * + * tableam.h + * POSTGRES table access method definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/tableam.h + * + * NOTES + * See tableam.sgml for higher level documentation. + * + *------------------------------------------------------------------------- + */ +#ifndef TABLEAM_H +#define TABLEAM_H + +#include "access/relscan.h" +#include "access/sdir.h" +#include "access/xact.h" +#include "utils/guc.h" +#include "utils/rel.h" +#include "utils/snapshot.h" + + +#define DEFAULT_TABLE_ACCESS_METHOD "heap" + +/* GUCs */ +extern PGDLLIMPORT char *default_table_access_method; +extern PGDLLIMPORT bool synchronize_seqscans; + + +struct BulkInsertStateData; +struct IndexInfo; +struct SampleScanState; +struct TBMIterateResult; +struct VacuumParams; +struct ValidateIndexState; + +/* + * Bitmask values for the flags argument to the scan_begin callback. + */ +typedef enum ScanOptions +{ + /* one of SO_TYPE_* may be specified */ + SO_TYPE_SEQSCAN = 1 << 0, + SO_TYPE_BITMAPSCAN = 1 << 1, + SO_TYPE_SAMPLESCAN = 1 << 2, + SO_TYPE_TIDSCAN = 1 << 3, + SO_TYPE_TIDRANGESCAN = 1 << 4, + SO_TYPE_ANALYZE = 1 << 5, + + /* several of SO_ALLOW_* may be specified */ + /* allow or disallow use of access strategy */ + SO_ALLOW_STRAT = 1 << 6, + /* report location to syncscan logic? */ + SO_ALLOW_SYNC = 1 << 7, + /* verify visibility page-at-a-time? */ + SO_ALLOW_PAGEMODE = 1 << 8, + + /* unregister snapshot at scan end? */ + SO_TEMP_SNAPSHOT = 1 << 9 +} ScanOptions; + +/* + * Result codes for table_{update,delete,lock_tuple}, and for visibility + * routines inside table AMs. + */ +typedef enum TM_Result +{ + /* + * Signals that the action succeeded (i.e. update/delete performed, lock + * was acquired) + */ + TM_Ok, + + /* The affected tuple wasn't visible to the relevant snapshot */ + TM_Invisible, + + /* The affected tuple was already modified by the calling backend */ + TM_SelfModified, + + /* + * The affected tuple was updated by another transaction. This includes + * the case where tuple was moved to another partition. + */ + TM_Updated, + + /* The affected tuple was deleted by another transaction */ + TM_Deleted, + + /* + * The affected tuple is currently being modified by another session. This + * will only be returned if table_(update/delete/lock_tuple) are + * instructed not to wait. + */ + TM_BeingModified, + + /* lock couldn't be acquired, action skipped. Only used by lock_tuple */ + TM_WouldBlock +} TM_Result; + +/* + * When table_tuple_update, table_tuple_delete, or table_tuple_lock fail + * because the target tuple is already outdated, they fill in this struct to + * provide information to the caller about what happened. + * + * ctid is the target's ctid link: it is the same as the target's TID if the + * target was deleted, or the location of the replacement tuple if the target + * was updated. + * + * xmax is the outdating transaction's XID. If the caller wants to visit the + * replacement tuple, it must check that this matches before believing the + * replacement is really a match. + * + * cmax is the outdating command's CID, but only when the failure code is + * TM_SelfModified (i.e., something in the current transaction outdated the + * tuple); otherwise cmax is zero. (We make this restriction because + * HeapTupleHeaderGetCmax doesn't work for tuples outdated in other + * transactions.) + */ +typedef struct TM_FailureData +{ + ItemPointerData ctid; + TransactionId xmax; + CommandId cmax; + bool traversed; +} TM_FailureData; + +/* + * State used when calling table_index_delete_tuples(). + * + * Represents the status of table tuples, referenced by table TID and taken by + * index AM from index tuples. State consists of high level parameters of the + * deletion operation, plus two mutable palloc()'d arrays for information + * about the status of individual table tuples. These are conceptually one + * single array. Using two arrays keeps the TM_IndexDelete struct small, + * which makes sorting the first array (the deltids array) fast. + * + * Some index AM callers perform simple index tuple deletion (by specifying + * bottomup = false), and include only known-dead deltids. These known-dead + * entries are all marked knowndeletable = true directly (typically these are + * TIDs from LP_DEAD-marked index tuples), but that isn't strictly required. + * + * Callers that specify bottomup = true are "bottom-up index deletion" + * callers. The considerations for the tableam are more subtle with these + * callers because they ask the tableam to perform highly speculative work, + * and might only expect the tableam to check a small fraction of all entries. + * Caller is not allowed to specify knowndeletable = true for any entry + * because everything is highly speculative. Bottom-up caller provides + * context and hints to tableam -- see comments below for details on how index + * AMs and tableams should coordinate during bottom-up index deletion. + * + * Simple index deletion callers may ask the tableam to perform speculative + * work, too. This is a little like bottom-up deletion, but not too much. + * The tableam will only perform speculative work when it's practically free + * to do so in passing for simple deletion caller (while always performing + * whatever work is needed to enable knowndeletable/LP_DEAD index tuples to + * be deleted within index AM). This is the real reason why it's possible for + * simple index deletion caller to specify knowndeletable = false up front + * (this means "check if it's possible for me to delete corresponding index + * tuple when it's cheap to do so in passing"). The index AM should only + * include "extra" entries for index tuples whose TIDs point to a table block + * that tableam is expected to have to visit anyway (in the event of a block + * orientated tableam). The tableam isn't strictly obligated to check these + * "extra" TIDs, but a block-based AM should always manage to do so in + * practice. + * + * The final contents of the deltids/status arrays are interesting to callers + * that ask tableam to perform speculative work (i.e. when _any_ items have + * knowndeletable set to false up front). These index AM callers will + * naturally need to consult final state to determine which index tuples are + * in fact deletable. + * + * The index AM can keep track of which index tuple relates to which deltid by + * setting idxoffnum (and/or relying on each entry being uniquely identifiable + * using tid), which is important when the final contents of the array will + * need to be interpreted -- the array can shrink from initial size after + * tableam processing and/or have entries in a new order (tableam may sort + * deltids array for its own reasons). Bottom-up callers may find that final + * ndeltids is 0 on return from call to tableam, in which case no index tuple + * deletions are possible. Simple deletion callers can rely on any entries + * they know to be deletable appearing in the final array as deletable. + */ +typedef struct TM_IndexDelete +{ + ItemPointerData tid; /* table TID from index tuple */ + int16 id; /* Offset into TM_IndexStatus array */ +} TM_IndexDelete; + +typedef struct TM_IndexStatus +{ + OffsetNumber idxoffnum; /* Index am page offset number */ + bool knowndeletable; /* Currently known to be deletable? */ + + /* Bottom-up index deletion specific fields follow */ + bool promising; /* Promising (duplicate) index tuple? */ + int16 freespace; /* Space freed in index if deleted */ +} TM_IndexStatus; + +/* + * Index AM/tableam coordination is central to the design of bottom-up index + * deletion. The index AM provides hints about where to look to the tableam + * by marking some entries as "promising". Index AM does this with duplicate + * index tuples that are strongly suspected to be old versions left behind by + * UPDATEs that did not logically modify indexed values. Index AM may find it + * helpful to only mark entries as promising when they're thought to have been + * affected by such an UPDATE in the recent past. + * + * Bottom-up index deletion casts a wide net at first, usually by including + * all TIDs on a target index page. It is up to the tableam to worry about + * the cost of checking transaction status information. The tableam is in + * control, but needs careful guidance from the index AM. Index AM requests + * that bottomupfreespace target be met, while tableam measures progress + * towards that goal by tallying the per-entry freespace value for known + * deletable entries. (All !bottomup callers can just set these space related + * fields to zero.) + */ +typedef struct TM_IndexDeleteOp +{ + Relation irel; /* Target index relation */ + BlockNumber iblknum; /* Index block number (for error reports) */ + bool bottomup; /* Bottom-up (not simple) deletion? */ + int bottomupfreespace; /* Bottom-up space target */ + + /* Mutable per-TID information follows (index AM initializes entries) */ + int ndeltids; /* Current # of deltids/status elements */ + TM_IndexDelete *deltids; + TM_IndexStatus *status; +} TM_IndexDeleteOp; + +/* "options" flag bits for table_tuple_insert */ +/* TABLE_INSERT_SKIP_WAL was 0x0001; RelationNeedsWAL() now governs */ +#define TABLE_INSERT_SKIP_FSM 0x0002 +#define TABLE_INSERT_FROZEN 0x0004 +#define TABLE_INSERT_NO_LOGICAL 0x0008 + +/* flag bits for table_tuple_lock */ +/* Follow tuples whose update is in progress if lock modes don't conflict */ +#define TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS (1 << 0) +/* Follow update chain and lock latest version of tuple */ +#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION (1 << 1) + + +/* Typedef for callback function for table_index_build_scan */ +typedef void (*IndexBuildCallback) (Relation index, + ItemPointer tid, + Datum *values, + bool *isnull, + bool tupleIsAlive, + void *state); + +/* + * API struct for a table AM. Note this must be allocated in a + * server-lifetime manner, typically as a static const struct, which then gets + * returned by FormData_pg_am.amhandler. + * + * In most cases it's not appropriate to call the callbacks directly, use the + * table_* wrapper functions instead. + * + * GetTableAmRoutine() asserts that required callbacks are filled in, remember + * to update when adding a callback. + */ +typedef struct TableAmRoutine +{ + /* this must be set to T_TableAmRoutine */ + NodeTag type; + + + /* ------------------------------------------------------------------------ + * Slot related callbacks. + * ------------------------------------------------------------------------ + */ + + /* + * Return slot implementation suitable for storing a tuple of this AM. + */ + const TupleTableSlotOps *(*slot_callbacks) (Relation rel); + + + /* ------------------------------------------------------------------------ + * Table scan callbacks. + * ------------------------------------------------------------------------ + */ + + /* + * Start a scan of `rel`. The callback has to return a TableScanDesc, + * which will typically be embedded in a larger, AM specific, struct. + * + * If nkeys != 0, the results need to be filtered by those scan keys. + * + * pscan, if not NULL, will have already been initialized with + * parallelscan_initialize(), and has to be for the same relation. Will + * only be set coming from table_beginscan_parallel(). + * + * `flags` is a bitmask indicating the type of scan (ScanOptions's + * SO_TYPE_*, currently only one may be specified), options controlling + * the scan's behaviour (ScanOptions's SO_ALLOW_*, several may be + * specified, an AM may ignore unsupported ones) and whether the snapshot + * needs to be deallocated at scan_end (ScanOptions's SO_TEMP_SNAPSHOT). + */ + TableScanDesc (*scan_begin) (Relation rel, + Snapshot snapshot, + int nkeys, struct ScanKeyData *key, + ParallelTableScanDesc pscan, + uint32 flags); + + /* + * Release resources and deallocate scan. If TableScanDesc.temp_snap, + * TableScanDesc.rs_snapshot needs to be unregistered. + */ + void (*scan_end) (TableScanDesc scan); + + /* + * Restart relation scan. If set_params is set to true, allow_{strat, + * sync, pagemode} (see scan_begin) changes should be taken into account. + */ + void (*scan_rescan) (TableScanDesc scan, struct ScanKeyData *key, + bool set_params, bool allow_strat, + bool allow_sync, bool allow_pagemode); + + /* + * Return next tuple from `scan`, store in slot. + */ + bool (*scan_getnextslot) (TableScanDesc scan, + ScanDirection direction, + TupleTableSlot *slot); + + /*----------- + * Optional functions to provide scanning for ranges of ItemPointers. + * Implementations must either provide both of these functions, or neither + * of them. + * + * Implementations of scan_set_tidrange must themselves handle + * ItemPointers of any value. i.e, they must handle each of the following: + * + * 1) mintid or maxtid is beyond the end of the table; and + * 2) mintid is above maxtid; and + * 3) item offset for mintid or maxtid is beyond the maximum offset + * allowed by the AM. + * + * Implementations can assume that scan_set_tidrange is always called + * before can_getnextslot_tidrange or after scan_rescan and before any + * further calls to scan_getnextslot_tidrange. + */ + void (*scan_set_tidrange) (TableScanDesc scan, + ItemPointer mintid, + ItemPointer maxtid); + + /* + * Return next tuple from `scan` that's in the range of TIDs defined by + * scan_set_tidrange. + */ + bool (*scan_getnextslot_tidrange) (TableScanDesc scan, + ScanDirection direction, + TupleTableSlot *slot); + + /* ------------------------------------------------------------------------ + * Parallel table scan related functions. + * ------------------------------------------------------------------------ + */ + + /* + * Estimate the size of shared memory needed for a parallel scan of this + * relation. The snapshot does not need to be accounted for. + */ + Size (*parallelscan_estimate) (Relation rel); + + /* + * Initialize ParallelTableScanDesc for a parallel scan of this relation. + * `pscan` will be sized according to parallelscan_estimate() for the same + * relation. + */ + Size (*parallelscan_initialize) (Relation rel, + ParallelTableScanDesc pscan); + + /* + * Reinitialize `pscan` for a new scan. `rel` will be the same relation as + * when `pscan` was initialized by parallelscan_initialize. + */ + void (*parallelscan_reinitialize) (Relation rel, + ParallelTableScanDesc pscan); + + + /* ------------------------------------------------------------------------ + * Index Scan Callbacks + * ------------------------------------------------------------------------ + */ + + /* + * Prepare to fetch tuples from the relation, as needed when fetching + * tuples for an index scan. The callback has to return an + * IndexFetchTableData, which the AM will typically embed in a larger + * structure with additional information. + * + * Tuples for an index scan can then be fetched via index_fetch_tuple. + */ + struct IndexFetchTableData *(*index_fetch_begin) (Relation rel); + + /* + * Reset index fetch. Typically this will release cross index fetch + * resources held in IndexFetchTableData. + */ + void (*index_fetch_reset) (struct IndexFetchTableData *data); + + /* + * Release resources and deallocate index fetch. + */ + void (*index_fetch_end) (struct IndexFetchTableData *data); + + /* + * Fetch tuple at `tid` into `slot`, after doing a visibility test + * according to `snapshot`. If a tuple was found and passed the visibility + * test, return true, false otherwise. + * + * Note that AMs that do not necessarily update indexes when indexed + * columns do not change, need to return the current/correct version of + * the tuple that is visible to the snapshot, even if the tid points to an + * older version of the tuple. + * + * *call_again is false on the first call to index_fetch_tuple for a tid. + * If there potentially is another tuple matching the tid, *call_again + * needs to be set to true by index_fetch_tuple, signaling to the caller + * that index_fetch_tuple should be called again for the same tid. + * + * *all_dead, if all_dead is not NULL, should be set to true by + * index_fetch_tuple iff it is guaranteed that no backend needs to see + * that tuple. Index AMs can use that to avoid returning that tid in + * future searches. + */ + bool (*index_fetch_tuple) (struct IndexFetchTableData *scan, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + bool *call_again, bool *all_dead); + + + /* ------------------------------------------------------------------------ + * Callbacks for non-modifying operations on individual tuples + * ------------------------------------------------------------------------ + */ + + /* + * Fetch tuple at `tid` into `slot`, after doing a visibility test + * according to `snapshot`. If a tuple was found and passed the visibility + * test, returns true, false otherwise. + */ + bool (*tuple_fetch_row_version) (Relation rel, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot); + + /* + * Is tid valid for a scan of this relation. + */ + bool (*tuple_tid_valid) (TableScanDesc scan, + ItemPointer tid); + + /* + * Return the latest version of the tuple at `tid`, by updating `tid` to + * point at the newest version. + */ + void (*tuple_get_latest_tid) (TableScanDesc scan, + ItemPointer tid); + + /* + * Does the tuple in `slot` satisfy `snapshot`? The slot needs to be of + * the appropriate type for the AM. + */ + bool (*tuple_satisfies_snapshot) (Relation rel, + TupleTableSlot *slot, + Snapshot snapshot); + + /* see table_index_delete_tuples() */ + TransactionId (*index_delete_tuples) (Relation rel, + TM_IndexDeleteOp *delstate); + + + /* ------------------------------------------------------------------------ + * Manipulations of physical tuples. + * ------------------------------------------------------------------------ + */ + + /* see table_tuple_insert() for reference about parameters */ + void (*tuple_insert) (Relation rel, TupleTableSlot *slot, + CommandId cid, int options, + struct BulkInsertStateData *bistate); + + /* see table_tuple_insert_speculative() for reference about parameters */ + void (*tuple_insert_speculative) (Relation rel, + TupleTableSlot *slot, + CommandId cid, + int options, + struct BulkInsertStateData *bistate, + uint32 specToken); + + /* see table_tuple_complete_speculative() for reference about parameters */ + void (*tuple_complete_speculative) (Relation rel, + TupleTableSlot *slot, + uint32 specToken, + bool succeeded); + + /* see table_multi_insert() for reference about parameters */ + void (*multi_insert) (Relation rel, TupleTableSlot **slots, int nslots, + CommandId cid, int options, struct BulkInsertStateData *bistate); + + /* see table_tuple_delete() for reference about parameters */ + TM_Result (*tuple_delete) (Relation rel, + ItemPointer tid, + CommandId cid, + Snapshot snapshot, + Snapshot crosscheck, + bool wait, + TM_FailureData *tmfd, + bool changingPart); + + /* see table_tuple_update() for reference about parameters */ + TM_Result (*tuple_update) (Relation rel, + ItemPointer otid, + TupleTableSlot *slot, + CommandId cid, + Snapshot snapshot, + Snapshot crosscheck, + bool wait, + TM_FailureData *tmfd, + LockTupleMode *lockmode, + bool *update_indexes); + + /* see table_tuple_lock() for reference about parameters */ + TM_Result (*tuple_lock) (Relation rel, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + CommandId cid, + LockTupleMode mode, + LockWaitPolicy wait_policy, + uint8 flags, + TM_FailureData *tmfd); + + /* + * Perform operations necessary to complete insertions made via + * tuple_insert and multi_insert with a BulkInsertState specified. In-tree + * access methods ceased to use this. + * + * Typically callers of tuple_insert and multi_insert will just pass all + * the flags that apply to them, and each AM has to decide which of them + * make sense for it, and then only take actions in finish_bulk_insert for + * those flags, and ignore others. + * + * Optional callback. + */ + void (*finish_bulk_insert) (Relation rel, int options); + + + /* ------------------------------------------------------------------------ + * DDL related functionality. + * ------------------------------------------------------------------------ + */ + + /* + * This callback needs to create a new relation filenode for `rel`, with + * appropriate durability behaviour for `persistence`. + * + * Note that only the subset of the relcache filled by + * RelationBuildLocalRelation() can be relied upon and that the relation's + * catalog entries will either not yet exist (new relation), or will still + * reference the old relfilenode. + * + * As output *freezeXid, *minmulti must be set to the values appropriate + * for pg_class.{relfrozenxid, relminmxid}. For AMs that don't need those + * fields to be filled they can be set to InvalidTransactionId and + * InvalidMultiXactId, respectively. + * + * See also table_relation_set_new_filenode(). + */ + void (*relation_set_new_filenode) (Relation rel, + const RelFileNode *newrnode, + char persistence, + TransactionId *freezeXid, + MultiXactId *minmulti); + + /* + * This callback needs to remove all contents from `rel`'s current + * relfilenode. No provisions for transactional behaviour need to be made. + * Often this can be implemented by truncating the underlying storage to + * its minimal size. + * + * See also table_relation_nontransactional_truncate(). + */ + void (*relation_nontransactional_truncate) (Relation rel); + + /* + * See table_relation_copy_data(). + * + * This can typically be implemented by directly copying the underlying + * storage, unless it contains references to the tablespace internally. + */ + void (*relation_copy_data) (Relation rel, + const RelFileNode *newrnode); + + /* See table_relation_copy_for_cluster() */ + void (*relation_copy_for_cluster) (Relation NewTable, + Relation OldTable, + Relation OldIndex, + bool use_sort, + TransactionId OldestXmin, + TransactionId *xid_cutoff, + MultiXactId *multi_cutoff, + double *num_tuples, + double *tups_vacuumed, + double *tups_recently_dead); + + /* + * React to VACUUM command on the relation. The VACUUM can be triggered by + * a user or by autovacuum. The specific actions performed by the AM will + * depend heavily on the individual AM. + * + * On entry a transaction is already established, and the relation is + * locked with a ShareUpdateExclusive lock. + * + * Note that neither VACUUM FULL (and CLUSTER), nor ANALYZE go through + * this routine, even if (for ANALYZE) it is part of the same VACUUM + * command. + * + * There probably, in the future, needs to be a separate callback to + * integrate with autovacuum's scheduling. + */ + void (*relation_vacuum) (Relation rel, + struct VacuumParams *params, + BufferAccessStrategy bstrategy); + + /* + * Prepare to analyze block `blockno` of `scan`. The scan has been started + * with table_beginscan_analyze(). See also + * table_scan_analyze_next_block(). + * + * The callback may acquire resources like locks that are held until + * table_scan_analyze_next_tuple() returns false. It e.g. can make sense + * to hold a lock until all tuples on a block have been analyzed by + * scan_analyze_next_tuple. + * + * The callback can return false if the block is not suitable for + * sampling, e.g. because it's a metapage that could never contain tuples. + * + * XXX: This obviously is primarily suited for block-based AMs. It's not + * clear what a good interface for non block based AMs would be, so there + * isn't one yet. + */ + bool (*scan_analyze_next_block) (TableScanDesc scan, + BlockNumber blockno, + BufferAccessStrategy bstrategy); + + /* + * See table_scan_analyze_next_tuple(). + * + * Not every AM might have a meaningful concept of dead rows, in which + * case it's OK to not increment *deadrows - but note that that may + * influence autovacuum scheduling (see comment for relation_vacuum + * callback). + */ + bool (*scan_analyze_next_tuple) (TableScanDesc scan, + TransactionId OldestXmin, + double *liverows, + double *deadrows, + TupleTableSlot *slot); + + /* see table_index_build_range_scan for reference about parameters */ + double (*index_build_range_scan) (Relation table_rel, + Relation index_rel, + struct IndexInfo *index_info, + bool allow_sync, + bool anyvisible, + bool progress, + BlockNumber start_blockno, + BlockNumber numblocks, + IndexBuildCallback callback, + void *callback_state, + TableScanDesc scan); + + /* see table_index_validate_scan for reference about parameters */ + void (*index_validate_scan) (Relation table_rel, + Relation index_rel, + struct IndexInfo *index_info, + Snapshot snapshot, + struct ValidateIndexState *state); + + + /* ------------------------------------------------------------------------ + * Miscellaneous functions. + * ------------------------------------------------------------------------ + */ + + /* + * See table_relation_size(). + * + * Note that currently a few callers use the MAIN_FORKNUM size to figure + * out the range of potentially interesting blocks (brin, analyze). It's + * probable that we'll need to revise the interface for those at some + * point. + */ + uint64 (*relation_size) (Relation rel, ForkNumber forkNumber); + + + /* + * This callback should return true if the relation requires a TOAST table + * and false if it does not. It may wish to examine the relation's tuple + * descriptor before making a decision, but if it uses some other method + * of storing large values (or if it does not support them) it can simply + * return false. + */ + bool (*relation_needs_toast_table) (Relation rel); + + /* + * This callback should return the OID of the table AM that implements + * TOAST tables for this AM. If the relation_needs_toast_table callback + * always returns false, this callback is not required. + */ + Oid (*relation_toast_am) (Relation rel); + + /* + * This callback is invoked when detoasting a value stored in a toast + * table implemented by this AM. See table_relation_fetch_toast_slice() + * for more details. + */ + void (*relation_fetch_toast_slice) (Relation toastrel, Oid valueid, + int32 attrsize, + int32 sliceoffset, + int32 slicelength, + struct varlena *result); + + + /* ------------------------------------------------------------------------ + * Planner related functions. + * ------------------------------------------------------------------------ + */ + + /* + * See table_relation_estimate_size(). + * + * While block oriented, it shouldn't be too hard for an AM that doesn't + * internally use blocks to convert into a usable representation. + * + * This differs from the relation_size callback by returning size + * estimates (both relation size and tuple count) for planning purposes, + * rather than returning a currently correct estimate. + */ + void (*relation_estimate_size) (Relation rel, int32 *attr_widths, + BlockNumber *pages, double *tuples, + double *allvisfrac); + + + /* ------------------------------------------------------------------------ + * Executor related functions. + * ------------------------------------------------------------------------ + */ + + /* + * Prepare to fetch / check / return tuples from `tbmres->blockno` as part + * of a bitmap table scan. `scan` was started via table_beginscan_bm(). + * Return false if there are no tuples to be found on the page, true + * otherwise. + * + * This will typically read and pin the target block, and do the necessary + * work to allow scan_bitmap_next_tuple() to return tuples (e.g. it might + * make sense to perform tuple visibility checks at this time). For some + * AMs it will make more sense to do all the work referencing `tbmres` + * contents here, for others it might be better to defer more work to + * scan_bitmap_next_tuple. + * + * If `tbmres->blockno` is -1, this is a lossy scan and all visible tuples + * on the page have to be returned, otherwise the tuples at offsets in + * `tbmres->offsets` need to be returned. + * + * XXX: Currently this may only be implemented if the AM uses md.c as its + * storage manager, and uses ItemPointer->ip_blkid in a manner that maps + * blockids directly to the underlying storage. nodeBitmapHeapscan.c + * performs prefetching directly using that interface. This probably + * needs to be rectified at a later point. + * + * XXX: Currently this may only be implemented if the AM uses the + * visibilitymap, as nodeBitmapHeapscan.c unconditionally accesses it to + * perform prefetching. This probably needs to be rectified at a later + * point. + * + * Optional callback, but either both scan_bitmap_next_block and + * scan_bitmap_next_tuple need to exist, or neither. + */ + bool (*scan_bitmap_next_block) (TableScanDesc scan, + struct TBMIterateResult *tbmres); + + /* + * Fetch the next tuple of a bitmap table scan into `slot` and return true + * if a visible tuple was found, false otherwise. + * + * For some AMs it will make more sense to do all the work referencing + * `tbmres` contents in scan_bitmap_next_block, for others it might be + * better to defer more work to this callback. + * + * Optional callback, but either both scan_bitmap_next_block and + * scan_bitmap_next_tuple need to exist, or neither. + */ + bool (*scan_bitmap_next_tuple) (TableScanDesc scan, + struct TBMIterateResult *tbmres, + TupleTableSlot *slot); + + /* + * Prepare to fetch tuples from the next block in a sample scan. Return + * false if the sample scan is finished, true otherwise. `scan` was + * started via table_beginscan_sampling(). + * + * Typically this will first determine the target block by calling the + * TsmRoutine's NextSampleBlock() callback if not NULL, or alternatively + * perform a sequential scan over all blocks. The determined block is + * then typically read and pinned. + * + * As the TsmRoutine interface is block based, a block needs to be passed + * to NextSampleBlock(). If that's not appropriate for an AM, it + * internally needs to perform mapping between the internal and a block + * based representation. + * + * Note that it's not acceptable to hold deadlock prone resources such as + * lwlocks until scan_sample_next_tuple() has exhausted the tuples on the + * block - the tuple is likely to be returned to an upper query node, and + * the next call could be off a long while. Holding buffer pins and such + * is obviously OK. + * + * Currently it is required to implement this interface, as there's no + * alternative way (contrary e.g. to bitmap scans) to implement sample + * scans. If infeasible to implement, the AM may raise an error. + */ + bool (*scan_sample_next_block) (TableScanDesc scan, + struct SampleScanState *scanstate); + + /* + * This callback, only called after scan_sample_next_block has returned + * true, should determine the next tuple to be returned from the selected + * block using the TsmRoutine's NextSampleTuple() callback. + * + * The callback needs to perform visibility checks, and only return + * visible tuples. That obviously can mean calling NextSampleTuple() + * multiple times. + * + * The TsmRoutine interface assumes that there's a maximum offset on a + * given page, so if that doesn't apply to an AM, it needs to emulate that + * assumption somehow. + */ + bool (*scan_sample_next_tuple) (TableScanDesc scan, + struct SampleScanState *scanstate, + TupleTableSlot *slot); + +} TableAmRoutine; + + +/* ---------------------------------------------------------------------------- + * Slot functions. + * ---------------------------------------------------------------------------- + */ + +/* + * Returns slot callbacks suitable for holding tuples of the appropriate type + * for the relation. Works for tables, views, foreign tables and partitioned + * tables. + */ +extern const TupleTableSlotOps *table_slot_callbacks(Relation rel); + +/* + * Returns slot using the callbacks returned by table_slot_callbacks(), and + * registers it on *reglist. + */ +extern TupleTableSlot *table_slot_create(Relation rel, List **reglist); + + +/* ---------------------------------------------------------------------------- + * Table scan functions. + * ---------------------------------------------------------------------------- + */ + +/* + * Start a scan of `rel`. Returned tuples pass a visibility test of + * `snapshot`, and if nkeys != 0, the results are filtered by those scan keys. + */ +static inline TableScanDesc +table_beginscan(Relation rel, Snapshot snapshot, + int nkeys, struct ScanKeyData *key) +{ + uint32 flags = SO_TYPE_SEQSCAN | + SO_ALLOW_STRAT | SO_ALLOW_SYNC | SO_ALLOW_PAGEMODE; + + return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags); +} + +/* + * Like table_beginscan(), but for scanning catalog. It'll automatically use a + * snapshot appropriate for scanning catalog relations. + */ +extern TableScanDesc table_beginscan_catalog(Relation rel, int nkeys, + struct ScanKeyData *key); + +/* + * Like table_beginscan(), but table_beginscan_strat() offers an extended API + * that lets the caller control whether a nondefault buffer access strategy + * can be used, and whether syncscan can be chosen (possibly resulting in the + * scan not starting from block zero). Both of these default to true with + * plain table_beginscan. + */ +static inline TableScanDesc +table_beginscan_strat(Relation rel, Snapshot snapshot, + int nkeys, struct ScanKeyData *key, + bool allow_strat, bool allow_sync) +{ + uint32 flags = SO_TYPE_SEQSCAN | SO_ALLOW_PAGEMODE; + + if (allow_strat) + flags |= SO_ALLOW_STRAT; + if (allow_sync) + flags |= SO_ALLOW_SYNC; + + return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags); +} + +/* + * table_beginscan_bm is an alternative entry point for setting up a + * TableScanDesc for a bitmap heap scan. Although that scan technology is + * really quite unlike a standard seqscan, there is just enough commonality to + * make it worth using the same data structure. + */ +static inline TableScanDesc +table_beginscan_bm(Relation rel, Snapshot snapshot, + int nkeys, struct ScanKeyData *key) +{ + uint32 flags = SO_TYPE_BITMAPSCAN | SO_ALLOW_PAGEMODE; + + return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags); +} + +/* + * table_beginscan_sampling is an alternative entry point for setting up a + * TableScanDesc for a TABLESAMPLE scan. As with bitmap scans, it's worth + * using the same data structure although the behavior is rather different. + * In addition to the options offered by table_beginscan_strat, this call + * also allows control of whether page-mode visibility checking is used. + */ +static inline TableScanDesc +table_beginscan_sampling(Relation rel, Snapshot snapshot, + int nkeys, struct ScanKeyData *key, + bool allow_strat, bool allow_sync, + bool allow_pagemode) +{ + uint32 flags = SO_TYPE_SAMPLESCAN; + + if (allow_strat) + flags |= SO_ALLOW_STRAT; + if (allow_sync) + flags |= SO_ALLOW_SYNC; + if (allow_pagemode) + flags |= SO_ALLOW_PAGEMODE; + + return rel->rd_tableam->scan_begin(rel, snapshot, nkeys, key, NULL, flags); +} + +/* + * table_beginscan_tid is an alternative entry point for setting up a + * TableScanDesc for a Tid scan. As with bitmap scans, it's worth using + * the same data structure although the behavior is rather different. + */ +static inline TableScanDesc +table_beginscan_tid(Relation rel, Snapshot snapshot) +{ + uint32 flags = SO_TYPE_TIDSCAN; + + return rel->rd_tableam->scan_begin(rel, snapshot, 0, NULL, NULL, flags); +} + +/* + * table_beginscan_analyze is an alternative entry point for setting up a + * TableScanDesc for an ANALYZE scan. As with bitmap scans, it's worth using + * the same data structure although the behavior is rather different. + */ +static inline TableScanDesc +table_beginscan_analyze(Relation rel) +{ + uint32 flags = SO_TYPE_ANALYZE; + + return rel->rd_tableam->scan_begin(rel, NULL, 0, NULL, NULL, flags); +} + +/* + * End relation scan. + */ +static inline void +table_endscan(TableScanDesc scan) +{ + scan->rs_rd->rd_tableam->scan_end(scan); +} + +/* + * Restart a relation scan. + */ +static inline void +table_rescan(TableScanDesc scan, + struct ScanKeyData *key) +{ + scan->rs_rd->rd_tableam->scan_rescan(scan, key, false, false, false, false); +} + +/* + * Restart a relation scan after changing params. + * + * This call allows changing the buffer strategy, syncscan, and pagemode + * options before starting a fresh scan. Note that although the actual use of + * syncscan might change (effectively, enabling or disabling reporting), the + * previously selected startblock will be kept. + */ +static inline void +table_rescan_set_params(TableScanDesc scan, struct ScanKeyData *key, + bool allow_strat, bool allow_sync, bool allow_pagemode) +{ + scan->rs_rd->rd_tableam->scan_rescan(scan, key, true, + allow_strat, allow_sync, + allow_pagemode); +} + +/* + * Update snapshot used by the scan. + */ +extern void table_scan_update_snapshot(TableScanDesc scan, Snapshot snapshot); + +/* + * Return next tuple from `scan`, store in slot. + */ +static inline bool +table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot) +{ + slot->tts_tableOid = RelationGetRelid(sscan->rs_rd); + + /* + * We don't expect direct calls to table_scan_getnextslot with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_scan_getnextslot call during logical decoding"); + + return sscan->rs_rd->rd_tableam->scan_getnextslot(sscan, direction, slot); +} + +/* ---------------------------------------------------------------------------- + * TID Range scanning related functions. + * ---------------------------------------------------------------------------- + */ + +/* + * table_beginscan_tidrange is the entry point for setting up a TableScanDesc + * for a TID range scan. + */ +static inline TableScanDesc +table_beginscan_tidrange(Relation rel, Snapshot snapshot, + ItemPointer mintid, + ItemPointer maxtid) +{ + TableScanDesc sscan; + uint32 flags = SO_TYPE_TIDRANGESCAN | SO_ALLOW_PAGEMODE; + + sscan = rel->rd_tableam->scan_begin(rel, snapshot, 0, NULL, NULL, flags); + + /* Set the range of TIDs to scan */ + sscan->rs_rd->rd_tableam->scan_set_tidrange(sscan, mintid, maxtid); + + return sscan; +} + +/* + * table_rescan_tidrange resets the scan position and sets the minimum and + * maximum TID range to scan for a TableScanDesc created by + * table_beginscan_tidrange. + */ +static inline void +table_rescan_tidrange(TableScanDesc sscan, ItemPointer mintid, + ItemPointer maxtid) +{ + /* Ensure table_beginscan_tidrange() was used. */ + Assert((sscan->rs_flags & SO_TYPE_TIDRANGESCAN) != 0); + + sscan->rs_rd->rd_tableam->scan_rescan(sscan, NULL, false, false, false, false); + sscan->rs_rd->rd_tableam->scan_set_tidrange(sscan, mintid, maxtid); +} + +/* + * Fetch the next tuple from `sscan` for a TID range scan created by + * table_beginscan_tidrange(). Stores the tuple in `slot` and returns true, + * or returns false if no more tuples exist in the range. + */ +static inline bool +table_scan_getnextslot_tidrange(TableScanDesc sscan, ScanDirection direction, + TupleTableSlot *slot) +{ + /* Ensure table_beginscan_tidrange() was used. */ + Assert((sscan->rs_flags & SO_TYPE_TIDRANGESCAN) != 0); + + return sscan->rs_rd->rd_tableam->scan_getnextslot_tidrange(sscan, + direction, + slot); +} + + +/* ---------------------------------------------------------------------------- + * Parallel table scan related functions. + * ---------------------------------------------------------------------------- + */ + +/* + * Estimate the size of shared memory needed for a parallel scan of this + * relation. + */ +extern Size table_parallelscan_estimate(Relation rel, Snapshot snapshot); + +/* + * Initialize ParallelTableScanDesc for a parallel scan of this + * relation. `pscan` needs to be sized according to parallelscan_estimate() + * for the same relation. Call this just once in the leader process; then, + * individual workers attach via table_beginscan_parallel. + */ +extern void table_parallelscan_initialize(Relation rel, + ParallelTableScanDesc pscan, + Snapshot snapshot); + +/* + * Begin a parallel scan. `pscan` needs to have been initialized with + * table_parallelscan_initialize(), for the same relation. The initialization + * does not need to have happened in this backend. + * + * Caller must hold a suitable lock on the relation. + */ +extern TableScanDesc table_beginscan_parallel(Relation rel, + ParallelTableScanDesc pscan); + +/* + * Restart a parallel scan. Call this in the leader process. Caller is + * responsible for making sure that all workers have finished the scan + * beforehand. + */ +static inline void +table_parallelscan_reinitialize(Relation rel, ParallelTableScanDesc pscan) +{ + rel->rd_tableam->parallelscan_reinitialize(rel, pscan); +} + + +/* ---------------------------------------------------------------------------- + * Index scan related functions. + * ---------------------------------------------------------------------------- + */ + +/* + * Prepare to fetch tuples from the relation, as needed when fetching tuples + * for an index scan. + * + * Tuples for an index scan can then be fetched via table_index_fetch_tuple(). + */ +static inline IndexFetchTableData * +table_index_fetch_begin(Relation rel) +{ + return rel->rd_tableam->index_fetch_begin(rel); +} + +/* + * Reset index fetch. Typically this will release cross index fetch resources + * held in IndexFetchTableData. + */ +static inline void +table_index_fetch_reset(struct IndexFetchTableData *scan) +{ + scan->rel->rd_tableam->index_fetch_reset(scan); +} + +/* + * Release resources and deallocate index fetch. + */ +static inline void +table_index_fetch_end(struct IndexFetchTableData *scan) +{ + scan->rel->rd_tableam->index_fetch_end(scan); +} + +/* + * Fetches, as part of an index scan, tuple at `tid` into `slot`, after doing + * a visibility test according to `snapshot`. If a tuple was found and passed + * the visibility test, returns true, false otherwise. Note that *tid may be + * modified when we return true (see later remarks on multiple row versions + * reachable via a single index entry). + * + * *call_again needs to be false on the first call to table_index_fetch_tuple() for + * a tid. If there potentially is another tuple matching the tid, *call_again + * will be set to true, signaling that table_index_fetch_tuple() should be called + * again for the same tid. + * + * *all_dead, if all_dead is not NULL, will be set to true by + * table_index_fetch_tuple() iff it is guaranteed that no backend needs to see + * that tuple. Index AMs can use that to avoid returning that tid in future + * searches. + * + * The difference between this function and table_tuple_fetch_row_version() + * is that this function returns the currently visible version of a row if + * the AM supports storing multiple row versions reachable via a single index + * entry (like heap's HOT). Whereas table_tuple_fetch_row_version() only + * evaluates the tuple exactly at `tid`. Outside of index entry ->table tuple + * lookups, table_tuple_fetch_row_version() is what's usually needed. + */ +static inline bool +table_index_fetch_tuple(struct IndexFetchTableData *scan, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + bool *call_again, bool *all_dead) +{ + /* + * We don't expect direct calls to table_index_fetch_tuple with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_index_fetch_tuple call during logical decoding"); + + return scan->rel->rd_tableam->index_fetch_tuple(scan, tid, snapshot, + slot, call_again, + all_dead); +} + +/* + * This is a convenience wrapper around table_index_fetch_tuple() which + * returns whether there are table tuple items corresponding to an index + * entry. This likely is only useful to verify if there's a conflict in a + * unique index. + */ +extern bool table_index_fetch_tuple_check(Relation rel, + ItemPointer tid, + Snapshot snapshot, + bool *all_dead); + + +/* ------------------------------------------------------------------------ + * Functions for non-modifying operations on individual tuples + * ------------------------------------------------------------------------ + */ + + +/* + * Fetch tuple at `tid` into `slot`, after doing a visibility test according to + * `snapshot`. If a tuple was found and passed the visibility test, returns + * true, false otherwise. + * + * See table_index_fetch_tuple's comment about what the difference between + * these functions is. It is correct to use this function outside of index + * entry->table tuple lookups. + */ +static inline bool +table_tuple_fetch_row_version(Relation rel, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot) +{ + /* + * We don't expect direct calls to table_tuple_fetch_row_version with + * valid CheckXidAlive for catalog or regular tables. See detailed + * comments in xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_tuple_fetch_row_version call during logical decoding"); + + return rel->rd_tableam->tuple_fetch_row_version(rel, tid, snapshot, slot); +} + +/* + * Verify that `tid` is a potentially valid tuple identifier. That doesn't + * mean that the pointed to row needs to exist or be visible, but that + * attempting to fetch the row (e.g. with table_tuple_get_latest_tid() or + * table_tuple_fetch_row_version()) should not error out if called with that + * tid. + * + * `scan` needs to have been started via table_beginscan(). + */ +static inline bool +table_tuple_tid_valid(TableScanDesc scan, ItemPointer tid) +{ + return scan->rs_rd->rd_tableam->tuple_tid_valid(scan, tid); +} + +/* + * Return the latest version of the tuple at `tid`, by updating `tid` to + * point at the newest version. + */ +extern void table_tuple_get_latest_tid(TableScanDesc scan, ItemPointer tid); + +/* + * Return true iff tuple in slot satisfies the snapshot. + * + * This assumes the slot's tuple is valid, and of the appropriate type for the + * AM. + * + * Some AMs might modify the data underlying the tuple as a side-effect. If so + * they ought to mark the relevant buffer dirty. + */ +static inline bool +table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, + Snapshot snapshot) +{ + return rel->rd_tableam->tuple_satisfies_snapshot(rel, slot, snapshot); +} + +/* + * Determine which index tuples are safe to delete based on their table TID. + * + * Determines which entries from index AM caller's TM_IndexDeleteOp state + * point to vacuumable table tuples. Entries that are found by tableam to be + * vacuumable are naturally safe for index AM to delete, and so get directly + * marked as deletable. See comments above TM_IndexDelete and comments above + * TM_IndexDeleteOp for full details. + * + * Returns a latestRemovedXid transaction ID that caller generally places in + * its index deletion WAL record. This might be used during subsequent REDO + * of the WAL record when in Hot Standby mode -- a recovery conflict for the + * index deletion operation might be required on the standby. + */ +static inline TransactionId +table_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate) +{ + return rel->rd_tableam->index_delete_tuples(rel, delstate); +} + + +/* ---------------------------------------------------------------------------- + * Functions for manipulations of physical tuples. + * ---------------------------------------------------------------------------- + */ + +/* + * Insert a tuple from a slot into table AM routine. + * + * The options bitmask allows the caller to specify options that may change the + * behaviour of the AM. The AM will ignore options that it does not support. + * + * If the TABLE_INSERT_SKIP_FSM option is specified, AMs are free to not reuse + * free space in the relation. This can save some cycles when we know the + * relation is new and doesn't contain useful amounts of free space. + * TABLE_INSERT_SKIP_FSM is commonly passed directly to + * RelationGetBufferForTuple. See that method for more information. + * + * TABLE_INSERT_FROZEN should only be specified for inserts into + * relfilenodes created during the current subtransaction and when + * there are no prior snapshots or pre-existing portals open. + * This causes rows to be frozen, which is an MVCC violation and + * requires explicit options chosen by user. + * + * TABLE_INSERT_NO_LOGICAL force-disables the emitting of logical decoding + * information for the tuple. This should solely be used during table rewrites + * where RelationIsLogicallyLogged(relation) is not yet accurate for the new + * relation. + * + * Note that most of these options will be applied when inserting into the + * heap's TOAST table, too, if the tuple requires any out-of-line data. + * + * The BulkInsertState object (if any; bistate can be NULL for default + * behavior) is also just passed through to RelationGetBufferForTuple. If + * `bistate` is provided, table_finish_bulk_insert() needs to be called. + * + * On return the slot's tts_tid and tts_tableOid are updated to reflect the + * insertion. But note that any toasting of fields within the slot is NOT + * reflected in the slots contents. + */ +static inline void +table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, + int options, struct BulkInsertStateData *bistate) +{ + rel->rd_tableam->tuple_insert(rel, slot, cid, options, + bistate); +} + +/* + * Perform a "speculative insertion". These can be backed out afterwards + * without aborting the whole transaction. Other sessions can wait for the + * speculative insertion to be confirmed, turning it into a regular tuple, or + * aborted, as if it never existed. Speculatively inserted tuples behave as + * "value locks" of short duration, used to implement INSERT .. ON CONFLICT. + * + * A transaction having performed a speculative insertion has to either abort, + * or finish the speculative insertion with + * table_tuple_complete_speculative(succeeded = ...). + */ +static inline void +table_tuple_insert_speculative(Relation rel, TupleTableSlot *slot, + CommandId cid, int options, + struct BulkInsertStateData *bistate, + uint32 specToken) +{ + rel->rd_tableam->tuple_insert_speculative(rel, slot, cid, options, + bistate, specToken); +} + +/* + * Complete "speculative insertion" started in the same transaction. If + * succeeded is true, the tuple is fully inserted, if false, it's removed. + */ +static inline void +table_tuple_complete_speculative(Relation rel, TupleTableSlot *slot, + uint32 specToken, bool succeeded) +{ + rel->rd_tableam->tuple_complete_speculative(rel, slot, specToken, + succeeded); +} + +/* + * Insert multiple tuples into a table. + * + * This is like table_tuple_insert(), but inserts multiple tuples in one + * operation. That's often faster than calling table_tuple_insert() in a loop, + * because e.g. the AM can reduce WAL logging and page locking overhead. + * + * Except for taking `nslots` tuples as input, and an array of TupleTableSlots + * in `slots`, the parameters for table_multi_insert() are the same as for + * table_tuple_insert(). + * + * Note: this leaks memory into the current memory context. You can create a + * temporary context before calling this, if that's a problem. + */ +static inline void +table_multi_insert(Relation rel, TupleTableSlot **slots, int nslots, + CommandId cid, int options, struct BulkInsertStateData *bistate) +{ + rel->rd_tableam->multi_insert(rel, slots, nslots, + cid, options, bistate); +} + +/* + * Delete a tuple. + * + * NB: do not call this directly unless prepared to deal with + * concurrent-update conditions. Use simple_table_tuple_delete instead. + * + * Input parameters: + * relation - table to be modified (caller must hold suitable lock) + * tid - TID of tuple to be deleted + * cid - delete command ID (used for visibility test, and stored into + * cmax if successful) + * crosscheck - if not InvalidSnapshot, also check tuple against this + * wait - true if should wait for any conflicting update to commit/abort + * Output parameters: + * tmfd - filled in failure cases (see below) + * changingPart - true iff the tuple is being moved to another partition + * table due to an update of the partition key. Otherwise, false. + * + * Normal, successful return value is TM_Ok, which means we did actually + * delete it. Failure return codes are TM_SelfModified, TM_Updated, and + * TM_BeingModified (the last only possible if wait == false). + * + * In the failure cases, the routine fills *tmfd with the tuple's t_ctid, + * t_xmax, and, if possible, and, if possible, t_cmax. See comments for + * struct TM_FailureData for additional info. + */ +static inline TM_Result +table_tuple_delete(Relation rel, ItemPointer tid, CommandId cid, + Snapshot snapshot, Snapshot crosscheck, bool wait, + TM_FailureData *tmfd, bool changingPart) +{ + return rel->rd_tableam->tuple_delete(rel, tid, cid, + snapshot, crosscheck, + wait, tmfd, changingPart); +} + +/* + * Update a tuple. + * + * NB: do not call this directly unless you are prepared to deal with + * concurrent-update conditions. Use simple_table_tuple_update instead. + * + * Input parameters: + * relation - table to be modified (caller must hold suitable lock) + * otid - TID of old tuple to be replaced + * slot - newly constructed tuple data to store + * cid - update command ID (used for visibility test, and stored into + * cmax/cmin if successful) + * crosscheck - if not InvalidSnapshot, also check old tuple against this + * wait - true if should wait for any conflicting update to commit/abort + * Output parameters: + * tmfd - filled in failure cases (see below) + * lockmode - filled with lock mode acquired on tuple + * update_indexes - in success cases this is set to true if new index entries + * are required for this tuple + * + * Normal, successful return value is TM_Ok, which means we did actually + * update it. Failure return codes are TM_SelfModified, TM_Updated, and + * TM_BeingModified (the last only possible if wait == false). + * + * On success, the slot's tts_tid and tts_tableOid are updated to match the new + * stored tuple; in particular, slot->tts_tid is set to the TID where the + * new tuple was inserted, and its HEAP_ONLY_TUPLE flag is set iff a HOT + * update was done. However, any TOAST changes in the new tuple's + * data are not reflected into *newtup. + * + * In the failure cases, the routine fills *tmfd with the tuple's t_ctid, + * t_xmax, and, if possible, t_cmax. See comments for struct TM_FailureData + * for additional info. + */ +static inline TM_Result +table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, + CommandId cid, Snapshot snapshot, Snapshot crosscheck, + bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, + bool *update_indexes) +{ + return rel->rd_tableam->tuple_update(rel, otid, slot, + cid, snapshot, crosscheck, + wait, tmfd, + lockmode, update_indexes); +} + +/* + * Lock a tuple in the specified mode. + * + * Input parameters: + * relation: relation containing tuple (caller must hold suitable lock) + * tid: TID of tuple to lock + * snapshot: snapshot to use for visibility determinations + * cid: current command ID (used for visibility test, and stored into + * tuple's cmax if lock is successful) + * mode: lock mode desired + * wait_policy: what to do if tuple lock is not available + * flags: + * If TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS, follow the update chain to + * also lock descendant tuples if lock modes don't conflict. + * If TUPLE_LOCK_FLAG_FIND_LAST_VERSION, follow the update chain and lock + * latest version. + * + * Output parameters: + * *slot: contains the target tuple + * *tmfd: filled in failure cases (see below) + * + * Function result may be: + * TM_Ok: lock was successfully acquired + * TM_Invisible: lock failed because tuple was never visible to us + * TM_SelfModified: lock failed because tuple updated by self + * TM_Updated: lock failed because tuple updated by other xact + * TM_Deleted: lock failed because tuple deleted by other xact + * TM_WouldBlock: lock couldn't be acquired and wait_policy is skip + * + * In the failure cases other than TM_Invisible and TM_Deleted, the routine + * fills *tmfd with the tuple's t_ctid, t_xmax, and, if possible, t_cmax. See + * comments for struct TM_FailureData for additional info. + */ +static inline TM_Result +table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, + TupleTableSlot *slot, CommandId cid, LockTupleMode mode, + LockWaitPolicy wait_policy, uint8 flags, + TM_FailureData *tmfd) +{ + return rel->rd_tableam->tuple_lock(rel, tid, snapshot, slot, + cid, mode, wait_policy, + flags, tmfd); +} + +/* + * Perform operations necessary to complete insertions made via + * tuple_insert and multi_insert with a BulkInsertState specified. + */ +static inline void +table_finish_bulk_insert(Relation rel, int options) +{ + /* optional callback */ + if (rel->rd_tableam && rel->rd_tableam->finish_bulk_insert) + rel->rd_tableam->finish_bulk_insert(rel, options); +} + + +/* ------------------------------------------------------------------------ + * DDL related functionality. + * ------------------------------------------------------------------------ + */ + +/* + * Create storage for `rel` in `newrnode`, with persistence set to + * `persistence`. + * + * This is used both during relation creation and various DDL operations to + * create a new relfilenode that can be filled from scratch. When creating + * new storage for an existing relfilenode, this should be called before the + * relcache entry has been updated. + * + * *freezeXid, *minmulti are set to the xid / multixact horizon for the table + * that pg_class.{relfrozenxid, relminmxid} have to be set to. + */ +static inline void +table_relation_set_new_filenode(Relation rel, + const RelFileNode *newrnode, + char persistence, + TransactionId *freezeXid, + MultiXactId *minmulti) +{ + rel->rd_tableam->relation_set_new_filenode(rel, newrnode, persistence, + freezeXid, minmulti); +} + +/* + * Remove all table contents from `rel`, in a non-transactional manner. + * Non-transactional meaning that there's no need to support rollbacks. This + * commonly only is used to perform truncations for relfilenodes created in the + * current transaction. + */ +static inline void +table_relation_nontransactional_truncate(Relation rel) +{ + rel->rd_tableam->relation_nontransactional_truncate(rel); +} + +/* + * Copy data from `rel` into the new relfilenode `newrnode`. The new + * relfilenode may not have storage associated before this function is + * called. This is only supposed to be used for low level operations like + * changing a relation's tablespace. + */ +static inline void +table_relation_copy_data(Relation rel, const RelFileNode *newrnode) +{ + rel->rd_tableam->relation_copy_data(rel, newrnode); +} + +/* + * Copy data from `OldTable` into `NewTable`, as part of a CLUSTER or VACUUM + * FULL. + * + * Additional Input parameters: + * - use_sort - if true, the table contents are sorted appropriate for + * `OldIndex`; if false and OldIndex is not InvalidOid, the data is copied + * in that index's order; if false and OldIndex is InvalidOid, no sorting is + * performed + * - OldIndex - see use_sort + * - OldestXmin - computed by vacuum_set_xid_limits(), even when + * not needed for the relation's AM + * - *xid_cutoff - ditto + * - *multi_cutoff - ditto + * + * Output parameters: + * - *xid_cutoff - rel's new relfrozenxid value, may be invalid + * - *multi_cutoff - rel's new relminmxid value, may be invalid + * - *tups_vacuumed - stats, for logging, if appropriate for AM + * - *tups_recently_dead - stats, for logging, if appropriate for AM + */ +static inline void +table_relation_copy_for_cluster(Relation OldTable, Relation NewTable, + Relation OldIndex, + bool use_sort, + TransactionId OldestXmin, + TransactionId *xid_cutoff, + MultiXactId *multi_cutoff, + double *num_tuples, + double *tups_vacuumed, + double *tups_recently_dead) +{ + OldTable->rd_tableam->relation_copy_for_cluster(OldTable, NewTable, OldIndex, + use_sort, OldestXmin, + xid_cutoff, multi_cutoff, + num_tuples, tups_vacuumed, + tups_recently_dead); +} + +/* + * Perform VACUUM on the relation. The VACUUM can be triggered by a user or by + * autovacuum. The specific actions performed by the AM will depend heavily on + * the individual AM. + * + * On entry a transaction needs to already been established, and the + * table is locked with a ShareUpdateExclusive lock. + * + * Note that neither VACUUM FULL (and CLUSTER), nor ANALYZE go through this + * routine, even if (for ANALYZE) it is part of the same VACUUM command. + */ +static inline void +table_relation_vacuum(Relation rel, struct VacuumParams *params, + BufferAccessStrategy bstrategy) +{ + rel->rd_tableam->relation_vacuum(rel, params, bstrategy); +} + +/* + * Prepare to analyze block `blockno` of `scan`. The scan needs to have been + * started with table_beginscan_analyze(). Note that this routine might + * acquire resources like locks that are held until + * table_scan_analyze_next_tuple() returns false. + * + * Returns false if block is unsuitable for sampling, true otherwise. + */ +static inline bool +table_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno, + BufferAccessStrategy bstrategy) +{ + return scan->rs_rd->rd_tableam->scan_analyze_next_block(scan, blockno, + bstrategy); +} + +/* + * Iterate over tuples in the block selected with + * table_scan_analyze_next_block() (which needs to have returned true, and + * this routine may not have returned false for the same block before). If a + * tuple that's suitable for sampling is found, true is returned and a tuple + * is stored in `slot`. + * + * *liverows and *deadrows are incremented according to the encountered + * tuples. + */ +static inline bool +table_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin, + double *liverows, double *deadrows, + TupleTableSlot *slot) +{ + return scan->rs_rd->rd_tableam->scan_analyze_next_tuple(scan, OldestXmin, + liverows, deadrows, + slot); +} + +/* + * table_index_build_scan - scan the table to find tuples to be indexed + * + * This is called back from an access-method-specific index build procedure + * after the AM has done whatever setup it needs. The parent table relation + * is scanned to find tuples that should be entered into the index. Each + * such tuple is passed to the AM's callback routine, which does the right + * things to add it to the new index. After we return, the AM's index + * build procedure does whatever cleanup it needs. + * + * The total count of live tuples is returned. This is for updating pg_class + * statistics. (It's annoying not to be able to do that here, but we want to + * merge that update with others; see index_update_stats.) Note that the + * index AM itself must keep track of the number of index tuples; we don't do + * so here because the AM might reject some of the tuples for its own reasons, + * such as being unable to store NULLs. + * + * If 'progress', the PROGRESS_SCAN_BLOCKS_TOTAL counter is updated when + * starting the scan, and PROGRESS_SCAN_BLOCKS_DONE is updated as we go along. + * + * A side effect is to set indexInfo->ii_BrokenHotChain to true if we detect + * any potentially broken HOT chains. Currently, we set this if there are any + * RECENTLY_DEAD or DELETE_IN_PROGRESS entries in a HOT chain, without trying + * very hard to detect whether they're really incompatible with the chain tip. + * This only really makes sense for heap AM, it might need to be generalized + * for other AMs later. + */ +static inline double +table_index_build_scan(Relation table_rel, + Relation index_rel, + struct IndexInfo *index_info, + bool allow_sync, + bool progress, + IndexBuildCallback callback, + void *callback_state, + TableScanDesc scan) +{ + return table_rel->rd_tableam->index_build_range_scan(table_rel, + index_rel, + index_info, + allow_sync, + false, + progress, + 0, + InvalidBlockNumber, + callback, + callback_state, + scan); +} + +/* + * As table_index_build_scan(), except that instead of scanning the complete + * table, only the given number of blocks are scanned. Scan to end-of-rel can + * be signaled by passing InvalidBlockNumber as numblocks. Note that + * restricting the range to scan cannot be done when requesting syncscan. + * + * When "anyvisible" mode is requested, all tuples visible to any transaction + * are indexed and counted as live, including those inserted or deleted by + * transactions that are still in progress. + */ +static inline double +table_index_build_range_scan(Relation table_rel, + Relation index_rel, + struct IndexInfo *index_info, + bool allow_sync, + bool anyvisible, + bool progress, + BlockNumber start_blockno, + BlockNumber numblocks, + IndexBuildCallback callback, + void *callback_state, + TableScanDesc scan) +{ + return table_rel->rd_tableam->index_build_range_scan(table_rel, + index_rel, + index_info, + allow_sync, + anyvisible, + progress, + start_blockno, + numblocks, + callback, + callback_state, + scan); +} + +/* + * table_index_validate_scan - second table scan for concurrent index build + * + * See validate_index() for an explanation. + */ +static inline void +table_index_validate_scan(Relation table_rel, + Relation index_rel, + struct IndexInfo *index_info, + Snapshot snapshot, + struct ValidateIndexState *state) +{ + table_rel->rd_tableam->index_validate_scan(table_rel, + index_rel, + index_info, + snapshot, + state); +} + + +/* ---------------------------------------------------------------------------- + * Miscellaneous functionality + * ---------------------------------------------------------------------------- + */ + +/* + * Return the current size of `rel` in bytes. If `forkNumber` is + * InvalidForkNumber, return the relation's overall size, otherwise the size + * for the indicated fork. + * + * Note that the overall size might not be the equivalent of the sum of sizes + * for the individual forks for some AMs, e.g. because the AMs storage does + * not neatly map onto the builtin types of forks. + */ +static inline uint64 +table_relation_size(Relation rel, ForkNumber forkNumber) +{ + return rel->rd_tableam->relation_size(rel, forkNumber); +} + +/* + * table_relation_needs_toast_table - does this relation need a toast table? + */ +static inline bool +table_relation_needs_toast_table(Relation rel) +{ + return rel->rd_tableam->relation_needs_toast_table(rel); +} + +/* + * Return the OID of the AM that should be used to implement the TOAST table + * for this relation. + */ +static inline Oid +table_relation_toast_am(Relation rel) +{ + return rel->rd_tableam->relation_toast_am(rel); +} + +/* + * Fetch all or part of a TOAST value from a TOAST table. + * + * If this AM is never used to implement a TOAST table, then this callback + * is not needed. But, if toasted values are ever stored in a table of this + * type, then you will need this callback. + * + * toastrel is the relation in which the toasted value is stored. + * + * valueid identifes which toast value is to be fetched. For the heap, + * this corresponds to the values stored in the chunk_id column. + * + * attrsize is the total size of the toast value to be fetched. + * + * sliceoffset is the offset within the toast value of the first byte that + * should be fetched. + * + * slicelength is the number of bytes from the toast value that should be + * fetched. + * + * result is caller-allocated space into which the fetched bytes should be + * stored. + */ +static inline void +table_relation_fetch_toast_slice(Relation toastrel, Oid valueid, + int32 attrsize, int32 sliceoffset, + int32 slicelength, struct varlena *result) +{ + toastrel->rd_tableam->relation_fetch_toast_slice(toastrel, valueid, + attrsize, + sliceoffset, slicelength, + result); +} + + +/* ---------------------------------------------------------------------------- + * Planner related functionality + * ---------------------------------------------------------------------------- + */ + +/* + * Estimate the current size of the relation, as an AM specific workhorse for + * estimate_rel_size(). Look there for an explanation of the parameters. + */ +static inline void +table_relation_estimate_size(Relation rel, int32 *attr_widths, + BlockNumber *pages, double *tuples, + double *allvisfrac) +{ + rel->rd_tableam->relation_estimate_size(rel, attr_widths, pages, tuples, + allvisfrac); +} + + +/* ---------------------------------------------------------------------------- + * Executor related functionality + * ---------------------------------------------------------------------------- + */ + +/* + * Prepare to fetch / check / return tuples from `tbmres->blockno` as part of + * a bitmap table scan. `scan` needs to have been started via + * table_beginscan_bm(). Returns false if there are no tuples to be found on + * the page, true otherwise. + * + * Note, this is an optionally implemented function, therefore should only be + * used after verifying the presence (at plan time or such). + */ +static inline bool +table_scan_bitmap_next_block(TableScanDesc scan, + struct TBMIterateResult *tbmres) +{ + /* + * We don't expect direct calls to table_scan_bitmap_next_block with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_scan_bitmap_next_block call during logical decoding"); + + return scan->rs_rd->rd_tableam->scan_bitmap_next_block(scan, + tbmres); +} + +/* + * Fetch the next tuple of a bitmap table scan into `slot` and return true if + * a visible tuple was found, false otherwise. + * table_scan_bitmap_next_block() needs to previously have selected a + * block (i.e. returned true), and no previous + * table_scan_bitmap_next_tuple() for the same block may have + * returned false. + */ +static inline bool +table_scan_bitmap_next_tuple(TableScanDesc scan, + struct TBMIterateResult *tbmres, + TupleTableSlot *slot) +{ + /* + * We don't expect direct calls to table_scan_bitmap_next_tuple with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_scan_bitmap_next_tuple call during logical decoding"); + + return scan->rs_rd->rd_tableam->scan_bitmap_next_tuple(scan, + tbmres, + slot); +} + +/* + * Prepare to fetch tuples from the next block in a sample scan. Returns false + * if the sample scan is finished, true otherwise. `scan` needs to have been + * started via table_beginscan_sampling(). + * + * This will call the TsmRoutine's NextSampleBlock() callback if necessary + * (i.e. NextSampleBlock is not NULL), or perform a sequential scan over the + * underlying relation. + */ +static inline bool +table_scan_sample_next_block(TableScanDesc scan, + struct SampleScanState *scanstate) +{ + /* + * We don't expect direct calls to table_scan_sample_next_block with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_scan_sample_next_block call during logical decoding"); + return scan->rs_rd->rd_tableam->scan_sample_next_block(scan, scanstate); +} + +/* + * Fetch the next sample tuple into `slot` and return true if a visible tuple + * was found, false otherwise. table_scan_sample_next_block() needs to + * previously have selected a block (i.e. returned true), and no previous + * table_scan_sample_next_tuple() for the same block may have returned false. + * + * This will call the TsmRoutine's NextSampleTuple() callback. + */ +static inline bool +table_scan_sample_next_tuple(TableScanDesc scan, + struct SampleScanState *scanstate, + TupleTableSlot *slot) +{ + /* + * We don't expect direct calls to table_scan_sample_next_tuple with valid + * CheckXidAlive for catalog or regular tables. See detailed comments in + * xact.c where these variables are declared. + */ + if (unlikely(TransactionIdIsValid(CheckXidAlive) && !bsysscan)) + elog(ERROR, "unexpected table_scan_sample_next_tuple call during logical decoding"); + return scan->rs_rd->rd_tableam->scan_sample_next_tuple(scan, scanstate, + slot); +} + + +/* ---------------------------------------------------------------------------- + * Functions to make modifications a bit simpler. + * ---------------------------------------------------------------------------- + */ + +extern void simple_table_tuple_insert(Relation rel, TupleTableSlot *slot); +extern void simple_table_tuple_delete(Relation rel, ItemPointer tid, + Snapshot snapshot); +extern void simple_table_tuple_update(Relation rel, ItemPointer otid, + TupleTableSlot *slot, Snapshot snapshot, + bool *update_indexes); + + +/* ---------------------------------------------------------------------------- + * Helper functions to implement parallel scans for block oriented AMs. + * ---------------------------------------------------------------------------- + */ + +extern Size table_block_parallelscan_estimate(Relation rel); +extern Size table_block_parallelscan_initialize(Relation rel, + ParallelTableScanDesc pscan); +extern void table_block_parallelscan_reinitialize(Relation rel, + ParallelTableScanDesc pscan); +extern BlockNumber table_block_parallelscan_nextpage(Relation rel, + ParallelBlockTableScanWorker pbscanwork, + ParallelBlockTableScanDesc pbscan); +extern void table_block_parallelscan_startblock_init(Relation rel, + ParallelBlockTableScanWorker pbscanwork, + ParallelBlockTableScanDesc pbscan); + + +/* ---------------------------------------------------------------------------- + * Helper functions to implement relation sizing for block oriented AMs. + * ---------------------------------------------------------------------------- + */ + +extern uint64 table_block_relation_size(Relation rel, ForkNumber forkNumber); +extern void table_block_relation_estimate_size(Relation rel, + int32 *attr_widths, + BlockNumber *pages, + double *tuples, + double *allvisfrac, + Size overhead_bytes_per_tuple, + Size usable_bytes_per_page); + +/* ---------------------------------------------------------------------------- + * Functions in tableamapi.c + * ---------------------------------------------------------------------------- + */ + +extern const TableAmRoutine *GetTableAmRoutine(Oid amhandler); +extern const TableAmRoutine *GetHeapamTableAmRoutine(void); +extern bool check_default_table_access_method(char **newval, void **extra, + GucSource source); + +#endif /* TABLEAM_H */ diff --git a/src/include/access/timeline.h b/src/include/access/timeline.h new file mode 100644 index 0000000..3a37086 --- /dev/null +++ b/src/include/access/timeline.h @@ -0,0 +1,44 @@ +/* + * timeline.h + * + * Functions for reading and writing timeline history files. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/timeline.h + */ +#ifndef TIMELINE_H +#define TIMELINE_H + +#include "access/xlogdefs.h" +#include "nodes/pg_list.h" + +/* + * A list of these structs describes the timeline history of the server. Each + * TimeLineHistoryEntry represents a piece of WAL belonging to the history, + * from newest to oldest. All WAL locations between 'begin' and 'end' belong to + * the timeline represented by the entry. Together the 'begin' and 'end' + * pointers of all the entries form a contiguous line from beginning of time + * to infinity. + */ +typedef struct +{ + TimeLineID tli; + XLogRecPtr begin; /* inclusive */ + XLogRecPtr end; /* exclusive, InvalidXLogRecPtr means infinity */ +} TimeLineHistoryEntry; + +extern List *readTimeLineHistory(TimeLineID targetTLI); +extern bool existsTimeLineHistory(TimeLineID probeTLI); +extern TimeLineID findNewestTimeLine(TimeLineID startTLI); +extern void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, + XLogRecPtr switchpoint, char *reason); +extern void writeTimeLineHistoryFile(TimeLineID tli, char *content, int size); +extern void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end); +extern bool tliInHistory(TimeLineID tli, List *expectedTLEs); +extern TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history); +extern XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, + TimeLineID *nextTLI); + +#endif /* TIMELINE_H */ diff --git a/src/include/access/toast_compression.h b/src/include/access/toast_compression.h new file mode 100644 index 0000000..deb8f99 --- /dev/null +++ b/src/include/access/toast_compression.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * toast_compression.h + * Functions for toast compression. + * + * Copyright (c) 2021-2022, PostgreSQL Global Development Group + * + * src/include/access/toast_compression.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TOAST_COMPRESSION_H +#define TOAST_COMPRESSION_H + +/* + * GUC support. + * + * default_toast_compression is an integer for purposes of the GUC machinery, + * but the value is one of the char values defined below, as they appear in + * pg_attribute.attcompression, e.g. TOAST_PGLZ_COMPRESSION. + */ +extern PGDLLIMPORT int default_toast_compression; + +/* + * Built-in compression method ID. The toast compression header will store + * this in the first 2 bits of the raw length. These built-in compression + * method IDs are directly mapped to the built-in compression methods. + * + * Don't use these values for anything other than understanding the meaning + * of the raw bits from a varlena; in particular, if the goal is to identify + * a compression method, use the constants TOAST_PGLZ_COMPRESSION, etc. + * below. We might someday support more than 4 compression methods, but + * we can never have more than 4 values in this enum, because there are + * only 2 bits available in the places where this is stored. + */ +typedef enum ToastCompressionId +{ + TOAST_PGLZ_COMPRESSION_ID = 0, + TOAST_LZ4_COMPRESSION_ID = 1, + TOAST_INVALID_COMPRESSION_ID = 2 +} ToastCompressionId; + +/* + * Built-in compression methods. pg_attribute will store these in the + * attcompression column. In attcompression, InvalidCompressionMethod + * denotes the default behavior. + */ +#define TOAST_PGLZ_COMPRESSION 'p' +#define TOAST_LZ4_COMPRESSION 'l' +#define InvalidCompressionMethod '\0' + +#define CompressionMethodIsValid(cm) ((cm) != InvalidCompressionMethod) + + +/* pglz compression/decompression routines */ +extern struct varlena *pglz_compress_datum(const struct varlena *value); +extern struct varlena *pglz_decompress_datum(const struct varlena *value); +extern struct varlena *pglz_decompress_datum_slice(const struct varlena *value, + int32 slicelength); + +/* lz4 compression/decompression routines */ +extern struct varlena *lz4_compress_datum(const struct varlena *value); +extern struct varlena *lz4_decompress_datum(const struct varlena *value); +extern struct varlena *lz4_decompress_datum_slice(const struct varlena *value, + int32 slicelength); + +/* other stuff */ +extern ToastCompressionId toast_get_compression_id(struct varlena *attr); +extern char CompressionNameToMethod(const char *compression); +extern const char *GetCompressionMethodName(char method); + +#endif /* TOAST_COMPRESSION_H */ diff --git a/src/include/access/toast_helper.h b/src/include/access/toast_helper.h new file mode 100644 index 0000000..1e2aaf3 --- /dev/null +++ b/src/include/access/toast_helper.h @@ -0,0 +1,116 @@ +/*------------------------------------------------------------------------- + * + * toast_helper.h + * Helper functions for table AMs implementing compressed or + * out-of-line storage of varlena attributes. + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/access/toast_helper.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TOAST_HELPER_H +#define TOAST_HELPER_H + +#include "utils/rel.h" + +/* + * Information about one column of a tuple being toasted. + * + * NOTE: toast_action[i] can have these values: + * ' ' default handling + * TYPSTORAGE_PLAIN already processed --- don't touch it + * TYPSTORAGE_EXTENDED incompressible, but OK to move off + * + * NOTE: toast_attr[i].tai_size is only made valid for varlena attributes with + * toast_action[i] different from TYPSTORAGE_PLAIN. + */ +typedef struct +{ + struct varlena *tai_oldexternal; + int32 tai_size; + uint8 tai_colflags; + char tai_compression; +} ToastAttrInfo; + +/* + * Information about one tuple being toasted. + */ +typedef struct +{ + /* + * Before calling toast_tuple_init, the caller must initialize the + * following fields. Each array must have a length equal to + * ttc_rel->rd_att->natts. The tts_oldvalues and tts_oldisnull fields + * should be NULL in the case of an insert. + */ + Relation ttc_rel; /* the relation that contains the tuple */ + Datum *ttc_values; /* values from the tuple columns */ + bool *ttc_isnull; /* null flags for the tuple columns */ + Datum *ttc_oldvalues; /* values from previous tuple */ + bool *ttc_oldisnull; /* null flags from previous tuple */ + + /* + * Before calling toast_tuple_init, the caller should set tts_attr to + * point to an array of ToastAttrInfo structures of a length equal to + * tts_rel->rd_att->natts. The contents of the array need not be + * initialized. ttc_flags also does not need to be initialized. + */ + uint8 ttc_flags; + ToastAttrInfo *ttc_attr; +} ToastTupleContext; + +/* + * Flags indicating the overall state of a TOAST operation. + * + * TOAST_NEEDS_DELETE_OLD indicates that one or more old TOAST datums need + * to be deleted. + * + * TOAST_NEEDS_FREE indicates that one or more TOAST values need to be freed. + * + * TOAST_HAS_NULLS indicates that nulls were found in the tuple being toasted. + * + * TOAST_NEEDS_CHANGE indicates that a new tuple needs to built; in other + * words, the toaster did something. + */ +#define TOAST_NEEDS_DELETE_OLD 0x0001 +#define TOAST_NEEDS_FREE 0x0002 +#define TOAST_HAS_NULLS 0x0004 +#define TOAST_NEEDS_CHANGE 0x0008 + +/* + * Flags indicating the status of a TOAST operation with respect to a + * particular column. + * + * TOASTCOL_NEEDS_DELETE_OLD indicates that the old TOAST datums for this + * column need to be deleted. + * + * TOASTCOL_NEEDS_FREE indicates that the value for this column needs to + * be freed. + * + * TOASTCOL_IGNORE indicates that the toaster should not further process + * this column. + * + * TOASTCOL_INCOMPRESSIBLE indicates that this column has been found to + * be incompressible, but could be moved out-of-line. + */ +#define TOASTCOL_NEEDS_DELETE_OLD TOAST_NEEDS_DELETE_OLD +#define TOASTCOL_NEEDS_FREE TOAST_NEEDS_FREE +#define TOASTCOL_IGNORE 0x0010 +#define TOASTCOL_INCOMPRESSIBLE 0x0020 + +extern void toast_tuple_init(ToastTupleContext *ttc); +extern int toast_tuple_find_biggest_attribute(ToastTupleContext *ttc, + bool for_compression, + bool check_main); +extern void toast_tuple_try_compression(ToastTupleContext *ttc, int attribute); +extern void toast_tuple_externalize(ToastTupleContext *ttc, int attribute, + int options); +extern void toast_tuple_cleanup(ToastTupleContext *ttc); + +extern void toast_delete_external(Relation rel, Datum *values, bool *isnull, + bool is_speculative); + +#endif diff --git a/src/include/access/toast_internals.h b/src/include/access/toast_internals.h new file mode 100644 index 0000000..85e7dc0 --- /dev/null +++ b/src/include/access/toast_internals.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * toast_internals.h + * Internal definitions for the TOAST system. + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/access/toast_internals.h + * + *------------------------------------------------------------------------- + */ +#ifndef TOAST_INTERNALS_H +#define TOAST_INTERNALS_H + +#include "access/toast_compression.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + +/* + * The information at the start of the compressed toast data. + */ +typedef struct toast_compress_header +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint32 tcinfo; /* 2 bits for compression method and 30 bits + * external size; see va_extinfo */ +} toast_compress_header; + +/* + * Utilities for manipulation of header information for compressed + * toast entries. + */ +#define TOAST_COMPRESS_EXTSIZE(ptr) \ + (((toast_compress_header *) (ptr))->tcinfo & VARLENA_EXTSIZE_MASK) +#define TOAST_COMPRESS_METHOD(ptr) \ + (((toast_compress_header *) (ptr))->tcinfo >> VARLENA_EXTSIZE_BITS) + +#define TOAST_COMPRESS_SET_SIZE_AND_COMPRESS_METHOD(ptr, len, cm_method) \ + do { \ + Assert((len) > 0 && (len) <= VARLENA_EXTSIZE_MASK); \ + Assert((cm_method) == TOAST_PGLZ_COMPRESSION_ID || \ + (cm_method) == TOAST_LZ4_COMPRESSION_ID); \ + ((toast_compress_header *) (ptr))->tcinfo = \ + (len) | ((uint32) (cm_method) << VARLENA_EXTSIZE_BITS); \ + } while (0) + +extern Datum toast_compress_datum(Datum value, char cmethod); +extern Oid toast_get_valid_index(Oid toastoid, LOCKMODE lock); + +extern void toast_delete_datum(Relation rel, Datum value, bool is_speculative); +extern Datum toast_save_datum(Relation rel, Datum value, + struct varlena *oldexternal, int options); + +extern int toast_open_indexes(Relation toastrel, + LOCKMODE lock, + Relation **toastidxs, + int *num_indexes); +extern void toast_close_indexes(Relation *toastidxs, int num_indexes, + LOCKMODE lock); +extern void init_toast_snapshot(Snapshot toast_snapshot); + +#endif /* TOAST_INTERNALS_H */ diff --git a/src/include/access/transam.h b/src/include/access/transam.h new file mode 100644 index 0000000..775471d --- /dev/null +++ b/src/include/access/transam.h @@ -0,0 +1,375 @@ +/*------------------------------------------------------------------------- + * + * transam.h + * postgres transaction access method support code + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/transam.h + * + *------------------------------------------------------------------------- + */ +#ifndef TRANSAM_H +#define TRANSAM_H + +#include "access/xlogdefs.h" + + +/* ---------------- + * Special transaction ID values + * + * BootstrapTransactionId is the XID for "bootstrap" operations, and + * FrozenTransactionId is used for very old tuples. Both should + * always be considered valid. + * + * FirstNormalTransactionId is the first "normal" transaction id. + * Note: if you need to change it, you must change pg_class.h as well. + * ---------------- + */ +#define InvalidTransactionId ((TransactionId) 0) +#define BootstrapTransactionId ((TransactionId) 1) +#define FrozenTransactionId ((TransactionId) 2) +#define FirstNormalTransactionId ((TransactionId) 3) +#define MaxTransactionId ((TransactionId) 0xFFFFFFFF) + +/* ---------------- + * transaction ID manipulation macros + * ---------------- + */ +#define TransactionIdIsValid(xid) ((xid) != InvalidTransactionId) +#define TransactionIdIsNormal(xid) ((xid) >= FirstNormalTransactionId) +#define TransactionIdEquals(id1, id2) ((id1) == (id2)) +#define TransactionIdStore(xid, dest) (*(dest) = (xid)) +#define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId) + +#define EpochFromFullTransactionId(x) ((uint32) ((x).value >> 32)) +#define XidFromFullTransactionId(x) ((uint32) (x).value) +#define U64FromFullTransactionId(x) ((x).value) +#define FullTransactionIdEquals(a, b) ((a).value == (b).value) +#define FullTransactionIdPrecedes(a, b) ((a).value < (b).value) +#define FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value) +#define FullTransactionIdFollows(a, b) ((a).value > (b).value) +#define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value) +#define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x)) +#define InvalidFullTransactionId FullTransactionIdFromEpochAndXid(0, InvalidTransactionId) +#define FirstNormalFullTransactionId FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId) +#define FullTransactionIdIsNormal(x) FullTransactionIdFollowsOrEquals(x, FirstNormalFullTransactionId) + +/* + * A 64 bit value that contains an epoch and a TransactionId. This is + * wrapped in a struct to prevent implicit conversion to/from TransactionId. + * Not all values represent valid normal XIDs. + */ +typedef struct FullTransactionId +{ + uint64 value; +} FullTransactionId; + +static inline FullTransactionId +FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid) +{ + FullTransactionId result; + + result.value = ((uint64) epoch) << 32 | xid; + + return result; +} + +static inline FullTransactionId +FullTransactionIdFromU64(uint64 value) +{ + FullTransactionId result; + + result.value = value; + + return result; +} + +/* advance a transaction ID variable, handling wraparound correctly */ +#define TransactionIdAdvance(dest) \ + do { \ + (dest)++; \ + if ((dest) < FirstNormalTransactionId) \ + (dest) = FirstNormalTransactionId; \ + } while(0) + +/* + * Retreat a FullTransactionId variable, stepping over xids that would appear + * to be special only when viewed as 32bit XIDs. + */ +static inline void +FullTransactionIdRetreat(FullTransactionId *dest) +{ + dest->value--; + + /* + * In contrast to 32bit XIDs don't step over the "actual" special xids. + * For 64bit xids these can't be reached as part of a wraparound as they + * can in the 32bit case. + */ + if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) + return; + + /* + * But we do need to step over XIDs that'd appear special only for 32bit + * XIDs. + */ + while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) + dest->value--; +} + +/* + * Advance a FullTransactionId variable, stepping over xids that would appear + * to be special only when viewed as 32bit XIDs. + */ +static inline void +FullTransactionIdAdvance(FullTransactionId *dest) +{ + dest->value++; + + /* see FullTransactionIdAdvance() */ + if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId)) + return; + + while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId) + dest->value++; +} + +/* back up a transaction ID variable, handling wraparound correctly */ +#define TransactionIdRetreat(dest) \ + do { \ + (dest)--; \ + } while ((dest) < FirstNormalTransactionId) + +/* compare two XIDs already known to be normal; this is a macro for speed */ +#define NormalTransactionIdPrecedes(id1, id2) \ + (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ + (int32) ((id1) - (id2)) < 0) + +/* compare two XIDs already known to be normal; this is a macro for speed */ +#define NormalTransactionIdFollows(id1, id2) \ + (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ + (int32) ((id1) - (id2)) > 0) + +/* ---------- + * Object ID (OID) zero is InvalidOid. + * + * OIDs 1-9999 are reserved for manual assignment (see .dat files in + * src/include/catalog/). Of these, 8000-9999 are reserved for + * development purposes (such as in-progress patches and forks); + * they should not appear in released versions. + * + * OIDs 10000-11999 are reserved for assignment by genbki.pl, for use + * when the .dat files in src/include/catalog/ do not specify an OID + * for a catalog entry that requires one. Note that genbki.pl assigns + * these OIDs independently in each catalog, so they're not guaranteed + * to be globally unique. Furthermore, the bootstrap backend and + * initdb's post-bootstrap processing can also assign OIDs in this range. + * The normal OID-generation logic takes care of any OID conflicts that + * might arise from that. + * + * OIDs 12000-16383 are reserved for unpinned objects created by initdb's + * post-bootstrap processing. initdb forces the OID generator up to + * 12000 as soon as it's made the pinned objects it's responsible for. + * + * OIDs beginning at 16384 are assigned from the OID generator + * during normal multiuser operation. (We force the generator up to + * 16384 as soon as we are in normal operation.) + * + * The choices of 8000, 10000 and 12000 are completely arbitrary, and can be + * moved if we run low on OIDs in any category. Changing the macros below, + * and updating relevant documentation (see bki.sgml and RELEASE_CHANGES), + * should be sufficient to do this. Moving the 16384 boundary between + * initdb-assigned OIDs and user-defined objects would be substantially + * more painful, however, since some user-defined OIDs will appear in + * on-disk data; such a change would probably break pg_upgrade. + * + * NOTE: if the OID generator wraps around, we skip over OIDs 0-16383 + * and resume with 16384. This minimizes the odds of OID conflict, by not + * reassigning OIDs that might have been assigned during initdb. Critically, + * it also ensures that no user-created object will be considered pinned. + * ---------- + */ +#define FirstGenbkiObjectId 10000 +#define FirstUnpinnedObjectId 12000 +#define FirstNormalObjectId 16384 + +/* + * VariableCache is a data structure in shared memory that is used to track + * OID and XID assignment state. For largely historical reasons, there is + * just one struct with different fields that are protected by different + * LWLocks. + * + * Note: xidWrapLimit and oldestXidDB are not "active" values, but are + * used just to generate useful messages when xidWarnLimit or xidStopLimit + * are exceeded. + */ +typedef struct VariableCacheData +{ + /* + * These fields are protected by OidGenLock. + */ + Oid nextOid; /* next OID to assign */ + uint32 oidCount; /* OIDs available before must do XLOG work */ + + /* + * These fields are protected by XidGenLock. + */ + FullTransactionId nextXid; /* next XID to assign */ + + TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ + TransactionId xidVacLimit; /* start forcing autovacuums here */ + TransactionId xidWarnLimit; /* start complaining here */ + TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */ + TransactionId xidWrapLimit; /* where the world ends */ + Oid oldestXidDB; /* database with minimum datfrozenxid */ + + /* + * These fields are protected by CommitTsLock + */ + TransactionId oldestCommitTsXid; + TransactionId newestCommitTsXid; + + /* + * These fields are protected by ProcArrayLock. + */ + FullTransactionId latestCompletedXid; /* newest full XID that has + * committed or aborted */ + + /* + * Number of top-level transactions with xids (i.e. which may have + * modified the database) that completed in some form since the start of + * the server. This currently is solely used to check whether + * GetSnapshotData() needs to recompute the contents of the snapshot, or + * not. There are likely other users of this. Always above 1. + */ + uint64 xactCompletionCount; + + /* + * These fields are protected by XactTruncationLock + */ + TransactionId oldestClogXid; /* oldest it's safe to look up in clog */ + +} VariableCacheData; + +typedef VariableCacheData *VariableCache; + + +/* ---------------- + * extern declarations + * ---------------- + */ + +/* in transam/xact.c */ +extern bool TransactionStartedDuringRecovery(void); + +/* in transam/varsup.c */ +extern PGDLLIMPORT VariableCache ShmemVariableCache; + +/* + * prototypes for functions in transam/transam.c + */ +extern bool TransactionIdDidCommit(TransactionId transactionId); +extern bool TransactionIdDidAbort(TransactionId transactionId); +extern void TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids); +extern void TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn); +extern void TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids); +extern bool TransactionIdPrecedes(TransactionId id1, TransactionId id2); +extern bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2); +extern bool TransactionIdFollows(TransactionId id1, TransactionId id2); +extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2); +extern TransactionId TransactionIdLatest(TransactionId mainxid, + int nxids, const TransactionId *xids); +extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid); + +/* in transam/varsup.c */ +extern FullTransactionId GetNewTransactionId(bool isSubXact); +extern void AdvanceNextFullTransactionIdPastXid(TransactionId xid); +extern FullTransactionId ReadNextFullTransactionId(void); +extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid, + Oid oldest_datoid); +extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid); +extern bool ForceTransactionIdLimitUpdate(void); +extern Oid GetNewObjectId(void); +extern void StopGeneratingPinnedObjectIds(void); + +#ifdef USE_ASSERT_CHECKING +extern void AssertTransactionIdInAllowableRange(TransactionId xid); +#else +#define AssertTransactionIdInAllowableRange(xid) ((void)true) +#endif + +/* + * Some frontend programs include this header. For compilers that emit static + * inline functions even when they're unused, that leads to unsatisfied + * external references; hence hide them with #ifndef FRONTEND. + */ +#ifndef FRONTEND + +/* + * For callers that just need the XID part of the next transaction ID. + */ +static inline TransactionId +ReadNextTransactionId(void) +{ + return XidFromFullTransactionId(ReadNextFullTransactionId()); +} + +/* return transaction ID backed up by amount, handling wraparound correctly */ +static inline TransactionId +TransactionIdRetreatedBy(TransactionId xid, uint32 amount) +{ + xid -= amount; + + while (xid < FirstNormalTransactionId) + xid--; + + return xid; +} + +/* return the older of the two IDs */ +static inline TransactionId +TransactionIdOlder(TransactionId a, TransactionId b) +{ + if (!TransactionIdIsValid(a)) + return b; + + if (!TransactionIdIsValid(b)) + return a; + + if (TransactionIdPrecedes(a, b)) + return a; + return b; +} + +/* return the older of the two IDs, assuming they're both normal */ +static inline TransactionId +NormalTransactionIdOlder(TransactionId a, TransactionId b) +{ + Assert(TransactionIdIsNormal(a)); + Assert(TransactionIdIsNormal(b)); + if (NormalTransactionIdPrecedes(a, b)) + return a; + return b; +} + +/* return the newer of the two IDs */ +static inline FullTransactionId +FullTransactionIdNewer(FullTransactionId a, FullTransactionId b) +{ + if (!FullTransactionIdIsValid(a)) + return b; + + if (!FullTransactionIdIsValid(b)) + return a; + + if (FullTransactionIdFollows(a, b)) + return a; + return b; +} + +#endif /* FRONTEND */ + +#endif /* TRANSAM_H */ diff --git a/src/include/access/tsmapi.h b/src/include/access/tsmapi.h new file mode 100644 index 0000000..970993f --- /dev/null +++ b/src/include/access/tsmapi.h @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------- + * + * tsmapi.h + * API for tablesample methods + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * src/include/access/tsmapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef TSMAPI_H +#define TSMAPI_H + +#include "nodes/execnodes.h" +#include "nodes/pathnodes.h" + + +/* + * Callback function signatures --- see tablesample-method.sgml for more info. + */ + +typedef void (*SampleScanGetSampleSize_function) (PlannerInfo *root, + RelOptInfo *baserel, + List *paramexprs, + BlockNumber *pages, + double *tuples); + +typedef void (*InitSampleScan_function) (SampleScanState *node, + int eflags); + +typedef void (*BeginSampleScan_function) (SampleScanState *node, + Datum *params, + int nparams, + uint32 seed); + +typedef BlockNumber (*NextSampleBlock_function) (SampleScanState *node, + BlockNumber nblocks); + +typedef OffsetNumber (*NextSampleTuple_function) (SampleScanState *node, + BlockNumber blockno, + OffsetNumber maxoffset); + +typedef void (*EndSampleScan_function) (SampleScanState *node); + +/* + * TsmRoutine is the struct returned by a tablesample method's handler + * function. It provides pointers to the callback functions needed by the + * planner and executor, as well as additional information about the method. + * + * More function pointers are likely to be added in the future. + * Therefore it's recommended that the handler initialize the struct with + * makeNode(TsmRoutine) so that all fields are set to NULL. This will + * ensure that no fields are accidentally left undefined. + */ +typedef struct TsmRoutine +{ + NodeTag type; + + /* List of datatype OIDs for the arguments of the TABLESAMPLE clause */ + List *parameterTypes; + + /* Can method produce repeatable samples across, or even within, queries? */ + bool repeatable_across_queries; + bool repeatable_across_scans; + + /* Functions for planning a SampleScan on a physical table */ + SampleScanGetSampleSize_function SampleScanGetSampleSize; + + /* Functions for executing a SampleScan on a physical table */ + InitSampleScan_function InitSampleScan; /* can be NULL */ + BeginSampleScan_function BeginSampleScan; + NextSampleBlock_function NextSampleBlock; /* can be NULL */ + NextSampleTuple_function NextSampleTuple; + EndSampleScan_function EndSampleScan; /* can be NULL */ +} TsmRoutine; + + +/* Functions in access/tablesample/tablesample.c */ +extern TsmRoutine *GetTsmRoutine(Oid tsmhandler); + +#endif /* TSMAPI_H */ diff --git a/src/include/access/tupconvert.h b/src/include/access/tupconvert.h new file mode 100644 index 0000000..f5a5fd8 --- /dev/null +++ b/src/include/access/tupconvert.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * tupconvert.h + * Tuple conversion support. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/tupconvert.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPCONVERT_H +#define TUPCONVERT_H + +#include "access/attmap.h" +#include "access/htup.h" +#include "access/tupdesc.h" +#include "executor/tuptable.h" +#include "nodes/bitmapset.h" + + +typedef struct TupleConversionMap +{ + TupleDesc indesc; /* tupdesc for source rowtype */ + TupleDesc outdesc; /* tupdesc for result rowtype */ + AttrMap *attrMap; /* indexes of input fields, or 0 for null */ + Datum *invalues; /* workspace for deconstructing source */ + bool *inisnull; + Datum *outvalues; /* workspace for constructing result */ + bool *outisnull; +} TupleConversionMap; + + +extern TupleConversionMap *convert_tuples_by_position(TupleDesc indesc, + TupleDesc outdesc, + const char *msg); + +extern TupleConversionMap *convert_tuples_by_name(TupleDesc indesc, + TupleDesc outdesc); + +extern HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map); +extern TupleTableSlot *execute_attr_map_slot(AttrMap *attrMap, + TupleTableSlot *in_slot, + TupleTableSlot *out_slot); +extern Bitmapset *execute_attr_map_cols(AttrMap *attrMap, Bitmapset *inbitmap); + +extern void free_conversion_map(TupleConversionMap *map); + +#endif /* TUPCONVERT_H */ diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h new file mode 100644 index 0000000..28dd6de --- /dev/null +++ b/src/include/access/tupdesc.h @@ -0,0 +1,154 @@ +/*------------------------------------------------------------------------- + * + * tupdesc.h + * POSTGRES tuple descriptor definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/tupdesc.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPDESC_H +#define TUPDESC_H + +#include "access/attnum.h" +#include "catalog/pg_attribute.h" +#include "nodes/pg_list.h" + + +typedef struct AttrDefault +{ + AttrNumber adnum; + char *adbin; /* nodeToString representation of expr */ +} AttrDefault; + +typedef struct ConstrCheck +{ + char *ccname; + char *ccbin; /* nodeToString representation of expr */ + bool ccvalid; + bool ccnoinherit; /* this is a non-inheritable constraint */ +} ConstrCheck; + +/* This structure contains constraints of a tuple */ +typedef struct TupleConstr +{ + AttrDefault *defval; /* array */ + ConstrCheck *check; /* array */ + struct AttrMissing *missing; /* missing attributes values, NULL if none */ + uint16 num_defval; + uint16 num_check; + bool has_not_null; + bool has_generated_stored; +} TupleConstr; + +/* + * This struct is passed around within the backend to describe the structure + * of tuples. For tuples coming from on-disk relations, the information is + * collected from the pg_attribute, pg_attrdef, and pg_constraint catalogs. + * Transient row types (such as the result of a join query) have anonymous + * TupleDesc structs that generally omit any constraint info; therefore the + * structure is designed to let the constraints be omitted efficiently. + * + * Note that only user attributes, not system attributes, are mentioned in + * TupleDesc. + * + * If the tupdesc is known to correspond to a named rowtype (such as a table's + * rowtype) then tdtypeid identifies that type and tdtypmod is -1. Otherwise + * tdtypeid is RECORDOID, and tdtypmod can be either -1 for a fully anonymous + * row type, or a value >= 0 to allow the rowtype to be looked up in the + * typcache.c type cache. + * + * Note that tdtypeid is never the OID of a domain over composite, even if + * we are dealing with values that are known (at some higher level) to be of + * a domain-over-composite type. This is because tdtypeid/tdtypmod need to + * match up with the type labeling of composite Datums, and those are never + * explicitly marked as being of a domain type, either. + * + * Tuple descriptors that live in caches (relcache or typcache, at present) + * are reference-counted: they can be deleted when their reference count goes + * to zero. Tuple descriptors created by the executor need no reference + * counting, however: they are simply created in the appropriate memory + * context and go away when the context is freed. We set the tdrefcount + * field of such a descriptor to -1, while reference-counted descriptors + * always have tdrefcount >= 0. + */ +typedef struct TupleDescData +{ + int natts; /* number of attributes in the tuple */ + Oid tdtypeid; /* composite type ID for tuple type */ + int32 tdtypmod; /* typmod for tuple type */ + int tdrefcount; /* reference count, or -1 if not counting */ + TupleConstr *constr; /* constraints, or NULL if none */ + /* attrs[N] is the description of Attribute Number N+1 */ + FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER]; +} TupleDescData; +typedef struct TupleDescData *TupleDesc; + +/* Accessor for the i'th attribute of tupdesc. */ +#define TupleDescAttr(tupdesc, i) (&(tupdesc)->attrs[(i)]) + +extern TupleDesc CreateTemplateTupleDesc(int natts); + +extern TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs); + +extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); + +extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); + +#define TupleDescSize(src) \ + (offsetof(struct TupleDescData, attrs) + \ + (src)->natts * sizeof(FormData_pg_attribute)) + +extern void TupleDescCopy(TupleDesc dst, TupleDesc src); + +extern void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, + TupleDesc src, AttrNumber srcAttno); + +extern void FreeTupleDesc(TupleDesc tupdesc); + +extern void IncrTupleDescRefCount(TupleDesc tupdesc); +extern void DecrTupleDescRefCount(TupleDesc tupdesc); + +#define PinTupleDesc(tupdesc) \ + do { \ + if ((tupdesc)->tdrefcount >= 0) \ + IncrTupleDescRefCount(tupdesc); \ + } while (0) + +#define ReleaseTupleDesc(tupdesc) \ + do { \ + if ((tupdesc)->tdrefcount >= 0) \ + DecrTupleDescRefCount(tupdesc); \ + } while (0) + +extern bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); + +extern uint32 hashTupleDesc(TupleDesc tupdesc); + +extern void TupleDescInitEntry(TupleDesc desc, + AttrNumber attributeNumber, + const char *attributeName, + Oid oidtypeid, + int32 typmod, + int attdim); + +extern void TupleDescInitBuiltinEntry(TupleDesc desc, + AttrNumber attributeNumber, + const char *attributeName, + Oid oidtypeid, + int32 typmod, + int attdim); + +extern void TupleDescInitEntryCollation(TupleDesc desc, + AttrNumber attributeNumber, + Oid collationid); + +extern TupleDesc BuildDescForRelation(List *schema); + +extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods, List *collations); + +#endif /* TUPDESC_H */ diff --git a/src/include/access/tupdesc_details.h b/src/include/access/tupdesc_details.h new file mode 100644 index 0000000..04034bf --- /dev/null +++ b/src/include/access/tupdesc_details.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * tupdesc_details.h + * POSTGRES tuple descriptor definitions we can't include everywhere + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/tupdesc_details.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TUPDESC_DETAILS_H +#define TUPDESC_DETAILS_H + +/* + * Structure used to represent value to be used when the attribute is not + * present at all in a tuple, i.e. when the column was created after the tuple + */ +typedef struct AttrMissing +{ + bool am_present; /* true if non-NULL missing value exists */ + Datum am_value; /* value when attribute is missing */ +} AttrMissing; + +#endif /* TUPDESC_DETAILS_H */ diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h new file mode 100644 index 0000000..16c74a5 --- /dev/null +++ b/src/include/access/tupmacs.h @@ -0,0 +1,247 @@ +/*------------------------------------------------------------------------- + * + * tupmacs.h + * Tuple macros used by both index tuples and heap tuples. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/tupmacs.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPMACS_H +#define TUPMACS_H + +#include "catalog/pg_type_d.h" /* for TYPALIGN macros */ + + +/* + * Check a tuple's null bitmap to determine whether the attribute is null. + * Note that a 0 in the null bitmap indicates a null, while 1 indicates + * non-null. + */ +#define att_isnull(ATT, BITS) (!((BITS)[(ATT) >> 3] & (1 << ((ATT) & 0x07)))) + +/* + * Given a Form_pg_attribute and a pointer into a tuple's data area, + * return the correct value or pointer. + * + * We return a Datum value in all cases. If the attribute has "byval" false, + * we return the same pointer into the tuple data area that we're passed. + * Otherwise, we return the correct number of bytes fetched from the data + * area and extended to Datum form. + * + * On machines where Datum is 8 bytes, we support fetching 8-byte byval + * attributes; otherwise, only 1, 2, and 4-byte values are supported. + * + * Note that T must already be properly aligned for this to work correctly. + */ +#define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen) + +/* + * Same, but work from byval/len parameters rather than Form_pg_attribute. + */ +#if SIZEOF_DATUM == 8 + +#define fetch_att(T,attbyval,attlen) \ +( \ + (attbyval) ? \ + ( \ + (attlen) == (int) sizeof(Datum) ? \ + *((Datum *)(T)) \ + : \ + ( \ + (attlen) == (int) sizeof(int32) ? \ + Int32GetDatum(*((int32 *)(T))) \ + : \ + ( \ + (attlen) == (int) sizeof(int16) ? \ + Int16GetDatum(*((int16 *)(T))) \ + : \ + ( \ + AssertMacro((attlen) == 1), \ + CharGetDatum(*((char *)(T))) \ + ) \ + ) \ + ) \ + ) \ + : \ + PointerGetDatum((char *) (T)) \ +) +#else /* SIZEOF_DATUM != 8 */ + +#define fetch_att(T,attbyval,attlen) \ +( \ + (attbyval) ? \ + ( \ + (attlen) == (int) sizeof(int32) ? \ + Int32GetDatum(*((int32 *)(T))) \ + : \ + ( \ + (attlen) == (int) sizeof(int16) ? \ + Int16GetDatum(*((int16 *)(T))) \ + : \ + ( \ + AssertMacro((attlen) == 1), \ + CharGetDatum(*((char *)(T))) \ + ) \ + ) \ + ) \ + : \ + PointerGetDatum((char *) (T)) \ +) +#endif /* SIZEOF_DATUM == 8 */ + +/* + * att_align_datum aligns the given offset as needed for a datum of alignment + * requirement attalign and typlen attlen. attdatum is the Datum variable + * we intend to pack into a tuple (it's only accessed if we are dealing with + * a varlena type). Note that this assumes the Datum will be stored as-is; + * callers that are intending to convert non-short varlena datums to short + * format have to account for that themselves. + */ +#define att_align_datum(cur_offset, attalign, attlen, attdatum) \ +( \ + ((attlen) == -1 && VARATT_IS_SHORT(DatumGetPointer(attdatum))) ? \ + (uintptr_t) (cur_offset) : \ + att_align_nominal(cur_offset, attalign) \ +) + +/* + * att_align_pointer performs the same calculation as att_align_datum, + * but is used when walking a tuple. attptr is the current actual data + * pointer; when accessing a varlena field we have to "peek" to see if we + * are looking at a pad byte or the first byte of a 1-byte-header datum. + * (A zero byte must be either a pad byte, or the first byte of a correctly + * aligned 4-byte length word; in either case we can align safely. A non-zero + * byte must be either a 1-byte length word, or the first byte of a correctly + * aligned 4-byte length word; in either case we need not align.) + * + * Note: some callers pass a "char *" pointer for cur_offset. This is + * a bit of a hack but should work all right as long as uintptr_t is the + * correct width. + */ +#define att_align_pointer(cur_offset, attalign, attlen, attptr) \ +( \ + ((attlen) == -1 && VARATT_NOT_PAD_BYTE(attptr)) ? \ + (uintptr_t) (cur_offset) : \ + att_align_nominal(cur_offset, attalign) \ +) + +/* + * att_align_nominal aligns the given offset as needed for a datum of alignment + * requirement attalign, ignoring any consideration of packed varlena datums. + * There are three main use cases for using this macro directly: + * * we know that the att in question is not varlena (attlen != -1); + * in this case it is cheaper than the above macros and just as good. + * * we need to estimate alignment padding cost abstractly, ie without + * reference to a real tuple. We must assume the worst case that + * all varlenas are aligned. + * * within arrays and multiranges, we unconditionally align varlenas (XXX this + * should be revisited, probably). + * + * The attalign cases are tested in what is hopefully something like their + * frequency of occurrence. + */ +#define att_align_nominal(cur_offset, attalign) \ +( \ + ((attalign) == TYPALIGN_INT) ? INTALIGN(cur_offset) : \ + (((attalign) == TYPALIGN_CHAR) ? (uintptr_t) (cur_offset) : \ + (((attalign) == TYPALIGN_DOUBLE) ? DOUBLEALIGN(cur_offset) : \ + ( \ + AssertMacro((attalign) == TYPALIGN_SHORT), \ + SHORTALIGN(cur_offset) \ + ))) \ +) + +/* + * att_addlength_datum increments the given offset by the space needed for + * the given Datum variable. attdatum is only accessed if we are dealing + * with a variable-length attribute. + */ +#define att_addlength_datum(cur_offset, attlen, attdatum) \ + att_addlength_pointer(cur_offset, attlen, DatumGetPointer(attdatum)) + +/* + * att_addlength_pointer performs the same calculation as att_addlength_datum, + * but is used when walking a tuple --- attptr is the pointer to the field + * within the tuple. + * + * Note: some callers pass a "char *" pointer for cur_offset. This is + * actually perfectly OK, but probably should be cleaned up along with + * the same practice for att_align_pointer. + */ +#define att_addlength_pointer(cur_offset, attlen, attptr) \ +( \ + ((attlen) > 0) ? \ + ( \ + (cur_offset) + (attlen) \ + ) \ + : (((attlen) == -1) ? \ + ( \ + (cur_offset) + VARSIZE_ANY(attptr) \ + ) \ + : \ + ( \ + AssertMacro((attlen) == -2), \ + (cur_offset) + (strlen((char *) (attptr)) + 1) \ + )) \ +) + +/* + * store_att_byval is a partial inverse of fetch_att: store a given Datum + * value into a tuple data area at the specified address. However, it only + * handles the byval case, because in typical usage the caller needs to + * distinguish by-val and by-ref cases anyway, and so a do-it-all macro + * wouldn't be convenient. + */ +#if SIZEOF_DATUM == 8 + +#define store_att_byval(T,newdatum,attlen) \ + do { \ + switch (attlen) \ + { \ + case sizeof(char): \ + *(char *) (T) = DatumGetChar(newdatum); \ + break; \ + case sizeof(int16): \ + *(int16 *) (T) = DatumGetInt16(newdatum); \ + break; \ + case sizeof(int32): \ + *(int32 *) (T) = DatumGetInt32(newdatum); \ + break; \ + case sizeof(Datum): \ + *(Datum *) (T) = (newdatum); \ + break; \ + default: \ + elog(ERROR, "unsupported byval length: %d", \ + (int) (attlen)); \ + break; \ + } \ + } while (0) +#else /* SIZEOF_DATUM != 8 */ + +#define store_att_byval(T,newdatum,attlen) \ + do { \ + switch (attlen) \ + { \ + case sizeof(char): \ + *(char *) (T) = DatumGetChar(newdatum); \ + break; \ + case sizeof(int16): \ + *(int16 *) (T) = DatumGetInt16(newdatum); \ + break; \ + case sizeof(int32): \ + *(int32 *) (T) = DatumGetInt32(newdatum); \ + break; \ + default: \ + elog(ERROR, "unsupported byval length: %d", \ + (int) (attlen)); \ + break; \ + } \ + } while (0) +#endif /* SIZEOF_DATUM == 8 */ + +#endif diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h new file mode 100644 index 0000000..5d6544e --- /dev/null +++ b/src/include/access/twophase.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + * + * twophase.h + * Two-phase-commit related declarations. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/twophase.h + * + *------------------------------------------------------------------------- + */ +#ifndef TWOPHASE_H +#define TWOPHASE_H + +#include "access/xact.h" +#include "access/xlogdefs.h" +#include "datatype/timestamp.h" +#include "storage/lock.h" + +/* + * GlobalTransactionData is defined in twophase.c; other places have no + * business knowing the internal definition. + */ +typedef struct GlobalTransactionData *GlobalTransaction; + +/* GUC variable */ +extern PGDLLIMPORT int max_prepared_xacts; + +extern Size TwoPhaseShmemSize(void); +extern void TwoPhaseShmemInit(void); + +extern void AtAbort_Twophase(void); +extern void PostPrepare_Twophase(void); + +extern TransactionId TwoPhaseGetXidByVirtualXID(VirtualTransactionId vxid, + bool *have_more); +extern PGPROC *TwoPhaseGetDummyProc(TransactionId xid, bool lock_held); +extern BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held); + +extern GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid, + TimestampTz prepared_at, + Oid owner, Oid databaseid); + +extern void StartPrepare(GlobalTransaction gxact); +extern void EndPrepare(GlobalTransaction gxact); +extern bool StandbyTransactionIdIsPrepared(TransactionId xid); + +extern TransactionId PrescanPreparedTransactions(TransactionId **xids_p, + int *nxids_p); +extern void StandbyRecoverPreparedTransactions(void); +extern void RecoverPreparedTransactions(void); + +extern void CheckPointTwoPhase(XLogRecPtr redo_horizon); + +extern void FinishPreparedTransaction(const char *gid, bool isCommit); + +extern void PrepareRedoAdd(char *buf, XLogRecPtr start_lsn, + XLogRecPtr end_lsn, RepOriginId origin_id); +extern void PrepareRedoRemove(TransactionId xid, bool giveWarning); +extern void restoreTwoPhaseData(void); +extern bool LookupGXact(const char *gid, XLogRecPtr prepare_at_lsn, + TimestampTz origin_prepare_timestamp); +#endif /* TWOPHASE_H */ diff --git a/src/include/access/twophase_rmgr.h b/src/include/access/twophase_rmgr.h new file mode 100644 index 0000000..96381a5 --- /dev/null +++ b/src/include/access/twophase_rmgr.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * twophase_rmgr.h + * Two-phase-commit resource managers definition + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/twophase_rmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef TWOPHASE_RMGR_H +#define TWOPHASE_RMGR_H + +typedef void (*TwoPhaseCallback) (TransactionId xid, uint16 info, + void *recdata, uint32 len); +typedef uint8 TwoPhaseRmgrId; + +/* + * Built-in resource managers + */ +#define TWOPHASE_RM_END_ID 0 +#define TWOPHASE_RM_LOCK_ID 1 +#define TWOPHASE_RM_PGSTAT_ID 2 +#define TWOPHASE_RM_MULTIXACT_ID 3 +#define TWOPHASE_RM_PREDICATELOCK_ID 4 +#define TWOPHASE_RM_MAX_ID TWOPHASE_RM_PREDICATELOCK_ID + +extern PGDLLIMPORT const TwoPhaseCallback twophase_recover_callbacks[]; +extern PGDLLIMPORT const TwoPhaseCallback twophase_postcommit_callbacks[]; +extern PGDLLIMPORT const TwoPhaseCallback twophase_postabort_callbacks[]; +extern PGDLLIMPORT const TwoPhaseCallback twophase_standby_recover_callbacks[]; + + +extern void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, + const void *data, uint32 len); + +#endif /* TWOPHASE_RMGR_H */ diff --git a/src/include/access/valid.h b/src/include/access/valid.h new file mode 100644 index 0000000..a5525d0 --- /dev/null +++ b/src/include/access/valid.h @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------- + * + * valid.h + * POSTGRES tuple qualification validity definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/valid.h + * + *------------------------------------------------------------------------- + */ +#ifndef VALID_H +#define VALID_H + +/* + * HeapKeyTest + * + * Test a heap tuple to see if it satisfies a scan key. + */ +#define HeapKeyTest(tuple, \ + tupdesc, \ + nkeys, \ + keys, \ + result) \ +do \ +{ \ + /* Use underscores to protect the variables passed in as parameters */ \ + int __cur_nkeys = (nkeys); \ + ScanKey __cur_keys = (keys); \ + \ + (result) = true; /* may change */ \ + for (; __cur_nkeys--; __cur_keys++) \ + { \ + Datum __atp; \ + bool __isnull; \ + Datum __test; \ + \ + if (__cur_keys->sk_flags & SK_ISNULL) \ + { \ + (result) = false; \ + break; \ + } \ + \ + __atp = heap_getattr((tuple), \ + __cur_keys->sk_attno, \ + (tupdesc), \ + &__isnull); \ + \ + if (__isnull) \ + { \ + (result) = false; \ + break; \ + } \ + \ + __test = FunctionCall2Coll(&__cur_keys->sk_func, \ + __cur_keys->sk_collation, \ + __atp, __cur_keys->sk_argument); \ + \ + if (!DatumGetBool(__test)) \ + { \ + (result) = false; \ + break; \ + } \ + } \ +} while (0) + +#endif /* VALID_H */ diff --git a/src/include/access/visibilitymap.h b/src/include/access/visibilitymap.h new file mode 100644 index 0000000..55f67ed --- /dev/null +++ b/src/include/access/visibilitymap.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * visibilitymap.h + * visibility map interface + * + * + * Portions Copyright (c) 2007-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/visibilitymap.h + * + *------------------------------------------------------------------------- + */ +#ifndef VISIBILITYMAP_H +#define VISIBILITYMAP_H + +#include "access/visibilitymapdefs.h" +#include "access/xlogdefs.h" +#include "storage/block.h" +#include "storage/buf.h" +#include "utils/relcache.h" + +/* Macros for visibilitymap test */ +#define VM_ALL_VISIBLE(r, b, v) \ + ((visibilitymap_get_status((r), (b), (v)) & VISIBILITYMAP_ALL_VISIBLE) != 0) +#define VM_ALL_FROZEN(r, b, v) \ + ((visibilitymap_get_status((r), (b), (v)) & VISIBILITYMAP_ALL_FROZEN) != 0) + +extern bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, + Buffer vmbuf, uint8 flags); +extern void visibilitymap_pin(Relation rel, BlockNumber heapBlk, + Buffer *vmbuf); +extern bool visibilitymap_pin_ok(BlockNumber heapBlk, Buffer vmbuf); +extern void visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf, + XLogRecPtr recptr, Buffer vmBuf, TransactionId cutoff_xid, + uint8 flags); +extern uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf); +extern void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen); +extern BlockNumber visibilitymap_prepare_truncate(Relation rel, + BlockNumber nheapblocks); + +#endif /* VISIBILITYMAP_H */ diff --git a/src/include/access/visibilitymapdefs.h b/src/include/access/visibilitymapdefs.h new file mode 100644 index 0000000..2803ef5 --- /dev/null +++ b/src/include/access/visibilitymapdefs.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * visibilitymapdefs.h + * macros for accessing contents of visibility map pages + * + * + * Copyright (c) 2021-2022, PostgreSQL Global Development Group + * + * src/include/access/visibilitymapdefs.h + * + *------------------------------------------------------------------------- + */ +#ifndef VISIBILITYMAPDEFS_H +#define VISIBILITYMAPDEFS_H + +/* Number of bits for one heap page */ +#define BITS_PER_HEAPBLOCK 2 + +/* Flags for bit map */ +#define VISIBILITYMAP_ALL_VISIBLE 0x01 +#define VISIBILITYMAP_ALL_FROZEN 0x02 +#define VISIBILITYMAP_VALID_BITS 0x03 /* OR of all valid visibilitymap + * flags bits */ + +#endif /* VISIBILITYMAPDEFS_H */ diff --git a/src/include/access/xact.h b/src/include/access/xact.h new file mode 100644 index 0000000..8d46a78 --- /dev/null +++ b/src/include/access/xact.h @@ -0,0 +1,530 @@ +/*------------------------------------------------------------------------- + * + * xact.h + * postgres transaction system definitions + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xact.h + * + *------------------------------------------------------------------------- + */ +#ifndef XACT_H +#define XACT_H + +#include "access/transam.h" +#include "access/xlogreader.h" +#include "datatype/timestamp.h" +#include "lib/stringinfo.h" +#include "nodes/pg_list.h" +#include "storage/relfilenode.h" +#include "storage/sinval.h" + +/* + * Maximum size of Global Transaction ID (including '\0'). + * + * Note that the max value of GIDSIZE must fit in the uint16 gidlen, + * specified in TwoPhaseFileHeader. + */ +#define GIDSIZE 200 + +/* + * Xact isolation levels + */ +#define XACT_READ_UNCOMMITTED 0 +#define XACT_READ_COMMITTED 1 +#define XACT_REPEATABLE_READ 2 +#define XACT_SERIALIZABLE 3 + +extern PGDLLIMPORT int DefaultXactIsoLevel; +extern PGDLLIMPORT int XactIsoLevel; + +/* + * We implement three isolation levels internally. + * The two stronger ones use one snapshot per database transaction; + * the others use one snapshot per statement. + * Serializable uses predicate locks in addition to snapshots. + * These macros should be used to check which isolation level is selected. + */ +#define IsolationUsesXactSnapshot() (XactIsoLevel >= XACT_REPEATABLE_READ) +#define IsolationIsSerializable() (XactIsoLevel == XACT_SERIALIZABLE) + +/* Xact read-only state */ +extern PGDLLIMPORT bool DefaultXactReadOnly; +extern PGDLLIMPORT bool XactReadOnly; + +/* flag for logging statements in this transaction */ +extern PGDLLIMPORT bool xact_is_sampled; + +/* + * Xact is deferrable -- only meaningful (currently) for read only + * SERIALIZABLE transactions + */ +extern PGDLLIMPORT bool DefaultXactDeferrable; +extern PGDLLIMPORT bool XactDeferrable; + +typedef enum +{ + SYNCHRONOUS_COMMIT_OFF, /* asynchronous commit */ + SYNCHRONOUS_COMMIT_LOCAL_FLUSH, /* wait for local flush only */ + SYNCHRONOUS_COMMIT_REMOTE_WRITE, /* wait for local flush and remote + * write */ + SYNCHRONOUS_COMMIT_REMOTE_FLUSH, /* wait for local and remote flush */ + SYNCHRONOUS_COMMIT_REMOTE_APPLY /* wait for local and remote flush and + * remote apply */ +} SyncCommitLevel; + +/* Define the default setting for synchronous_commit */ +#define SYNCHRONOUS_COMMIT_ON SYNCHRONOUS_COMMIT_REMOTE_FLUSH + +/* Synchronous commit level */ +extern PGDLLIMPORT int synchronous_commit; + +/* used during logical streaming of a transaction */ +extern PGDLLIMPORT TransactionId CheckXidAlive; +extern PGDLLIMPORT bool bsysscan; + +/* + * Miscellaneous flag bits to record events which occur on the top level + * transaction. These flags are only persisted in MyXactFlags and are intended + * so we remember to do certain things later in the transaction. This is + * globally accessible, so can be set from anywhere in the code which requires + * recording flags. + */ +extern PGDLLIMPORT int MyXactFlags; + +/* + * XACT_FLAGS_ACCESSEDTEMPNAMESPACE - set when a temporary object is accessed. + * We don't allow PREPARE TRANSACTION in that case. + */ +#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE (1U << 0) + +/* + * XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK - records whether the top level xact + * logged any Access Exclusive Locks. + */ +#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK (1U << 1) + +/* + * XACT_FLAGS_NEEDIMMEDIATECOMMIT - records whether the top level statement + * is one that requires immediate commit, such as CREATE DATABASE. + */ +#define XACT_FLAGS_NEEDIMMEDIATECOMMIT (1U << 2) + +/* + * XACT_FLAGS_PIPELINING - set when we complete an extended-query-protocol + * Execute message. This is useful for detecting that an implicit transaction + * block has been created via pipelining. + */ +#define XACT_FLAGS_PIPELINING (1U << 3) + +/* + * start- and end-of-transaction callbacks for dynamically loaded modules + */ +typedef enum +{ + XACT_EVENT_COMMIT, + XACT_EVENT_PARALLEL_COMMIT, + XACT_EVENT_ABORT, + XACT_EVENT_PARALLEL_ABORT, + XACT_EVENT_PREPARE, + XACT_EVENT_PRE_COMMIT, + XACT_EVENT_PARALLEL_PRE_COMMIT, + XACT_EVENT_PRE_PREPARE +} XactEvent; + +typedef void (*XactCallback) (XactEvent event, void *arg); + +typedef enum +{ + SUBXACT_EVENT_START_SUB, + SUBXACT_EVENT_COMMIT_SUB, + SUBXACT_EVENT_ABORT_SUB, + SUBXACT_EVENT_PRE_COMMIT_SUB +} SubXactEvent; + +typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid, + SubTransactionId parentSubid, void *arg); + +/* Data structure for Save/RestoreTransactionCharacteristics */ +typedef struct SavedTransactionCharacteristics +{ + int save_XactIsoLevel; + bool save_XactReadOnly; + bool save_XactDeferrable; +} SavedTransactionCharacteristics; + + +/* ---------------- + * transaction-related XLOG entries + * ---------------- + */ + +/* + * XLOG allows to store some information in high 4 bits of log record xl_info + * field. We use 3 for the opcode, and one about an optional flag variable. + */ +#define XLOG_XACT_COMMIT 0x00 +#define XLOG_XACT_PREPARE 0x10 +#define XLOG_XACT_ABORT 0x20 +#define XLOG_XACT_COMMIT_PREPARED 0x30 +#define XLOG_XACT_ABORT_PREPARED 0x40 +#define XLOG_XACT_ASSIGNMENT 0x50 +#define XLOG_XACT_INVALIDATIONS 0x60 +/* free opcode 0x70 */ + +/* mask for filtering opcodes out of xl_info */ +#define XLOG_XACT_OPMASK 0x70 + +/* does this record have a 'xinfo' field or not */ +#define XLOG_XACT_HAS_INFO 0x80 + +/* + * The following flags, stored in xinfo, determine which information is + * contained in commit/abort records. + */ +#define XACT_XINFO_HAS_DBINFO (1U << 0) +#define XACT_XINFO_HAS_SUBXACTS (1U << 1) +#define XACT_XINFO_HAS_RELFILENODES (1U << 2) +#define XACT_XINFO_HAS_INVALS (1U << 3) +#define XACT_XINFO_HAS_TWOPHASE (1U << 4) +#define XACT_XINFO_HAS_ORIGIN (1U << 5) +#define XACT_XINFO_HAS_AE_LOCKS (1U << 6) +#define XACT_XINFO_HAS_GID (1U << 7) +#define XACT_XINFO_HAS_DROPPED_STATS (1U << 8) + +/* + * Also stored in xinfo, these indicating a variety of additional actions that + * need to occur when emulating transaction effects during recovery. + * + * They are named XactCompletion... to differentiate them from + * EOXact... routines which run at the end of the original transaction + * completion. + */ +#define XACT_COMPLETION_APPLY_FEEDBACK (1U << 29) +#define XACT_COMPLETION_UPDATE_RELCACHE_FILE (1U << 30) +#define XACT_COMPLETION_FORCE_SYNC_COMMIT (1U << 31) + +/* Access macros for above flags */ +#define XactCompletionApplyFeedback(xinfo) \ + ((xinfo & XACT_COMPLETION_APPLY_FEEDBACK) != 0) +#define XactCompletionRelcacheInitFileInval(xinfo) \ + ((xinfo & XACT_COMPLETION_UPDATE_RELCACHE_FILE) != 0) +#define XactCompletionForceSyncCommit(xinfo) \ + ((xinfo & XACT_COMPLETION_FORCE_SYNC_COMMIT) != 0) + +typedef struct xl_xact_assignment +{ + TransactionId xtop; /* assigned XID's top-level XID */ + int nsubxacts; /* number of subtransaction XIDs */ + TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */ +} xl_xact_assignment; + +#define MinSizeOfXactAssignment offsetof(xl_xact_assignment, xsub) + +/* + * Commit and abort records can contain a lot of information. But a large + * portion of the records won't need all possible pieces of information. So we + * only include what's needed. + * + * A minimal commit/abort record only consists of a xl_xact_commit/abort + * struct. The presence of additional information is indicated by bits set in + * 'xl_xact_xinfo->xinfo'. The presence of the xinfo field itself is signaled + * by a set XLOG_XACT_HAS_INFO bit in the xl_info field. + * + * NB: All the individual data chunks should be sized to multiples of + * sizeof(int) and only require int32 alignment. If they require bigger + * alignment, they need to be copied upon reading. + */ + +/* sub-records for commit/abort */ + +typedef struct xl_xact_xinfo +{ + /* + * Even though we right now only require two bytes of space in xinfo we + * use four so following records don't have to care about alignment. + * Commit records can be large, so copying large portions isn't + * attractive. + */ + uint32 xinfo; +} xl_xact_xinfo; + +typedef struct xl_xact_dbinfo +{ + Oid dbId; /* MyDatabaseId */ + Oid tsId; /* MyDatabaseTableSpace */ +} xl_xact_dbinfo; + +typedef struct xl_xact_subxacts +{ + int nsubxacts; /* number of subtransaction XIDs */ + TransactionId subxacts[FLEXIBLE_ARRAY_MEMBER]; +} xl_xact_subxacts; +#define MinSizeOfXactSubxacts offsetof(xl_xact_subxacts, subxacts) + +typedef struct xl_xact_relfilenodes +{ + int nrels; /* number of relations */ + RelFileNode xnodes[FLEXIBLE_ARRAY_MEMBER]; +} xl_xact_relfilenodes; +#define MinSizeOfXactRelfilenodes offsetof(xl_xact_relfilenodes, xnodes) + +/* + * A transactionally dropped statistics entry. + * + * Declared here rather than pgstat.h because pgstat.h can't be included from + * frontend code, but the WAL format needs to be readable by frontend + * programs. + */ +typedef struct xl_xact_stats_item +{ + int kind; + Oid dboid; + Oid objoid; +} xl_xact_stats_item; + +typedef struct xl_xact_stats_items +{ + int nitems; + xl_xact_stats_item items[FLEXIBLE_ARRAY_MEMBER]; +} xl_xact_stats_items; +#define MinSizeOfXactStatsItems offsetof(xl_xact_stats_items, items) + +typedef struct xl_xact_invals +{ + int nmsgs; /* number of shared inval msgs */ + SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER]; +} xl_xact_invals; +#define MinSizeOfXactInvals offsetof(xl_xact_invals, msgs) + +typedef struct xl_xact_twophase +{ + TransactionId xid; +} xl_xact_twophase; + +typedef struct xl_xact_origin +{ + XLogRecPtr origin_lsn; + TimestampTz origin_timestamp; +} xl_xact_origin; + +typedef struct xl_xact_commit +{ + TimestampTz xact_time; /* time of commit */ + + /* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */ + /* xl_xact_dbinfo follows if XINFO_HAS_DBINFO */ + /* xl_xact_subxacts follows if XINFO_HAS_SUBXACT */ + /* xl_xact_relfilenodes follows if XINFO_HAS_RELFILENODES */ + /* xl_xact_stats_items follows if XINFO_HAS_DROPPED_STATS */ + /* xl_xact_invals follows if XINFO_HAS_INVALS */ + /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */ + /* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */ + /* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */ +} xl_xact_commit; +#define MinSizeOfXactCommit (offsetof(xl_xact_commit, xact_time) + sizeof(TimestampTz)) + +typedef struct xl_xact_abort +{ + TimestampTz xact_time; /* time of abort */ + + /* xl_xact_xinfo follows if XLOG_XACT_HAS_INFO */ + /* xl_xact_dbinfo follows if XINFO_HAS_DBINFO */ + /* xl_xact_subxacts follows if XINFO_HAS_SUBXACT */ + /* xl_xact_relfilenodes follows if XINFO_HAS_RELFILENODES */ + /* xl_xact_stats_items follows if XINFO_HAS_DROPPED_STATS */ + /* No invalidation messages needed. */ + /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */ + /* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */ + /* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */ +} xl_xact_abort; +#define MinSizeOfXactAbort sizeof(xl_xact_abort) + +typedef struct xl_xact_prepare +{ + uint32 magic; /* format identifier */ + uint32 total_len; /* actual file length */ + TransactionId xid; /* original transaction XID */ + Oid database; /* OID of database it was in */ + TimestampTz prepared_at; /* time of preparation */ + Oid owner; /* user running the transaction */ + int32 nsubxacts; /* number of following subxact XIDs */ + int32 ncommitrels; /* number of delete-on-commit rels */ + int32 nabortrels; /* number of delete-on-abort rels */ + int32 ncommitstats; /* number of stats to drop on commit */ + int32 nabortstats; /* number of stats to drop on abort */ + int32 ninvalmsgs; /* number of cache invalidation messages */ + bool initfileinval; /* does relcache init file need invalidation? */ + uint16 gidlen; /* length of the GID - GID follows the header */ + XLogRecPtr origin_lsn; /* lsn of this record at origin node */ + TimestampTz origin_timestamp; /* time of prepare at origin node */ +} xl_xact_prepare; + +/* + * Commit/Abort records in the above form are a bit verbose to parse, so + * there's a deconstructed versions generated by ParseCommit/AbortRecord() for + * easier consumption. + */ +typedef struct xl_xact_parsed_commit +{ + TimestampTz xact_time; + uint32 xinfo; + + Oid dbId; /* MyDatabaseId */ + Oid tsId; /* MyDatabaseTableSpace */ + + int nsubxacts; + TransactionId *subxacts; + + int nrels; + RelFileNode *xnodes; + + int nstats; + xl_xact_stats_item *stats; + + int nmsgs; + SharedInvalidationMessage *msgs; + + TransactionId twophase_xid; /* only for 2PC */ + char twophase_gid[GIDSIZE]; /* only for 2PC */ + int nabortrels; /* only for 2PC */ + RelFileNode *abortnodes; /* only for 2PC */ + int nabortstats; /* only for 2PC */ + xl_xact_stats_item *abortstats; /* only for 2PC */ + + XLogRecPtr origin_lsn; + TimestampTz origin_timestamp; +} xl_xact_parsed_commit; + +typedef xl_xact_parsed_commit xl_xact_parsed_prepare; + +typedef struct xl_xact_parsed_abort +{ + TimestampTz xact_time; + uint32 xinfo; + + Oid dbId; /* MyDatabaseId */ + Oid tsId; /* MyDatabaseTableSpace */ + + int nsubxacts; + TransactionId *subxacts; + + int nrels; + RelFileNode *xnodes; + + int nstats; + xl_xact_stats_item *stats; + + TransactionId twophase_xid; /* only for 2PC */ + char twophase_gid[GIDSIZE]; /* only for 2PC */ + + XLogRecPtr origin_lsn; + TimestampTz origin_timestamp; +} xl_xact_parsed_abort; + + +/* ---------------- + * extern definitions + * ---------------- + */ +extern bool IsTransactionState(void); +extern bool IsAbortedTransactionBlockState(void); +extern TransactionId GetTopTransactionId(void); +extern TransactionId GetTopTransactionIdIfAny(void); +extern TransactionId GetCurrentTransactionId(void); +extern TransactionId GetCurrentTransactionIdIfAny(void); +extern TransactionId GetStableLatestTransactionId(void); +extern SubTransactionId GetCurrentSubTransactionId(void); +extern FullTransactionId GetTopFullTransactionId(void); +extern FullTransactionId GetTopFullTransactionIdIfAny(void); +extern FullTransactionId GetCurrentFullTransactionId(void); +extern FullTransactionId GetCurrentFullTransactionIdIfAny(void); +extern void MarkCurrentTransactionIdLoggedIfAny(void); +extern bool SubTransactionIsActive(SubTransactionId subxid); +extern CommandId GetCurrentCommandId(bool used); +extern void SetParallelStartTimestamps(TimestampTz xact_ts, TimestampTz stmt_ts); +extern TimestampTz GetCurrentTransactionStartTimestamp(void); +extern TimestampTz GetCurrentStatementStartTimestamp(void); +extern TimestampTz GetCurrentTransactionStopTimestamp(void); +extern void SetCurrentStatementStartTimestamp(void); +extern int GetCurrentTransactionNestLevel(void); +extern bool TransactionIdIsCurrentTransactionId(TransactionId xid); +extern void CommandCounterIncrement(void); +extern void ForceSyncCommit(void); +extern void StartTransactionCommand(void); +extern void SaveTransactionCharacteristics(SavedTransactionCharacteristics *s); +extern void RestoreTransactionCharacteristics(const SavedTransactionCharacteristics *s); +extern void CommitTransactionCommand(void); +extern void AbortCurrentTransaction(void); +extern void BeginTransactionBlock(void); +extern bool EndTransactionBlock(bool chain); +extern bool PrepareTransactionBlock(const char *gid); +extern void UserAbortTransactionBlock(bool chain); +extern void BeginImplicitTransactionBlock(void); +extern void EndImplicitTransactionBlock(void); +extern void ReleaseSavepoint(const char *name); +extern void DefineSavepoint(const char *name); +extern void RollbackToSavepoint(const char *name); +extern void BeginInternalSubTransaction(const char *name); +extern void ReleaseCurrentSubTransaction(void); +extern void RollbackAndReleaseCurrentSubTransaction(void); +extern bool IsSubTransaction(void); +extern Size EstimateTransactionStateSpace(void); +extern void SerializeTransactionState(Size maxsize, char *start_address); +extern void StartParallelWorkerTransaction(char *tstatespace); +extern void EndParallelWorkerTransaction(void); +extern bool IsTransactionBlock(void); +extern bool IsTransactionOrTransactionBlock(void); +extern char TransactionBlockStatusCode(void); +extern void AbortOutOfAnyTransaction(void); +extern void PreventInTransactionBlock(bool isTopLevel, const char *stmtType); +extern void RequireTransactionBlock(bool isTopLevel, const char *stmtType); +extern void WarnNoTransactionBlock(bool isTopLevel, const char *stmtType); +extern bool IsInTransactionBlock(bool isTopLevel); +extern void RegisterXactCallback(XactCallback callback, void *arg); +extern void UnregisterXactCallback(XactCallback callback, void *arg); +extern void RegisterSubXactCallback(SubXactCallback callback, void *arg); +extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg); + +extern bool IsSubxactTopXidLogPending(void); +extern void MarkSubxactTopXidLogged(void); + +extern int xactGetCommittedChildren(TransactionId **ptr); + +extern XLogRecPtr XactLogCommitRecord(TimestampTz commit_time, + int nsubxacts, TransactionId *subxacts, + int nrels, RelFileNode *rels, + int nstats, + xl_xact_stats_item *stats, + int nmsgs, SharedInvalidationMessage *msgs, + bool relcacheInval, + int xactflags, + TransactionId twophase_xid, + const char *twophase_gid); + +extern XLogRecPtr XactLogAbortRecord(TimestampTz abort_time, + int nsubxacts, TransactionId *subxacts, + int nrels, RelFileNode *rels, + int nstats, + xl_xact_stats_item *stats, + int xactflags, TransactionId twophase_xid, + const char *twophase_gid); +extern void xact_redo(XLogReaderState *record); + +/* xactdesc.c */ +extern void xact_desc(StringInfo buf, XLogReaderState *record); +extern const char *xact_identify(uint8 info); + +/* also in xactdesc.c, so they can be shared between front/backend code */ +extern void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed); +extern void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed); +extern void ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parsed_prepare *parsed); + +extern void EnterParallelMode(void); +extern void ExitParallelMode(void); +extern bool IsInParallelMode(void); + +#endif /* XACT_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h new file mode 100644 index 0000000..cd674c3 --- /dev/null +++ b/src/include/access/xlog.h @@ -0,0 +1,303 @@ +/* + * xlog.h + * + * PostgreSQL write-ahead log manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlog.h + */ +#ifndef XLOG_H +#define XLOG_H + +#include "access/xlogdefs.h" +#include "access/xlogreader.h" +#include "datatype/timestamp.h" +#include "lib/stringinfo.h" +#include "nodes/pg_list.h" + + +/* Sync methods */ +#define SYNC_METHOD_FSYNC 0 +#define SYNC_METHOD_FDATASYNC 1 +#define SYNC_METHOD_OPEN 2 /* for O_SYNC */ +#define SYNC_METHOD_FSYNC_WRITETHROUGH 3 +#define SYNC_METHOD_OPEN_DSYNC 4 /* for O_DSYNC */ +extern PGDLLIMPORT int sync_method; + +extern PGDLLIMPORT XLogRecPtr ProcLastRecPtr; +extern PGDLLIMPORT XLogRecPtr XactLastRecEnd; +extern PGDLLIMPORT XLogRecPtr XactLastCommitEnd; + +/* these variables are GUC parameters related to XLOG */ +extern PGDLLIMPORT int wal_segment_size; +extern PGDLLIMPORT int min_wal_size_mb; +extern PGDLLIMPORT int max_wal_size_mb; +extern PGDLLIMPORT int wal_keep_size_mb; +extern PGDLLIMPORT int max_slot_wal_keep_size_mb; +extern PGDLLIMPORT int XLOGbuffers; +extern PGDLLIMPORT int XLogArchiveTimeout; +extern PGDLLIMPORT int wal_retrieve_retry_interval; +extern PGDLLIMPORT char *XLogArchiveCommand; +extern PGDLLIMPORT bool EnableHotStandby; +extern PGDLLIMPORT bool fullPageWrites; +extern PGDLLIMPORT bool wal_log_hints; +extern PGDLLIMPORT int wal_compression; +extern PGDLLIMPORT bool wal_init_zero; +extern PGDLLIMPORT bool wal_recycle; +extern PGDLLIMPORT bool *wal_consistency_checking; +extern PGDLLIMPORT char *wal_consistency_checking_string; +extern PGDLLIMPORT bool log_checkpoints; +extern PGDLLIMPORT bool track_wal_io_timing; +extern PGDLLIMPORT int wal_decode_buffer_size; + +extern PGDLLIMPORT int CheckPointSegments; + +/* Archive modes */ +typedef enum ArchiveMode +{ + ARCHIVE_MODE_OFF = 0, /* disabled */ + ARCHIVE_MODE_ON, /* enabled while server is running normally */ + ARCHIVE_MODE_ALWAYS /* enabled always (even during recovery) */ +} ArchiveMode; +extern PGDLLIMPORT int XLogArchiveMode; + +/* WAL levels */ +typedef enum WalLevel +{ + WAL_LEVEL_MINIMAL = 0, + WAL_LEVEL_REPLICA, + WAL_LEVEL_LOGICAL +} WalLevel; + +/* Compression algorithms for WAL */ +typedef enum WalCompression +{ + WAL_COMPRESSION_NONE = 0, + WAL_COMPRESSION_PGLZ, + WAL_COMPRESSION_LZ4, + WAL_COMPRESSION_ZSTD +} WalCompression; + +/* Recovery states */ +typedef enum RecoveryState +{ + RECOVERY_STATE_CRASH = 0, /* crash recovery */ + RECOVERY_STATE_ARCHIVE, /* archive recovery */ + RECOVERY_STATE_DONE /* currently in production */ +} RecoveryState; + +extern PGDLLIMPORT int wal_level; + +/* Is WAL archiving enabled (always or only while server is running normally)? */ +#define XLogArchivingActive() \ + (AssertMacro(XLogArchiveMode == ARCHIVE_MODE_OFF || wal_level >= WAL_LEVEL_REPLICA), XLogArchiveMode > ARCHIVE_MODE_OFF) +/* Is WAL archiving enabled always (even during recovery)? */ +#define XLogArchivingAlways() \ + (AssertMacro(XLogArchiveMode == ARCHIVE_MODE_OFF || wal_level >= WAL_LEVEL_REPLICA), XLogArchiveMode == ARCHIVE_MODE_ALWAYS) + +/* + * Is WAL-logging necessary for archival or log-shipping, or can we skip + * WAL-logging if we fsync() the data before committing instead? + */ +#define XLogIsNeeded() (wal_level >= WAL_LEVEL_REPLICA) + +/* + * Is a full-page image needed for hint bit updates? + * + * Normally, we don't WAL-log hint bit updates, but if checksums are enabled, + * we have to protect them against torn page writes. When you only set + * individual bits on a page, it's still consistent no matter what combination + * of the bits make it to disk, but the checksum wouldn't match. Also WAL-log + * them if forced by wal_log_hints=on. + */ +#define XLogHintBitIsNeeded() (DataChecksumsEnabled() || wal_log_hints) + +/* Do we need to WAL-log information required only for Hot Standby and logical replication? */ +#define XLogStandbyInfoActive() (wal_level >= WAL_LEVEL_REPLICA) + +/* Do we need to WAL-log information required only for logical replication? */ +#define XLogLogicalInfoActive() (wal_level >= WAL_LEVEL_LOGICAL) + +#ifdef WAL_DEBUG +extern PGDLLIMPORT bool XLOG_DEBUG; +#endif + +/* + * OR-able request flag bits for checkpoints. The "cause" bits are used only + * for logging purposes. Note: the flags must be defined so that it's + * sensible to OR together request flags arising from different requestors. + */ + +/* These directly affect the behavior of CreateCheckPoint and subsidiaries */ +#define CHECKPOINT_IS_SHUTDOWN 0x0001 /* Checkpoint is for shutdown */ +#define CHECKPOINT_END_OF_RECOVERY 0x0002 /* Like shutdown checkpoint, but + * issued at end of WAL recovery */ +#define CHECKPOINT_IMMEDIATE 0x0004 /* Do it without delays */ +#define CHECKPOINT_FORCE 0x0008 /* Force even if no activity */ +#define CHECKPOINT_FLUSH_ALL 0x0010 /* Flush all pages, including those + * belonging to unlogged tables */ +/* These are important to RequestCheckpoint */ +#define CHECKPOINT_WAIT 0x0020 /* Wait for completion */ +#define CHECKPOINT_REQUESTED 0x0040 /* Checkpoint request has been made */ +/* These indicate the cause of a checkpoint request */ +#define CHECKPOINT_CAUSE_XLOG 0x0080 /* XLOG consumption */ +#define CHECKPOINT_CAUSE_TIME 0x0100 /* Elapsed time */ + +/* + * Flag bits for the record being inserted, set using XLogSetRecordFlags(). + */ +#define XLOG_INCLUDE_ORIGIN 0x01 /* include the replication origin */ +#define XLOG_MARK_UNIMPORTANT 0x02 /* record not important for durability */ + + +/* Checkpoint statistics */ +typedef struct CheckpointStatsData +{ + TimestampTz ckpt_start_t; /* start of checkpoint */ + TimestampTz ckpt_write_t; /* start of flushing buffers */ + TimestampTz ckpt_sync_t; /* start of fsyncs */ + TimestampTz ckpt_sync_end_t; /* end of fsyncs */ + TimestampTz ckpt_end_t; /* end of checkpoint */ + + int ckpt_bufs_written; /* # of buffers written */ + + int ckpt_segs_added; /* # of new xlog segments created */ + int ckpt_segs_removed; /* # of xlog segments deleted */ + int ckpt_segs_recycled; /* # of xlog segments recycled */ + + int ckpt_sync_rels; /* # of relations synced */ + uint64 ckpt_longest_sync; /* Longest sync for one relation */ + uint64 ckpt_agg_sync_time; /* The sum of all the individual sync + * times, which is not necessarily the + * same as the total elapsed time for the + * entire sync phase. */ +} CheckpointStatsData; + +extern PGDLLIMPORT CheckpointStatsData CheckpointStats; + +/* + * GetWALAvailability return codes + */ +typedef enum WALAvailability +{ + WALAVAIL_INVALID_LSN, /* parameter error */ + WALAVAIL_RESERVED, /* WAL segment is within max_wal_size */ + WALAVAIL_EXTENDED, /* WAL segment is reserved by a slot or + * wal_keep_size */ + WALAVAIL_UNRESERVED, /* no longer reserved, but not removed yet */ + WALAVAIL_REMOVED /* WAL segment has been removed */ +} WALAvailability; + +struct XLogRecData; + +extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, + XLogRecPtr fpw_lsn, + uint8 flags, + int num_fpi, + bool topxid_included); +extern void XLogFlush(XLogRecPtr RecPtr); +extern bool XLogBackgroundFlush(void); +extern bool XLogNeedsFlush(XLogRecPtr RecPtr); +extern int XLogFileInit(XLogSegNo segno, TimeLineID tli); +extern int XLogFileOpen(XLogSegNo segno, TimeLineID tli); + +extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli); +extern XLogSegNo XLogGetLastRemovedSegno(void); +extern void XLogSetAsyncXactLSN(XLogRecPtr record); +extern void XLogSetReplicationSlotMinimumLSN(XLogRecPtr lsn); + +extern void xlog_redo(XLogReaderState *record); +extern void xlog_desc(StringInfo buf, XLogReaderState *record); +extern const char *xlog_identify(uint8 info); + +extern void issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli); + +extern bool RecoveryInProgress(void); +extern RecoveryState GetRecoveryState(void); +extern bool XLogInsertAllowed(void); +extern XLogRecPtr GetXLogInsertRecPtr(void); +extern XLogRecPtr GetXLogWriteRecPtr(void); + +extern uint64 GetSystemIdentifier(void); +extern char *GetMockAuthenticationNonce(void); +extern bool DataChecksumsEnabled(void); +extern XLogRecPtr GetFakeLSNForUnloggedRel(void); +extern Size XLOGShmemSize(void); +extern void XLOGShmemInit(void); +extern void BootStrapXLOG(void); +extern void LocalProcessControlFile(bool reset); +extern void StartupXLOG(void); +extern void ShutdownXLOG(int code, Datum arg); +extern void CreateCheckPoint(int flags); +extern bool CreateRestartPoint(int flags); +extern WALAvailability GetWALAvailability(XLogRecPtr targetLSN); +extern void XLogPutNextOid(Oid nextOid); +extern XLogRecPtr XLogRestorePoint(const char *rpName); +extern void UpdateFullPageWrites(void); +extern void GetFullPageWriteInfo(XLogRecPtr *RedoRecPtr_p, bool *doPageWrites_p); +extern XLogRecPtr GetRedoRecPtr(void); +extern XLogRecPtr GetInsertRecPtr(void); +extern XLogRecPtr GetFlushRecPtr(TimeLineID *insertTLI); +extern TimeLineID GetWALInsertionTimeLine(void); +extern XLogRecPtr GetLastImportantRecPtr(void); + +extern void SetWalWriterSleeping(bool sleeping); + +extern void assign_max_wal_size(int newval, void *extra); +extern void assign_checkpoint_completion_target(double newval, void *extra); + +/* + * Routines used by xlogrecovery.c to call back into xlog.c during recovery. + */ +extern void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI); +extern bool XLogCheckpointNeeded(XLogSegNo new_segno); +extern void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI); +extern void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli); +extern void SetInstallXLogFileSegmentActive(void); +extern bool IsInstallXLogFileSegmentActive(void); +extern void XLogShutdownWalRcv(void); + +/* + * Routines to start, stop, and get status of a base backup. + */ + +/* + * Session-level status of base backups + * + * This is used in parallel with the shared memory status to control parallel + * execution of base backup functions for a given session, be it a backend + * dedicated to replication or a normal backend connected to a database. The + * update of the session-level status happens at the same time as the shared + * memory counters to keep a consistent global and local state of the backups + * running. + */ +typedef enum SessionBackupState +{ + SESSION_BACKUP_NONE, + SESSION_BACKUP_RUNNING, +} SessionBackupState; + +extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast, + TimeLineID *starttli_p, StringInfo labelfile, + List **tablespaces, StringInfo tblspcmapfile); +extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive, + TimeLineID *stoptli_p); +extern void do_pg_abort_backup(int code, Datum arg); +extern void register_persistent_abort_backup_handler(void); +extern SessionBackupState get_backup_status(void); + +/* File path names (all relative to $PGDATA) */ +#define RECOVERY_SIGNAL_FILE "recovery.signal" +#define STANDBY_SIGNAL_FILE "standby.signal" +#define BACKUP_LABEL_FILE "backup_label" +#define BACKUP_LABEL_OLD "backup_label.old" + +#define TABLESPACE_MAP "tablespace_map" +#define TABLESPACE_MAP_OLD "tablespace_map.old" + +/* files to signal promotion to primary */ +#define PROMOTE_SIGNAL_FILE "promote" + +#endif /* XLOG_H */ diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h new file mode 100644 index 0000000..fae0bef --- /dev/null +++ b/src/include/access/xlog_internal.h @@ -0,0 +1,366 @@ +/* + * xlog_internal.h + * + * PostgreSQL write-ahead log internal declarations + * + * NOTE: this file is intended to contain declarations useful for + * manipulating the XLOG files directly, but it is not supposed to be + * needed by rmgr routines (redo support for individual record types). + * So the XLogRecord typedef and associated stuff appear in xlogrecord.h. + * + * Note: This file must be includable in both frontend and backend contexts, + * to allow stand-alone tools like pg_receivewal to deal with WAL files. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlog_internal.h + */ +#ifndef XLOG_INTERNAL_H +#define XLOG_INTERNAL_H + +#include "access/xlogdefs.h" +#include "access/xlogreader.h" +#include "datatype/timestamp.h" +#include "lib/stringinfo.h" +#include "pgtime.h" +#include "storage/block.h" +#include "storage/relfilenode.h" + + +/* + * Each page of XLOG file has a header like this: + */ +#define XLOG_PAGE_MAGIC 0xD110 /* can be used as WAL version indicator */ + +typedef struct XLogPageHeaderData +{ + uint16 xlp_magic; /* magic value for correctness checks */ + uint16 xlp_info; /* flag bits, see below */ + TimeLineID xlp_tli; /* TimeLineID of first record on page */ + XLogRecPtr xlp_pageaddr; /* XLOG address of this page */ + + /* + * When there is not enough space on current page for whole record, we + * continue on the next page. xlp_rem_len is the number of bytes + * remaining from a previous page; it tracks xl_tot_len in the initial + * header. Note that the continuation data isn't necessarily aligned. + */ + uint32 xlp_rem_len; /* total len of remaining data for record */ +} XLogPageHeaderData; + +#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData)) + +typedef XLogPageHeaderData *XLogPageHeader; + +/* + * When the XLP_LONG_HEADER flag is set, we store additional fields in the + * page header. (This is ordinarily done just in the first page of an + * XLOG file.) The additional fields serve to identify the file accurately. + */ +typedef struct XLogLongPageHeaderData +{ + XLogPageHeaderData std; /* standard header fields */ + uint64 xlp_sysid; /* system identifier from pg_control */ + uint32 xlp_seg_size; /* just as a cross-check */ + uint32 xlp_xlog_blcksz; /* just as a cross-check */ +} XLogLongPageHeaderData; + +#define SizeOfXLogLongPHD MAXALIGN(sizeof(XLogLongPageHeaderData)) + +typedef XLogLongPageHeaderData *XLogLongPageHeader; + +/* When record crosses page boundary, set this flag in new page's header */ +#define XLP_FIRST_IS_CONTRECORD 0x0001 +/* This flag indicates a "long" page header */ +#define XLP_LONG_HEADER 0x0002 +/* This flag indicates backup blocks starting in this page are optional */ +#define XLP_BKP_REMOVABLE 0x0004 +/* Replaces a missing contrecord; see CreateOverwriteContrecordRecord */ +#define XLP_FIRST_IS_OVERWRITE_CONTRECORD 0x0008 +/* All defined flag bits in xlp_info (used for validity checking of header) */ +#define XLP_ALL_FLAGS 0x000F + +#define XLogPageHeaderSize(hdr) \ + (((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD) + +/* wal_segment_size can range from 1MB to 1GB */ +#define WalSegMinSize 1024 * 1024 +#define WalSegMaxSize 1024 * 1024 * 1024 +/* default number of min and max wal segments */ +#define DEFAULT_MIN_WAL_SEGS 5 +#define DEFAULT_MAX_WAL_SEGS 64 + +/* check that the given size is a valid wal_segment_size */ +#define IsPowerOf2(x) (x > 0 && ((x) & ((x)-1)) == 0) +#define IsValidWalSegSize(size) \ + (IsPowerOf2(size) && \ + ((size) >= WalSegMinSize && (size) <= WalSegMaxSize)) + +#define XLogSegmentsPerXLogId(wal_segsz_bytes) \ + (UINT64CONST(0x100000000) / (wal_segsz_bytes)) + +#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest) \ + (dest) = (segno) * (wal_segsz_bytes) + (offset) + +#define XLogSegmentOffset(xlogptr, wal_segsz_bytes) \ + ((xlogptr) & ((wal_segsz_bytes) - 1)) + +/* + * Compute a segment number from an XLogRecPtr. + * + * For XLByteToSeg, do the computation at face value. For XLByteToPrevSeg, + * a boundary byte is taken to be in the previous segment. This is suitable + * for deciding which segment to write given a pointer to a record end, + * for example. + */ +#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes) \ + logSegNo = (xlrp) / (wal_segsz_bytes) + +#define XLByteToPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \ + logSegNo = ((xlrp) - 1) / (wal_segsz_bytes) + +/* + * Convert values of GUCs measured in megabytes to equiv. segment count. + * Rounds down. + */ +#define XLogMBVarToSegs(mbvar, wal_segsz_bytes) \ + ((mbvar) / ((wal_segsz_bytes) / (1024 * 1024))) + +/* + * Is an XLogRecPtr within a particular XLOG segment? + * + * For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg, + * a boundary byte is taken to be in the previous segment. + */ +#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes) \ + (((xlrp) / (wal_segsz_bytes)) == (logSegNo)) + +#define XLByteInPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \ + ((((xlrp) - 1) / (wal_segsz_bytes)) == (logSegNo)) + +/* Check if an XLogRecPtr value is in a plausible range */ +#define XRecOffIsValid(xlrp) \ + ((xlrp) % XLOG_BLCKSZ >= SizeOfXLogShortPHD) + +/* + * The XLog directory and control file (relative to $PGDATA) + */ +#define XLOGDIR "pg_wal" +#define XLOG_CONTROL_FILE "global/pg_control" + +/* + * These macros encapsulate knowledge about the exact layout of XLog file + * names, timeline history file names, and archive-status file names. + */ +#define MAXFNAMELEN 64 + +/* Length of XLog file name */ +#define XLOG_FNAME_LEN 24 + +/* + * Generate a WAL segment file name. Do not use this macro in a helper + * function allocating the result generated. + */ +#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes) \ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \ + (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes))) + +#define XLogFileNameById(fname, tli, log, seg) \ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg) + +#define IsXLogFileName(fname) \ + (strlen(fname) == XLOG_FNAME_LEN && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN) + +/* + * XLOG segment with .partial suffix. Used by pg_receivewal and at end of + * archive recovery, when we want to archive a WAL segment but it might not + * be complete yet. + */ +#define IsPartialXLogFileName(fname) \ + (strlen(fname) == XLOG_FNAME_LEN + strlen(".partial") && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ + strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0) + +#define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes) \ + do { \ + uint32 log; \ + uint32 seg; \ + sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \ + *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; \ + } while (0) + +#define XLogFilePath(path, tli, logSegNo, wal_segsz_bytes) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \ + (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes))) + +#define TLHistoryFileName(fname, tli) \ + snprintf(fname, MAXFNAMELEN, "%08X.history", tli) + +#define IsTLHistoryFileName(fname) \ + (strlen(fname) == 8 + strlen(".history") && \ + strspn(fname, "0123456789ABCDEF") == 8 && \ + strcmp((fname) + 8, ".history") == 0) + +#define TLHistoryFilePath(path, tli) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli) + +#define StatusFilePath(path, xlog, suffix) \ + snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) + +#define BackupHistoryFileName(fname, tli, logSegNo, startpoint, wal_segsz_bytes) \ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \ + (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes))) + +#define IsBackupHistoryFileName(fname) \ + (strlen(fname) > XLOG_FNAME_LEN && \ + strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ + strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0) + +#define BackupHistoryFilePath(path, tli, logSegNo, startpoint, wal_segsz_bytes) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \ + (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \ + (uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes))) + +/* + * Information logged when we detect a change in one of the parameters + * important for Hot Standby. + */ +typedef struct xl_parameter_change +{ + int MaxConnections; + int max_worker_processes; + int max_wal_senders; + int max_prepared_xacts; + int max_locks_per_xact; + int wal_level; + bool wal_log_hints; + bool track_commit_timestamp; +} xl_parameter_change; + +/* logs restore point */ +typedef struct xl_restore_point +{ + TimestampTz rp_time; + char rp_name[MAXFNAMELEN]; +} xl_restore_point; + +/* Overwrite of prior contrecord */ +typedef struct xl_overwrite_contrecord +{ + XLogRecPtr overwritten_lsn; + TimestampTz overwrite_time; +} xl_overwrite_contrecord; + +/* End of recovery mark, when we don't do an END_OF_RECOVERY checkpoint */ +typedef struct xl_end_of_recovery +{ + TimestampTz end_time; + TimeLineID ThisTimeLineID; /* new TLI */ + TimeLineID PrevTimeLineID; /* previous TLI we forked off from */ +} xl_end_of_recovery; + +/* + * The functions in xloginsert.c construct a chain of XLogRecData structs + * to represent the final WAL record. + */ +typedef struct XLogRecData +{ + struct XLogRecData *next; /* next struct in chain, or NULL */ + char *data; /* start of rmgr data to include */ + uint32 len; /* length of rmgr data to include */ +} XLogRecData; + +/* + * Recovery target action. + */ +typedef enum +{ + RECOVERY_TARGET_ACTION_PAUSE, + RECOVERY_TARGET_ACTION_PROMOTE, + RECOVERY_TARGET_ACTION_SHUTDOWN +} RecoveryTargetAction; + +struct LogicalDecodingContext; +struct XLogRecordBuffer; + +/* + * Method table for resource managers. + * + * This struct must be kept in sync with the PG_RMGR definition in + * rmgr.c. + * + * rm_identify must return a name for the record based on xl_info (without + * reference to the rmid). For example, XLOG_BTREE_VACUUM would be named + * "VACUUM". rm_desc can then be called to obtain additional detail for the + * record, if available (e.g. the last block). + * + * rm_mask takes as input a page modified by the resource manager and masks + * out bits that shouldn't be flagged by wal_consistency_checking. + * + * RmgrTable[] is indexed by RmgrId values (see rmgrlist.h). If rm_name is + * NULL, the corresponding RmgrTable entry is considered invalid. + */ +typedef struct RmgrData +{ + const char *rm_name; + void (*rm_redo) (XLogReaderState *record); + void (*rm_desc) (StringInfo buf, XLogReaderState *record); + const char *(*rm_identify) (uint8 info); + void (*rm_startup) (void); + void (*rm_cleanup) (void); + void (*rm_mask) (char *pagedata, BlockNumber blkno); + void (*rm_decode) (struct LogicalDecodingContext *ctx, + struct XLogRecordBuffer *buf); +} RmgrData; + +extern PGDLLIMPORT RmgrData RmgrTable[]; +extern void RmgrStartup(void); +extern void RmgrCleanup(void); +extern void RmgrNotFound(RmgrId rmid); +extern void RegisterCustomRmgr(RmgrId rmid, RmgrData *rmgr); + +#ifndef FRONTEND +static inline bool +RmgrIdExists(RmgrId rmid) +{ + return RmgrTable[rmid].rm_name != NULL; +} + +static inline RmgrData +GetRmgr(RmgrId rmid) +{ + if (unlikely(!RmgrIdExists(rmid))) + RmgrNotFound(rmid); + return RmgrTable[rmid]; +} +#endif + +/* + * Exported to support xlog switching from checkpointer + */ +extern pg_time_t GetLastSegSwitchData(XLogRecPtr *lastSwitchLSN); +extern XLogRecPtr RequestXLogSwitch(bool mark_unimportant); + +extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli); + +extern void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, + bool detailed_format, StringInfo buf, + uint32 *fpi_len); + +/* + * Exported for the functions in timeline.c and xlogarchive.c. Only valid + * in the startup process. + */ +extern PGDLLIMPORT bool ArchiveRecoveryRequested; +extern PGDLLIMPORT bool InArchiveRecovery; +extern PGDLLIMPORT bool StandbyMode; +extern PGDLLIMPORT char *recoveryRestoreCommand; + +#endif /* XLOG_INTERNAL_H */ diff --git a/src/include/access/xlogarchive.h b/src/include/access/xlogarchive.h new file mode 100644 index 0000000..f47b219 --- /dev/null +++ b/src/include/access/xlogarchive.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------ + * + * xlogarchive.h + * Prototypes for WAL archives in the backend + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/xlogarchive.h + * + *------------------------------------------------------------------------ + */ + +#ifndef XLOG_ARCHIVE_H +#define XLOG_ARCHIVE_H + +#include "access/xlogdefs.h" + +extern bool RestoreArchivedFile(char *path, const char *xlogfname, + const char *recovername, off_t expectedSize, + bool cleanupEnabled); +extern void ExecuteRecoveryCommand(const char *command, const char *commandName, + bool failOnSignal, uint32 wait_event_info); +extern void KeepFileRestoredFromArchive(const char *path, const char *xlogfname); +extern void XLogArchiveNotify(const char *xlog); +extern void XLogArchiveNotifySeg(XLogSegNo segno, TimeLineID tli); +extern void XLogArchiveForceDone(const char *xlog); +extern bool XLogArchiveCheckDone(const char *xlog); +extern bool XLogArchiveIsBusy(const char *xlog); +extern bool XLogArchiveIsReady(const char *xlog); +extern bool XLogArchiveIsReadyOrDone(const char *xlog); +extern void XLogArchiveCleanup(const char *xlog); + +#endif /* XLOG_ARCHIVE_H */ diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h new file mode 100644 index 0000000..a47e3ee --- /dev/null +++ b/src/include/access/xlogdefs.h @@ -0,0 +1,101 @@ +/* + * xlogdefs.h + * + * Postgres write-ahead log manager record pointer and + * timeline number definitions + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogdefs.h + */ +#ifndef XLOG_DEFS_H +#define XLOG_DEFS_H + +#include <fcntl.h> /* need open() flags */ + +/* + * Pointer to a location in the XLOG. These pointers are 64 bits wide, + * because we don't want them ever to overflow. + */ +typedef uint64 XLogRecPtr; + +/* + * Zero is used indicate an invalid pointer. Bootstrap skips the first possible + * WAL segment, initializing the first WAL page at WAL segment size, so no XLOG + * record can begin at zero. + */ +#define InvalidXLogRecPtr 0 +#define XLogRecPtrIsInvalid(r) ((r) == InvalidXLogRecPtr) + +/* + * First LSN to use for "fake" LSNs. + * + * Values smaller than this can be used for special per-AM purposes. + */ +#define FirstNormalUnloggedLSN ((XLogRecPtr) 1000) + +/* + * Handy macro for printing XLogRecPtr in conventional format, e.g., + * + * printf("%X/%X", LSN_FORMAT_ARGS(lsn)); + */ +#define LSN_FORMAT_ARGS(lsn) (AssertVariableIsOfTypeMacro((lsn), XLogRecPtr), (uint32) ((lsn) >> 32)), ((uint32) (lsn)) + +/* + * XLogSegNo - physical log file sequence number. + */ +typedef uint64 XLogSegNo; + +/* + * TimeLineID (TLI) - identifies different database histories to prevent + * confusion after restoring a prior state of a database installation. + * TLI does not change in a normal stop/restart of the database (including + * crash-and-recover cases); but we must assign a new TLI after doing + * a recovery to a prior state, a/k/a point-in-time recovery. This makes + * the new WAL logfile sequence we generate distinguishable from the + * sequence that was generated in the previous incarnation. + */ +typedef uint32 TimeLineID; + +/* + * Replication origin id - this is located in this file to avoid having to + * include origin.h in a bunch of xlog related places. + */ +typedef uint16 RepOriginId; + +/* + * This chunk of hackery attempts to determine which file sync methods + * are available on the current platform, and to choose an appropriate + * default method. We assume that fsync() is always available, and that + * configure determined whether fdatasync() is. + */ +#if defined(O_SYNC) +#define OPEN_SYNC_FLAG O_SYNC +#elif defined(O_FSYNC) +#define OPEN_SYNC_FLAG O_FSYNC +#endif + +#if defined(O_DSYNC) +#if defined(OPEN_SYNC_FLAG) +/* O_DSYNC is distinct? */ +#if O_DSYNC != OPEN_SYNC_FLAG +#define OPEN_DATASYNC_FLAG O_DSYNC +#endif +#else /* !defined(OPEN_SYNC_FLAG) */ +/* Win32 only has O_DSYNC */ +#define OPEN_DATASYNC_FLAG O_DSYNC +#endif +#endif + +#if defined(PLATFORM_DEFAULT_SYNC_METHOD) +#define DEFAULT_SYNC_METHOD PLATFORM_DEFAULT_SYNC_METHOD +#elif defined(OPEN_DATASYNC_FLAG) +#define DEFAULT_SYNC_METHOD SYNC_METHOD_OPEN_DSYNC +#elif defined(HAVE_FDATASYNC) +#define DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC +#else +#define DEFAULT_SYNC_METHOD SYNC_METHOD_FSYNC +#endif + +#endif /* XLOG_DEFS_H */ diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h new file mode 100644 index 0000000..5fc340c --- /dev/null +++ b/src/include/access/xloginsert.h @@ -0,0 +1,66 @@ +/* + * xloginsert.h + * + * Functions for generating WAL records + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xloginsert.h + */ +#ifndef XLOGINSERT_H +#define XLOGINSERT_H + +#include "access/rmgr.h" +#include "access/xlogdefs.h" +#include "storage/block.h" +#include "storage/buf.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + +/* + * The minimum size of the WAL construction working area. If you need to + * register more than XLR_NORMAL_MAX_BLOCK_ID block references or have more + * than XLR_NORMAL_RDATAS data chunks in a single WAL record, you must call + * XLogEnsureRecordSpace() first to allocate more working memory. + */ +#define XLR_NORMAL_MAX_BLOCK_ID 4 +#define XLR_NORMAL_RDATAS 20 + +/* flags for XLogRegisterBuffer */ +#define REGBUF_FORCE_IMAGE 0x01 /* force a full-page image */ +#define REGBUF_NO_IMAGE 0x02 /* don't take a full-page image */ +#define REGBUF_WILL_INIT (0x04 | 0x02) /* page will be re-initialized at + * replay (implies NO_IMAGE) */ +#define REGBUF_STANDARD 0x08 /* page follows "standard" page layout, + * (data between pd_lower and pd_upper + * will be skipped) */ +#define REGBUF_KEEP_DATA 0x10 /* include data even if a full-page image + * is taken */ + +/* prototypes for public functions in xloginsert.c: */ +extern void XLogBeginInsert(void); +extern void XLogSetRecordFlags(uint8 flags); +extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info); +extern void XLogEnsureRecordSpace(int max_block_id, int ndatas); +extern void XLogRegisterData(char *data, int len); +extern void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags); +extern void XLogRegisterBlock(uint8 block_id, RelFileNode *rnode, + ForkNumber forknum, BlockNumber blknum, char *page, + uint8 flags); +extern void XLogRegisterBufData(uint8 block_id, char *data, int len); +extern void XLogResetInsertion(void); +extern bool XLogCheckBufferNeedsBackup(Buffer buffer); + +extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, + BlockNumber blk, char *page, bool page_std); +extern void log_newpages(RelFileNode *rnode, ForkNumber forkNum, int num_pages, + BlockNumber *blknos, char **pages, bool page_std); +extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std); +extern void log_newpage_range(Relation rel, ForkNumber forkNum, + BlockNumber startblk, BlockNumber endblk, bool page_std); +extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std); + +extern void InitXLogInsert(void); + +#endif /* XLOGINSERT_H */ diff --git a/src/include/access/xlogprefetcher.h b/src/include/access/xlogprefetcher.h new file mode 100644 index 0000000..fdd67fc --- /dev/null +++ b/src/include/access/xlogprefetcher.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * xlogprefetcher.h + * Declarations for the recovery prefetching module. + * + * Portions Copyright (c) 2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/access/xlogprefetcher.h + *------------------------------------------------------------------------- + */ +#ifndef XLOGPREFETCHER_H +#define XLOGPREFETCHER_H + +#include "access/xlogdefs.h" +#include "access/xlogreader.h" +#include "access/xlogrecord.h" + +/* GUCs */ +extern PGDLLIMPORT int recovery_prefetch; + +/* Possible values for recovery_prefetch */ +typedef enum +{ + RECOVERY_PREFETCH_OFF, + RECOVERY_PREFETCH_ON, + RECOVERY_PREFETCH_TRY +} RecoveryPrefetchValue; + +struct XLogPrefetcher; +typedef struct XLogPrefetcher XLogPrefetcher; + + +extern void XLogPrefetchReconfigure(void); + +extern size_t XLogPrefetchShmemSize(void); +extern void XLogPrefetchShmemInit(void); + +extern void XLogPrefetchResetStats(void); + +extern XLogPrefetcher *XLogPrefetcherAllocate(XLogReaderState *reader); +extern void XLogPrefetcherFree(XLogPrefetcher *prefetcher); + +extern XLogReaderState *XLogPrefetcherGetReader(XLogPrefetcher *prefetcher); + +extern void XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, + XLogRecPtr recPtr); + +extern XLogRecord *XLogPrefetcherReadRecord(XLogPrefetcher *prefetcher, + char **errmsg); + +extern void XLogPrefetcherComputeStats(XLogPrefetcher *prefetcher); + +#endif diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h new file mode 100644 index 0000000..9e63162 --- /dev/null +++ b/src/include/access/xlogreader.h @@ -0,0 +1,443 @@ +/*------------------------------------------------------------------------- + * + * xlogreader.h + * Definitions for the generic XLog reading facility + * + * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/access/xlogreader.h + * + * NOTES + * See the definition of the XLogReaderState struct for instructions on + * how to use the XLogReader infrastructure. + * + * The basic idea is to allocate an XLogReaderState via + * XLogReaderAllocate(), position the reader to the first record with + * XLogBeginRead() or XLogFindNextRecord(), and call XLogReadRecord() + * until it returns NULL. + * + * Callers supply a page_read callback if they want to call + * XLogReadRecord or XLogFindNextRecord; it can be passed in as NULL + * otherwise. The WALRead function can be used as a helper to write + * page_read callbacks, but it is not mandatory; callers that use it, + * must supply segment_open callbacks. The segment_close callback + * must always be supplied. + * + * After reading a record with XLogReadRecord(), it's decomposed into + * the per-block and main data parts, and the parts can be accessed + * with the XLogRec* macros and functions. You can also decode a + * record that's already constructed in memory, without reading from + * disk, by calling the DecodeXLogRecord() function. + *------------------------------------------------------------------------- + */ +#ifndef XLOGREADER_H +#define XLOGREADER_H + +#ifndef FRONTEND +#include "access/transam.h" +#endif + +#include "access/xlogrecord.h" +#include "storage/buf.h" + +/* WALOpenSegment represents a WAL segment being read. */ +typedef struct WALOpenSegment +{ + int ws_file; /* segment file descriptor */ + XLogSegNo ws_segno; /* segment number */ + TimeLineID ws_tli; /* timeline ID of the currently open file */ +} WALOpenSegment; + +/* WALSegmentContext carries context information about WAL segments to read */ +typedef struct WALSegmentContext +{ + char ws_dir[MAXPGPATH]; + int ws_segsize; +} WALSegmentContext; + +typedef struct XLogReaderState XLogReaderState; + +/* Function type definitions for various xlogreader interactions */ +typedef int (*XLogPageReadCB) (XLogReaderState *xlogreader, + XLogRecPtr targetPagePtr, + int reqLen, + XLogRecPtr targetRecPtr, + char *readBuf); +typedef void (*WALSegmentOpenCB) (XLogReaderState *xlogreader, + XLogSegNo nextSegNo, + TimeLineID *tli_p); +typedef void (*WALSegmentCloseCB) (XLogReaderState *xlogreader); + +typedef struct XLogReaderRoutine +{ + /* + * Data input callback + * + * This callback shall read at least reqLen valid bytes of the xlog page + * starting at targetPagePtr, and store them in readBuf. The callback + * shall return the number of bytes read (never more than XLOG_BLCKSZ), or + * -1 on failure. The callback shall sleep, if necessary, to wait for the + * requested bytes to become available. The callback will not be invoked + * again for the same page unless more than the returned number of bytes + * are needed. + * + * targetRecPtr is the position of the WAL record we're reading. Usually + * it is equal to targetPagePtr + reqLen, but sometimes xlogreader needs + * to read and verify the page or segment header, before it reads the + * actual WAL record it's interested in. In that case, targetRecPtr can + * be used to determine which timeline to read the page from. + * + * The callback shall set ->seg.ws_tli to the TLI of the file the page was + * read from. + */ + XLogPageReadCB page_read; + + /* + * Callback to open the specified WAL segment for reading. ->seg.ws_file + * shall be set to the file descriptor of the opened segment. In case of + * failure, an error shall be raised by the callback and it shall not + * return. + * + * "nextSegNo" is the number of the segment to be opened. + * + * "tli_p" is an input/output argument. WALRead() uses it to pass the + * timeline in which the new segment should be found, but the callback can + * use it to return the TLI that it actually opened. + */ + WALSegmentOpenCB segment_open; + + /* + * WAL segment close callback. ->seg.ws_file shall be set to a negative + * number. + */ + WALSegmentCloseCB segment_close; +} XLogReaderRoutine; + +#define XL_ROUTINE(...) &(XLogReaderRoutine){__VA_ARGS__} + +typedef struct +{ + /* Is this block ref in use? */ + bool in_use; + + /* Identify the block this refers to */ + RelFileNode rnode; + ForkNumber forknum; + BlockNumber blkno; + + /* Prefetching workspace. */ + Buffer prefetch_buffer; + + /* copy of the fork_flags field from the XLogRecordBlockHeader */ + uint8 flags; + + /* Information on full-page image, if any */ + bool has_image; /* has image, even for consistency checking */ + bool apply_image; /* has image that should be restored */ + char *bkp_image; + uint16 hole_offset; + uint16 hole_length; + uint16 bimg_len; + uint8 bimg_info; + + /* Buffer holding the rmgr-specific data associated with this block */ + bool has_data; + char *data; + uint16 data_len; + uint16 data_bufsz; +} DecodedBkpBlock; + +/* + * The decoded contents of a record. This occupies a contiguous region of + * memory, with main_data and blocks[n].data pointing to memory after the + * members declared here. + */ +typedef struct DecodedXLogRecord +{ + /* Private member used for resource management. */ + size_t size; /* total size of decoded record */ + bool oversized; /* outside the regular decode buffer? */ + struct DecodedXLogRecord *next; /* decoded record queue link */ + + /* Public members. */ + XLogRecPtr lsn; /* location */ + XLogRecPtr next_lsn; /* location of next record */ + XLogRecord header; /* header */ + RepOriginId record_origin; + TransactionId toplevel_xid; /* XID of top-level transaction */ + char *main_data; /* record's main data portion */ + uint32 main_data_len; /* main data portion's length */ + int max_block_id; /* highest block_id in use (-1 if none) */ + DecodedBkpBlock blocks[FLEXIBLE_ARRAY_MEMBER]; +} DecodedXLogRecord; + +struct XLogReaderState +{ + /* + * Operational callbacks + */ + XLogReaderRoutine routine; + + /* ---------------------------------------- + * Public parameters + * ---------------------------------------- + */ + + /* + * System identifier of the xlog files we're about to read. Set to zero + * (the default value) if unknown or unimportant. + */ + uint64 system_identifier; + + /* + * Opaque data for callbacks to use. Not used by XLogReader. + */ + void *private_data; + + /* + * Start and end point of last record read. EndRecPtr is also used as the + * position to read next. Calling XLogBeginRead() sets EndRecPtr to the + * starting position and ReadRecPtr to invalid. + * + * Start and end point of last record returned by XLogReadRecord(). These + * are also available as record->lsn and record->next_lsn. + */ + XLogRecPtr ReadRecPtr; /* start of last record read */ + XLogRecPtr EndRecPtr; /* end+1 of last record read */ + + /* + * Set at the end of recovery: the start point of a partial record at the + * end of WAL (InvalidXLogRecPtr if there wasn't one), and the start + * location of its first contrecord that went missing. + */ + XLogRecPtr abortedRecPtr; + XLogRecPtr missingContrecPtr; + /* Set when XLP_FIRST_IS_OVERWRITE_CONTRECORD is found */ + XLogRecPtr overwrittenRecPtr; + + + /* ---------------------------------------- + * Decoded representation of current record + * + * Use XLogRecGet* functions to investigate the record; these fields + * should not be accessed directly. + * ---------------------------------------- + * Start and end point of the last record read and decoded by + * XLogReadRecordInternal(). NextRecPtr is also used as the position to + * decode next. Calling XLogBeginRead() sets NextRecPtr and EndRecPtr to + * the requested starting position. + */ + XLogRecPtr DecodeRecPtr; /* start of last record decoded */ + XLogRecPtr NextRecPtr; /* end+1 of last record decoded */ + XLogRecPtr PrevRecPtr; /* start of previous record decoded */ + + /* Last record returned by XLogReadRecord(). */ + DecodedXLogRecord *record; + + /* ---------------------------------------- + * private/internal state + * ---------------------------------------- + */ + + /* + * Buffer for decoded records. This is a circular buffer, though + * individual records can't be split in the middle, so some space is often + * wasted at the end. Oversized records that don't fit in this space are + * allocated separately. + */ + char *decode_buffer; + size_t decode_buffer_size; + bool free_decode_buffer; /* need to free? */ + char *decode_buffer_head; /* data is read from the head */ + char *decode_buffer_tail; /* new data is written at the tail */ + + /* + * Queue of records that have been decoded. This is a linked list that + * usually consists of consecutive records in decode_buffer, but may also + * contain oversized records allocated with palloc(). + */ + DecodedXLogRecord *decode_queue_head; /* oldest decoded record */ + DecodedXLogRecord *decode_queue_tail; /* newest decoded record */ + + /* + * Buffer for currently read page (XLOG_BLCKSZ bytes, valid up to at least + * readLen bytes) + */ + char *readBuf; + uint32 readLen; + + /* last read XLOG position for data currently in readBuf */ + WALSegmentContext segcxt; + WALOpenSegment seg; + uint32 segoff; + + /* + * beginning of prior page read, and its TLI. Doesn't necessarily + * correspond to what's in readBuf; used for timeline sanity checks. + */ + XLogRecPtr latestPagePtr; + TimeLineID latestPageTLI; + + /* beginning of the WAL record being read. */ + XLogRecPtr currRecPtr; + /* timeline to read it from, 0 if a lookup is required */ + TimeLineID currTLI; + + /* + * Safe point to read to in currTLI if current TLI is historical + * (tliSwitchPoint) or InvalidXLogRecPtr if on current timeline. + * + * Actually set to the start of the segment containing the timeline switch + * that ends currTLI's validity, not the LSN of the switch its self, since + * we can't assume the old segment will be present. + */ + XLogRecPtr currTLIValidUntil; + + /* + * If currTLI is not the most recent known timeline, the next timeline to + * read from when currTLIValidUntil is reached. + */ + TimeLineID nextTLI; + + /* + * Buffer for current ReadRecord result (expandable), used when a record + * crosses a page boundary. + */ + char *readRecordBuf; + uint32 readRecordBufSize; + + /* Buffer to hold error message */ + char *errormsg_buf; + bool errormsg_deferred; + + /* + * Flag to indicate to XLogPageReadCB that it should not block waiting for + * data. + */ + bool nonblocking; +}; + +/* + * Check if XLogNextRecord() has any more queued records or an error to return. + */ +static inline bool +XLogReaderHasQueuedRecordOrError(XLogReaderState *state) +{ + return (state->decode_queue_head != NULL) || state->errormsg_deferred; +} + +/* Get a new XLogReader */ +extern XLogReaderState *XLogReaderAllocate(int wal_segment_size, + const char *waldir, + XLogReaderRoutine *routine, + void *private_data); +extern XLogReaderRoutine *LocalXLogReaderRoutine(void); + +/* Free an XLogReader */ +extern void XLogReaderFree(XLogReaderState *state); + +/* Optionally provide a circular decoding buffer to allow readahead. */ +extern void XLogReaderSetDecodeBuffer(XLogReaderState *state, + void *buffer, + size_t size); + +/* Position the XLogReader to given record */ +extern void XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr); +extern XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr); + +/* Return values from XLogPageReadCB. */ +typedef enum XLogPageReadResult +{ + XLREAD_SUCCESS = 0, /* record is successfully read */ + XLREAD_FAIL = -1, /* failed during reading a record */ + XLREAD_WOULDBLOCK = -2 /* nonblocking mode only, no data */ +} XLogPageReadResult; + +/* Read the next XLog record. Returns NULL on end-of-WAL or failure */ +extern struct XLogRecord *XLogReadRecord(XLogReaderState *state, + char **errormsg); + +/* Consume the next record or error. */ +extern DecodedXLogRecord *XLogNextRecord(XLogReaderState *state, + char **errormsg); + +/* Release the previously returned record, if necessary. */ +extern XLogRecPtr XLogReleasePreviousRecord(XLogReaderState *state); + +/* Try to read ahead, if there is data and space. */ +extern DecodedXLogRecord *XLogReadAhead(XLogReaderState *state, + bool nonblocking); + +/* Validate a page */ +extern bool XLogReaderValidatePageHeader(XLogReaderState *state, + XLogRecPtr recptr, char *phdr); + +/* Forget error produced by XLogReaderValidatePageHeader(). */ +extern void XLogReaderResetError(XLogReaderState *state); + +/* + * Error information from WALRead that both backend and frontend caller can + * process. Currently only errors from pg_pread can be reported. + */ +typedef struct WALReadError +{ + int wre_errno; /* errno set by the last pg_pread() */ + int wre_off; /* Offset we tried to read from. */ + int wre_req; /* Bytes requested to be read. */ + int wre_read; /* Bytes read by the last read(). */ + WALOpenSegment wre_seg; /* Segment we tried to read from. */ +} WALReadError; + +extern bool WALRead(XLogReaderState *state, + char *buf, XLogRecPtr startptr, Size count, + TimeLineID tli, WALReadError *errinfo); + +/* Functions for decoding an XLogRecord */ + +extern size_t DecodeXLogRecordRequiredSpace(size_t xl_tot_len); +extern bool DecodeXLogRecord(XLogReaderState *state, + DecodedXLogRecord *decoded, + XLogRecord *record, + XLogRecPtr lsn, + char **errmsg); + +/* + * Macros that provide access to parts of the record most recently returned by + * XLogReadRecord() or XLogNextRecord(). + */ +#define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len) +#define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev) +#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info) +#define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid) +#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid) +#define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin) +#define XLogRecGetTopXid(decoder) ((decoder)->record->toplevel_xid) +#define XLogRecGetData(decoder) ((decoder)->record->main_data) +#define XLogRecGetDataLen(decoder) ((decoder)->record->main_data_len) +#define XLogRecHasAnyBlockRefs(decoder) ((decoder)->record->max_block_id >= 0) +#define XLogRecMaxBlockId(decoder) ((decoder)->record->max_block_id) +#define XLogRecGetBlock(decoder, i) (&(decoder)->record->blocks[(i)]) +#define XLogRecHasBlockRef(decoder, block_id) \ + (((decoder)->record->max_block_id >= (block_id)) && \ + ((decoder)->record->blocks[block_id].in_use)) +#define XLogRecHasBlockImage(decoder, block_id) \ + ((decoder)->record->blocks[block_id].has_image) +#define XLogRecBlockImageApply(decoder, block_id) \ + ((decoder)->record->blocks[block_id].apply_image) + +#ifndef FRONTEND +extern FullTransactionId XLogRecGetFullXid(XLogReaderState *record); +#endif + +extern bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page); +extern char *XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len); +extern void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, + RelFileNode *rnode, ForkNumber *forknum, + BlockNumber *blknum); +extern bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, + RelFileNode *rnode, ForkNumber *forknum, + BlockNumber *blknum, + Buffer *prefetch_buffer); + +#endif /* XLOGREADER_H */ diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h new file mode 100644 index 0000000..052ac68 --- /dev/null +++ b/src/include/access/xlogrecord.h @@ -0,0 +1,236 @@ +/* + * xlogrecord.h + * + * Definitions for the WAL record format. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogrecord.h + */ +#ifndef XLOGRECORD_H +#define XLOGRECORD_H + +#include "access/rmgr.h" +#include "access/xlogdefs.h" +#include "port/pg_crc32c.h" +#include "storage/block.h" +#include "storage/relfilenode.h" + +/* + * The overall layout of an XLOG record is: + * Fixed-size header (XLogRecord struct) + * XLogRecordBlockHeader struct + * XLogRecordBlockHeader struct + * ... + * XLogRecordDataHeader[Short|Long] struct + * block data + * block data + * ... + * main data + * + * There can be zero or more XLogRecordBlockHeaders, and 0 or more bytes of + * rmgr-specific data not associated with a block. XLogRecord structs + * always start on MAXALIGN boundaries in the WAL files, but the rest of + * the fields are not aligned. + * + * The XLogRecordBlockHeader, XLogRecordDataHeaderShort and + * XLogRecordDataHeaderLong structs all begin with a single 'id' byte. It's + * used to distinguish between block references, and the main data structs. + */ +typedef struct XLogRecord +{ + uint32 xl_tot_len; /* total len of entire record */ + TransactionId xl_xid; /* xact id */ + XLogRecPtr xl_prev; /* ptr to previous record in log */ + uint8 xl_info; /* flag bits, see below */ + RmgrId xl_rmid; /* resource manager for this record */ + /* 2 bytes of padding here, initialize to zero */ + pg_crc32c xl_crc; /* CRC for this record */ + + /* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */ + +} XLogRecord; + +#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c)) + +/* + * The high 4 bits in xl_info may be used freely by rmgr. The + * XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits can be passed by + * XLogInsert caller. The rest are set internally by XLogInsert. + */ +#define XLR_INFO_MASK 0x0F +#define XLR_RMGR_INFO_MASK 0xF0 + +/* + * If a WAL record modifies any relation files, in ways not covered by the + * usual block references, this flag is set. This is not used for anything + * by PostgreSQL itself, but it allows external tools that read WAL and keep + * track of modified blocks to recognize such special record types. + */ +#define XLR_SPECIAL_REL_UPDATE 0x01 + +/* + * Enforces consistency checks of replayed WAL at recovery. If enabled, + * each record will log a full-page write for each block modified by the + * record and will reuse it afterwards for consistency checks. The caller + * of XLogInsert can use this value if necessary, but if + * wal_consistency_checking is enabled for a rmgr this is set unconditionally. + */ +#define XLR_CHECK_CONSISTENCY 0x02 + +/* + * Header info for block data appended to an XLOG record. + * + * 'data_length' is the length of the rmgr-specific payload data associated + * with this block. It does not include the possible full page image, nor + * XLogRecordBlockHeader struct itself. + * + * Note that we don't attempt to align the XLogRecordBlockHeader struct! + * So, the struct must be copied to aligned local storage before use. + */ +typedef struct XLogRecordBlockHeader +{ + uint8 id; /* block reference ID */ + uint8 fork_flags; /* fork within the relation, and flags */ + uint16 data_length; /* number of payload bytes (not including page + * image) */ + + /* If BKPBLOCK_HAS_IMAGE, an XLogRecordBlockImageHeader struct follows */ + /* If BKPBLOCK_SAME_REL is not set, a RelFileNode follows */ + /* BlockNumber follows */ +} XLogRecordBlockHeader; + +#define SizeOfXLogRecordBlockHeader (offsetof(XLogRecordBlockHeader, data_length) + sizeof(uint16)) + +/* + * Additional header information when a full-page image is included + * (i.e. when BKPBLOCK_HAS_IMAGE is set). + * + * The XLOG code is aware that PG data pages usually contain an unused "hole" + * in the middle, which contains only zero bytes. Since we know that the + * "hole" is all zeros, we remove it from the stored data (and it's not counted + * in the XLOG record's CRC, either). Hence, the amount of block data actually + * present is (BLCKSZ - <length of "hole" bytes>). + * + * Additionally, when wal_compression is enabled, we will try to compress full + * page images using one of the supported algorithms, after removing the + * "hole". This can reduce the WAL volume, but at some extra cost of CPU spent + * on the compression during WAL logging. In this case, since the "hole" + * length cannot be calculated by subtracting the number of page image bytes + * from BLCKSZ, basically it needs to be stored as an extra information. + * But when no "hole" exists, we can assume that the "hole" length is zero + * and no such an extra information needs to be stored. Note that + * the original version of page image is stored in WAL instead of the + * compressed one if the number of bytes saved by compression is less than + * the length of extra information. Hence, when a page image is successfully + * compressed, the amount of block data actually present is less than + * BLCKSZ - the length of "hole" bytes - the length of extra information. + */ +typedef struct XLogRecordBlockImageHeader +{ + uint16 length; /* number of page image bytes */ + uint16 hole_offset; /* number of bytes before "hole" */ + uint8 bimg_info; /* flag bits, see below */ + + /* + * If BKPIMAGE_HAS_HOLE and BKPIMAGE_COMPRESSED(), an + * XLogRecordBlockCompressHeader struct follows. + */ +} XLogRecordBlockImageHeader; + +#define SizeOfXLogRecordBlockImageHeader \ + (offsetof(XLogRecordBlockImageHeader, bimg_info) + sizeof(uint8)) + +/* Information stored in bimg_info */ +#define BKPIMAGE_HAS_HOLE 0x01 /* page image has "hole" */ +#define BKPIMAGE_APPLY 0x02 /* page image should be restored + * during replay */ +/* compression methods supported */ +#define BKPIMAGE_COMPRESS_PGLZ 0x04 +#define BKPIMAGE_COMPRESS_LZ4 0x08 +#define BKPIMAGE_COMPRESS_ZSTD 0x10 + +#define BKPIMAGE_COMPRESSED(info) \ + ((info & (BKPIMAGE_COMPRESS_PGLZ | BKPIMAGE_COMPRESS_LZ4 | \ + BKPIMAGE_COMPRESS_ZSTD)) != 0) + +/* + * Extra header information used when page image has "hole" and + * is compressed. + */ +typedef struct XLogRecordBlockCompressHeader +{ + uint16 hole_length; /* number of bytes in "hole" */ +} XLogRecordBlockCompressHeader; + +#define SizeOfXLogRecordBlockCompressHeader \ + sizeof(XLogRecordBlockCompressHeader) + +/* + * Maximum size of the header for a block reference. This is used to size a + * temporary buffer for constructing the header. + */ +#define MaxSizeOfXLogRecordBlockHeader \ + (SizeOfXLogRecordBlockHeader + \ + SizeOfXLogRecordBlockImageHeader + \ + SizeOfXLogRecordBlockCompressHeader + \ + sizeof(RelFileNode) + \ + sizeof(BlockNumber)) + +/* + * The fork number fits in the lower 4 bits in the fork_flags field. The upper + * bits are used for flags. + */ +#define BKPBLOCK_FORK_MASK 0x0F +#define BKPBLOCK_FLAG_MASK 0xF0 +#define BKPBLOCK_HAS_IMAGE 0x10 /* block data is an XLogRecordBlockImage */ +#define BKPBLOCK_HAS_DATA 0x20 +#define BKPBLOCK_WILL_INIT 0x40 /* redo will re-init the page */ +#define BKPBLOCK_SAME_REL 0x80 /* RelFileNode omitted, same as previous */ + +/* + * XLogRecordDataHeaderShort/Long are used for the "main data" portion of + * the record. If the length of the data is less than 256 bytes, the short + * form is used, with a single byte to hold the length. Otherwise the long + * form is used. + * + * (These structs are currently not used in the code, they are here just for + * documentation purposes). + */ +typedef struct XLogRecordDataHeaderShort +{ + uint8 id; /* XLR_BLOCK_ID_DATA_SHORT */ + uint8 data_length; /* number of payload bytes */ +} XLogRecordDataHeaderShort; + +#define SizeOfXLogRecordDataHeaderShort (sizeof(uint8) * 2) + +typedef struct XLogRecordDataHeaderLong +{ + uint8 id; /* XLR_BLOCK_ID_DATA_LONG */ + /* followed by uint32 data_length, unaligned */ +} XLogRecordDataHeaderLong; + +#define SizeOfXLogRecordDataHeaderLong (sizeof(uint8) + sizeof(uint32)) + +/* + * Block IDs used to distinguish different kinds of record fragments. Block + * references are numbered from 0 to XLR_MAX_BLOCK_ID. A rmgr is free to use + * any ID number in that range (although you should stick to small numbers, + * because the WAL machinery is optimized for that case). A few ID + * numbers are reserved to denote the "main" data portion of the record, + * as well as replication-supporting transaction metadata. + * + * The maximum is currently set at 32, quite arbitrarily. Most records only + * need a handful of block references, but there are a few exceptions that + * need more. + */ +#define XLR_MAX_BLOCK_ID 32 + +#define XLR_BLOCK_ID_DATA_SHORT 255 +#define XLR_BLOCK_ID_DATA_LONG 254 +#define XLR_BLOCK_ID_ORIGIN 253 +#define XLR_BLOCK_ID_TOPLEVEL_XID 252 + +#endif /* XLOGRECORD_H */ diff --git a/src/include/access/xlogrecovery.h b/src/include/access/xlogrecovery.h new file mode 100644 index 0000000..0aa85d9 --- /dev/null +++ b/src/include/access/xlogrecovery.h @@ -0,0 +1,157 @@ +/* + * xlogrecovery.h + * + * Functions for WAL recovery and standby mode + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogrecovery.h + */ +#ifndef XLOGRECOVERY_H +#define XLOGRECOVERY_H + +#include "access/xlogreader.h" +#include "catalog/pg_control.h" +#include "lib/stringinfo.h" +#include "utils/timestamp.h" + +/* + * Recovery target type. + * Only set during a Point in Time recovery, not when in standby mode. + */ +typedef enum +{ + RECOVERY_TARGET_UNSET, + RECOVERY_TARGET_XID, + RECOVERY_TARGET_TIME, + RECOVERY_TARGET_NAME, + RECOVERY_TARGET_LSN, + RECOVERY_TARGET_IMMEDIATE +} RecoveryTargetType; + +/* + * Recovery target TimeLine goal + */ +typedef enum +{ + RECOVERY_TARGET_TIMELINE_CONTROLFILE, + RECOVERY_TARGET_TIMELINE_LATEST, + RECOVERY_TARGET_TIMELINE_NUMERIC +} RecoveryTargetTimeLineGoal; + +/* Recovery pause states */ +typedef enum RecoveryPauseState +{ + RECOVERY_NOT_PAUSED, /* pause not requested */ + RECOVERY_PAUSE_REQUESTED, /* pause requested, but not yet paused */ + RECOVERY_PAUSED /* recovery is paused */ +} RecoveryPauseState; + +/* User-settable GUC parameters */ +extern PGDLLIMPORT bool recoveryTargetInclusive; +extern PGDLLIMPORT int recoveryTargetAction; +extern PGDLLIMPORT int recovery_min_apply_delay; +extern PGDLLIMPORT char *PrimaryConnInfo; +extern PGDLLIMPORT char *PrimarySlotName; +extern PGDLLIMPORT char *recoveryRestoreCommand; +extern PGDLLIMPORT char *recoveryEndCommand; +extern PGDLLIMPORT char *archiveCleanupCommand; + +/* indirectly set via GUC system */ +extern PGDLLIMPORT TransactionId recoveryTargetXid; +extern PGDLLIMPORT char *recovery_target_time_string; +extern PGDLLIMPORT TimestampTz recoveryTargetTime; +extern PGDLLIMPORT const char *recoveryTargetName; +extern PGDLLIMPORT XLogRecPtr recoveryTargetLSN; +extern PGDLLIMPORT RecoveryTargetType recoveryTarget; +extern PGDLLIMPORT char *PromoteTriggerFile; +extern PGDLLIMPORT bool wal_receiver_create_temp_slot; +extern PGDLLIMPORT RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal; +extern PGDLLIMPORT TimeLineID recoveryTargetTLIRequested; +extern PGDLLIMPORT TimeLineID recoveryTargetTLI; + +/* Have we already reached a consistent database state? */ +extern PGDLLIMPORT bool reachedConsistency; + +/* Are we currently in standby mode? */ +extern PGDLLIMPORT bool StandbyMode; + +extern Size XLogRecoveryShmemSize(void); +extern void XLogRecoveryShmemInit(void); + +extern void InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdownPtr, bool *haveBackupLabel, bool *haveTblspcMap); +extern void PerformWalRecovery(void); + +/* + * FinishWalRecovery() returns this. It contains information about the point + * where recovery ended, and why it ended. + */ +typedef struct +{ + /* + * Information about the last valid or applied record, after which new WAL + * can be appended. 'lastRec' is the position where the last record + * starts, and 'endOfLog' is its end. 'lastPage' is a copy of the last + * partial page that contains endOfLog (or NULL if endOfLog is exactly at + * page boundary). 'lastPageBeginPtr' is the position where the last page + * begins. + * + * endOfLogTLI is the TLI in the filename of the XLOG segment containing + * the last applied record. It could be different from lastRecTLI, if + * there was a timeline switch in that segment, and we were reading the + * old WAL from a segment belonging to a higher timeline. + */ + XLogRecPtr lastRec; /* start of last valid or applied record */ + TimeLineID lastRecTLI; + XLogRecPtr endOfLog; /* end of last valid or applied record */ + TimeLineID endOfLogTLI; + + XLogRecPtr lastPageBeginPtr; /* LSN of page that contains endOfLog */ + char *lastPage; /* copy of the last page, up to endOfLog */ + + /* + * abortedRecPtr is the start pointer of a broken record at end of WAL + * when recovery completes; missingContrecPtr is the location of the first + * contrecord that went missing. See CreateOverwriteContrecordRecord for + * details. + */ + XLogRecPtr abortedRecPtr; + XLogRecPtr missingContrecPtr; + + /* short human-readable string describing why recovery ended */ + char *recoveryStopReason; + + /* + * If standby or recovery signal file was found, these flags are set + * accordingly. + */ + bool standby_signal_file_found; + bool recovery_signal_file_found; +} EndOfWalRecoveryInfo; + +extern EndOfWalRecoveryInfo *FinishWalRecovery(void); +extern void ShutdownWalRecovery(void); +extern void RemovePromoteSignalFiles(void); + +extern bool HotStandbyActive(void); +extern XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI); +extern RecoveryPauseState GetRecoveryPauseState(void); +extern void SetRecoveryPause(bool recoveryPause); +extern void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream); +extern TimestampTz GetLatestXTime(void); +extern TimestampTz GetCurrentChunkReplayStartTime(void); +extern XLogRecPtr GetCurrentReplayRecPtr(TimeLineID *replayEndTLI); + +extern bool PromoteIsTriggered(void); +extern bool CheckPromoteSignal(void); +extern void WakeupRecovery(void); + +extern void StartupRequestWalReceiverRestart(void); +extern void XLogRequestWalReceiverReply(void); + +extern void RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue); + +extern void xlog_outdesc(StringInfo buf, XLogReaderState *record); + +#endif /* XLOGRECOVERY_H */ diff --git a/src/include/access/xlogstats.h b/src/include/access/xlogstats.h new file mode 100644 index 0000000..7eb4370 --- /dev/null +++ b/src/include/access/xlogstats.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + * + * xlogstats.h + * Definitions for WAL Statitstics + * + * Copyright (c) 2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/access/xlogstats.h + * + *------------------------------------------------------------------------- + */ +#ifndef XLOGSTATS_H +#define XLOGSTATS_H + +#include "access/rmgr.h" +#include "access/xlogreader.h" + +#define MAX_XLINFO_TYPES 16 + +typedef struct XLogRecStats +{ + uint64 count; + uint64 rec_len; + uint64 fpi_len; +} XLogRecStats; + +typedef struct XLogStats +{ + uint64 count; +#ifdef FRONTEND + XLogRecPtr startptr; + XLogRecPtr endptr; +#endif + XLogRecStats rmgr_stats[RM_MAX_ID + 1]; + XLogRecStats record_stats[RM_MAX_ID + 1][MAX_XLINFO_TYPES]; +} XLogStats; + +extern void XLogRecGetLen(XLogReaderState *record, uint32 *rec_len, + uint32 *fpi_len); +extern void XLogRecStoreStats(XLogStats *stats, XLogReaderState *record); + +#endif /* XLOGSTATS_H */ diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h new file mode 100644 index 0000000..c9d0b75 --- /dev/null +++ b/src/include/access/xlogutils.h @@ -0,0 +1,118 @@ +/* + * xlogutils.h + * + * Utilities for replaying WAL records. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/access/xlogutils.h + */ +#ifndef XLOG_UTILS_H +#define XLOG_UTILS_H + +#include "access/xlogreader.h" +#include "storage/bufmgr.h" + +/* + * Prior to 8.4, all activity during recovery was carried out by the startup + * process. This local variable continues to be used in many parts of the + * code to indicate actions taken by RecoveryManagers. Other processes that + * potentially perform work during recovery should check RecoveryInProgress(). + * See XLogCtl notes in xlog.c. + */ +extern PGDLLIMPORT bool InRecovery; + +/* + * Like InRecovery, standbyState is only valid in the startup process. + * In all other processes it will have the value STANDBY_DISABLED (so + * InHotStandby will read as false). + * + * In DISABLED state, we're performing crash recovery or hot standby was + * disabled in postgresql.conf. + * + * In INITIALIZED state, we've run InitRecoveryTransactionEnvironment, but + * we haven't yet processed a RUNNING_XACTS or shutdown-checkpoint WAL record + * to initialize our primary-transaction tracking system. + * + * When the transaction tracking is initialized, we enter the SNAPSHOT_PENDING + * state. The tracked information might still be incomplete, so we can't allow + * connections yet, but redo functions must update the in-memory state when + * appropriate. + * + * In SNAPSHOT_READY mode, we have full knowledge of transactions that are + * (or were) running on the primary at the current WAL location. Snapshots + * can be taken, and read-only queries can be run. + */ +typedef enum +{ + STANDBY_DISABLED, + STANDBY_INITIALIZED, + STANDBY_SNAPSHOT_PENDING, + STANDBY_SNAPSHOT_READY +} HotStandbyState; + +extern PGDLLIMPORT HotStandbyState standbyState; + +#define InHotStandby (standbyState >= STANDBY_SNAPSHOT_PENDING) + + +extern bool XLogHaveInvalidPages(void); +extern void XLogCheckInvalidPages(void); + +extern void XLogDropRelation(RelFileNode rnode, ForkNumber forknum); +extern void XLogDropDatabase(Oid dbid); +extern void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, + BlockNumber nblocks); + +/* Result codes for XLogReadBufferForRedo[Extended] */ +typedef enum +{ + BLK_NEEDS_REDO, /* changes from WAL record need to be applied */ + BLK_DONE, /* block is already up-to-date */ + BLK_RESTORED, /* block was restored from a full-page image */ + BLK_NOTFOUND /* block was not found (and hence does not + * need to be replayed) */ +} XLogRedoAction; + +/* Private data of the read_local_xlog_page_no_wait callback. */ +typedef struct ReadLocalXLogPageNoWaitPrivate +{ + bool end_of_wal; /* true, when end of WAL is reached */ +} ReadLocalXLogPageNoWaitPrivate; + +extern XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, + uint8 buffer_id, Buffer *buf); +extern Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id); +extern XLogRedoAction XLogReadBufferForRedoExtended(XLogReaderState *record, + uint8 buffer_id, + ReadBufferMode mode, bool get_cleanup_lock, + Buffer *buf); + +extern Buffer XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, + BlockNumber blkno, ReadBufferMode mode, + Buffer recent_buffer); + +extern Relation CreateFakeRelcacheEntry(RelFileNode rnode); +extern void FreeFakeRelcacheEntry(Relation fakerel); + +extern int read_local_xlog_page(XLogReaderState *state, + XLogRecPtr targetPagePtr, int reqLen, + XLogRecPtr targetRecPtr, char *cur_page); +extern int read_local_xlog_page_no_wait(XLogReaderState *state, + XLogRecPtr targetPagePtr, int reqLen, + XLogRecPtr targetRecPtr, + char *cur_page); +extern void wal_segment_open(XLogReaderState *state, + XLogSegNo nextSegNo, + TimeLineID *tli_p); +extern void wal_segment_close(XLogReaderState *state); + +extern void XLogReadDetermineTimeline(XLogReaderState *state, + XLogRecPtr wantPage, + uint32 wantLength, + TimeLineID currTLI); + +extern void WALReadRaiseError(WALReadError *errinfo); + +#endif diff --git a/src/include/backup/backup_manifest.h b/src/include/backup/backup_manifest.h new file mode 100644 index 0000000..b15f0fa --- /dev/null +++ b/src/include/backup/backup_manifest.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * backup_manifest.h + * Routines for generating a backup manifest. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/backup/backup_manifest.h + * + *------------------------------------------------------------------------- + */ +#ifndef BACKUP_MANIFEST_H +#define BACKUP_MANIFEST_H + +#include "backup/basebackup_sink.h" +#include "common/checksum_helper.h" +#include "pgtime.h" +#include "storage/buffile.h" + +typedef enum manifest_option +{ + MANIFEST_OPTION_YES, + MANIFEST_OPTION_NO, + MANIFEST_OPTION_FORCE_ENCODE +} backup_manifest_option; + +typedef struct backup_manifest_info +{ + BufFile *buffile; + pg_checksum_type checksum_type; + pg_cryptohash_ctx *manifest_ctx; + uint64 manifest_size; + bool force_encode; + bool first_file; + bool still_checksumming; +} backup_manifest_info; + +extern void InitializeBackupManifest(backup_manifest_info *manifest, + backup_manifest_option want_manifest, + pg_checksum_type manifest_checksum_type); +extern void AddFileToBackupManifest(backup_manifest_info *manifest, + const char *spcoid, + const char *pathname, size_t size, + pg_time_t mtime, + pg_checksum_context *checksum_ctx); +extern void AddWALInfoToBackupManifest(backup_manifest_info *manifest, + XLogRecPtr startptr, + TimeLineID starttli, XLogRecPtr endptr, + TimeLineID endtli); + +extern void SendBackupManifest(backup_manifest_info *manifest, bbsink *sink); +extern void FreeBackupManifest(backup_manifest_info *manifest); + +#endif diff --git a/src/include/backup/basebackup.h b/src/include/backup/basebackup.h new file mode 100644 index 0000000..593479a --- /dev/null +++ b/src/include/backup/basebackup.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * basebackup.h + * Exports from replication/basebackup.c. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/backup/basebackup.h + * + *------------------------------------------------------------------------- + */ +#ifndef _BASEBACKUP_H +#define _BASEBACKUP_H + +#include "nodes/replnodes.h" + +/* + * Minimum and maximum values of MAX_RATE option in BASE_BACKUP command. + */ +#define MAX_RATE_LOWER 32 +#define MAX_RATE_UPPER 1048576 + +/* + * Information about a tablespace + * + * In some usages, "path" can be NULL to denote the PGDATA directory itself. + */ +typedef struct +{ + char *oid; /* tablespace's OID, as a decimal string */ + char *path; /* full path to tablespace's directory */ + char *rpath; /* relative path if it's within PGDATA, else + * NULL */ + int64 size; /* total size as sent; -1 if not known */ +} tablespaceinfo; + +extern void SendBaseBackup(BaseBackupCmd *cmd); + +#endif /* _BASEBACKUP_H */ diff --git a/src/include/backup/basebackup_sink.h b/src/include/backup/basebackup_sink.h new file mode 100644 index 0000000..a1cd24c --- /dev/null +++ b/src/include/backup/basebackup_sink.h @@ -0,0 +1,301 @@ +/*------------------------------------------------------------------------- + * + * basebackup_sink.h + * API for filtering or sending to a final destination the archives + * produced by the base backup process + * + * Taking a base backup produces one archive per tablespace directory, + * plus a backup manifest unless that feature has been disabled. The + * goal of the backup process is to put those archives and that manifest + * someplace, possibly after postprocessing them in some way. A 'bbsink' + * is an object to which those archives, and the manifest if present, + * can be sent. + * + * In practice, there will be a chain of 'bbsink' objects rather than + * just one, with callbacks being forwarded from one to the next, + * possibly with modification. Each object is responsible for a + * single task e.g. command progress reporting, throttling, or + * communication with the client. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/backup/basebackup_sink.h + * + *------------------------------------------------------------------------- + */ +#ifndef BASEBACKUP_SINK_H +#define BASEBACKUP_SINK_H + +#include "access/xlog_internal.h" +#include "common/compression.h" +#include "nodes/pg_list.h" + +/* Forward declarations. */ +struct bbsink; +struct bbsink_ops; +typedef struct bbsink bbsink; +typedef struct bbsink_ops bbsink_ops; + +/* + * Overall backup state shared by all bbsink objects for a backup. + * + * Before calling bbstate_begin_backup, caller must initiate a bbsink_state + * object which will last for the lifetime of the backup, and must thereafter + * update it as required before each new call to a bbsink method. The bbsink + * will retain a pointer to the state object and will consult it to understand + * the progress of the backup. + * + * 'tablespaces' is a list of tablespaceinfo objects. It must be set before + * calling bbstate_begin_backup() and must not be modified thereafter. + * + * 'tablespace_num' is the index of the current tablespace within the list + * stored in 'tablespaces'. + * + * 'bytes_done' is the number of bytes read so far from $PGDATA. + * + * 'bytes_total' is the total number of bytes estimated to be present in + * $PGDATA, if we have estimated this. + * + * 'bytes_total_is_valid' is true if and only if a proper estimate has been + * stored into 'bytes_total'. + * + * 'startptr' and 'starttli' identify the point in the WAL stream at which + * the backup began. They must be set before calling bbstate_begin_backup() + * and must not be modified thereafter. + */ +typedef struct bbsink_state +{ + List *tablespaces; + int tablespace_num; + uint64 bytes_done; + uint64 bytes_total; + bool bytes_total_is_valid; + XLogRecPtr startptr; + TimeLineID starttli; +} bbsink_state; + +/* + * Common data for any type of basebackup sink. + * + * 'bbs_ops' is the relevant callback table. + * + * 'bbs_buffer' is the buffer into which data destined for the bbsink + * should be stored. It must be a multiple of BLCKSZ. + * + * 'bbs_buffer_length' is the allocated length of the buffer. + * + * 'bbs_next' is a pointer to another bbsink to which this bbsink is + * forwarding some or all operations. + * + * 'bbs_state' is a pointer to the bbsink_state object for this backup. + * Every bbsink associated with this backup should point to the same + * underlying state object. + * + * In general it is expected that the values of these fields are set when + * a bbsink is created and that they do not change thereafter. It's OK + * to modify the data to which bbs_buffer or bbs_state point, but no changes + * should be made to the contents of this struct. + */ +struct bbsink +{ + const bbsink_ops *bbs_ops; + char *bbs_buffer; + size_t bbs_buffer_length; + bbsink *bbs_next; + bbsink_state *bbs_state; +}; + +/* + * Callbacks for a base backup sink. + * + * All of these callbacks are required. If a particular callback just needs to + * forward the call to sink->bbs_next, use bbsink_forward_<callback_name> as + * the callback. + * + * Callers should always invoke these callbacks via the bbsink_* inline + * functions rather than calling them directly. + */ +struct bbsink_ops +{ + /* + * This callback is invoked just once, at the very start of the backup. It + * must set bbs_buffer to point to a chunk of storage where at least + * bbs_buffer_length bytes of data can be written. + */ + void (*begin_backup) (bbsink *sink); + + /* + * For each archive transmitted to a bbsink, there will be one call to the + * begin_archive() callback, some number of calls to the + * archive_contents() callback, and then one call to the end_archive() + * callback. + * + * Before invoking the archive_contents() callback, the caller should copy + * a number of bytes equal to what will be passed as len into bbs_buffer, + * but not more than bbs_buffer_length. + * + * It's generally good if the buffer is as full as possible before the + * archive_contents() callback is invoked, but it's not worth expending + * extra cycles to make sure it's absolutely 100% full. + */ + void (*begin_archive) (bbsink *sink, const char *archive_name); + void (*archive_contents) (bbsink *sink, size_t len); + void (*end_archive) (bbsink *sink); + + /* + * If a backup manifest is to be transmitted to a bbsink, there will be + * one call to the begin_manifest() callback, some number of calls to the + * manifest_contents() callback, and then one call to the end_manifest() + * callback. These calls will occur after all archives are transmitted. + * + * The rules for invoking the manifest_contents() callback are the same as + * for the archive_contents() callback above. + */ + void (*begin_manifest) (bbsink *sink); + void (*manifest_contents) (bbsink *sink, size_t len); + void (*end_manifest) (bbsink *sink); + + /* + * This callback is invoked just once, after all archives and the manifest + * have been sent. + */ + void (*end_backup) (bbsink *sink, XLogRecPtr endptr, TimeLineID endtli); + + /* + * If a backup is aborted by an error, this callback is invoked before the + * bbsink object is destroyed, so that it can release any resources that + * would not be released automatically. If no error occurs, this callback + * is invoked after the end_backup callback. + */ + void (*cleanup) (bbsink *sink); +}; + +/* Begin a backup. */ +static inline void +bbsink_begin_backup(bbsink *sink, bbsink_state *state, int buffer_length) +{ + Assert(sink != NULL); + + Assert(buffer_length > 0); + + sink->bbs_state = state; + sink->bbs_buffer_length = buffer_length; + sink->bbs_ops->begin_backup(sink); + + Assert(sink->bbs_buffer != NULL); + Assert((sink->bbs_buffer_length % BLCKSZ) == 0); +} + +/* Begin an archive. */ +static inline void +bbsink_begin_archive(bbsink *sink, const char *archive_name) +{ + Assert(sink != NULL); + + sink->bbs_ops->begin_archive(sink, archive_name); +} + +/* Process some of the contents of an archive. */ +static inline void +bbsink_archive_contents(bbsink *sink, size_t len) +{ + Assert(sink != NULL); + + /* + * The caller should make a reasonable attempt to fill the buffer before + * calling this function, so it shouldn't be completely empty. Nor should + * it be filled beyond capacity. + */ + Assert(len > 0 && len <= sink->bbs_buffer_length); + + sink->bbs_ops->archive_contents(sink, len); +} + +/* Finish an archive. */ +static inline void +bbsink_end_archive(bbsink *sink) +{ + Assert(sink != NULL); + + sink->bbs_ops->end_archive(sink); +} + +/* Begin the backup manifest. */ +static inline void +bbsink_begin_manifest(bbsink *sink) +{ + Assert(sink != NULL); + + sink->bbs_ops->begin_manifest(sink); +} + +/* Process some of the manifest contents. */ +static inline void +bbsink_manifest_contents(bbsink *sink, size_t len) +{ + Assert(sink != NULL); + + /* See comments in bbsink_archive_contents. */ + Assert(len > 0 && len <= sink->bbs_buffer_length); + + sink->bbs_ops->manifest_contents(sink, len); +} + +/* Finish the backup manifest. */ +static inline void +bbsink_end_manifest(bbsink *sink) +{ + Assert(sink != NULL); + + sink->bbs_ops->end_manifest(sink); +} + +/* Finish a backup. */ +static inline void +bbsink_end_backup(bbsink *sink, XLogRecPtr endptr, TimeLineID endtli) +{ + Assert(sink != NULL); + Assert(sink->bbs_state->tablespace_num == list_length(sink->bbs_state->tablespaces)); + + sink->bbs_ops->end_backup(sink, endptr, endtli); +} + +/* Release resources before destruction. */ +static inline void +bbsink_cleanup(bbsink *sink) +{ + Assert(sink != NULL); + + sink->bbs_ops->cleanup(sink); +} + +/* Forwarding callbacks. Use these to pass operations through to next sink. */ +extern void bbsink_forward_begin_backup(bbsink *sink); +extern void bbsink_forward_begin_archive(bbsink *sink, + const char *archive_name); +extern void bbsink_forward_archive_contents(bbsink *sink, size_t len); +extern void bbsink_forward_end_archive(bbsink *sink); +extern void bbsink_forward_begin_manifest(bbsink *sink); +extern void bbsink_forward_manifest_contents(bbsink *sink, size_t len); +extern void bbsink_forward_end_manifest(bbsink *sink); +extern void bbsink_forward_end_backup(bbsink *sink, XLogRecPtr endptr, + TimeLineID endtli); +extern void bbsink_forward_cleanup(bbsink *sink); + +/* Constructors for various types of sinks. */ +extern bbsink *bbsink_copystream_new(bool send_to_client); +extern bbsink *bbsink_gzip_new(bbsink *next, pg_compress_specification *); +extern bbsink *bbsink_lz4_new(bbsink *next, pg_compress_specification *); +extern bbsink *bbsink_zstd_new(bbsink *next, pg_compress_specification *); +extern bbsink *bbsink_progress_new(bbsink *next, bool estimate_backup_size); +extern bbsink *bbsink_server_new(bbsink *next, char *pathname); +extern bbsink *bbsink_throttle_new(bbsink *next, uint32 maxrate); + +/* Extra interface functions for progress reporting. */ +extern void basebackup_progress_wait_checkpoint(void); +extern void basebackup_progress_estimate_backup_size(void); +extern void basebackup_progress_wait_wal_archive(bbsink_state *); +extern void basebackup_progress_transfer_wal(void); +extern void basebackup_progress_done(void); + +#endif diff --git a/src/include/backup/basebackup_target.h b/src/include/backup/basebackup_target.h new file mode 100644 index 0000000..3a359dd --- /dev/null +++ b/src/include/backup/basebackup_target.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * basebackup_target.h + * Extensibility framework for adding base backup targets. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/backup/basebackup_target.h + * + *------------------------------------------------------------------------- + */ +#ifndef BASEBACKUP_TARGET_H +#define BASEBACKUP_TARGET_H + +#include "backup/basebackup_sink.h" + +struct BaseBackupTargetHandle; +typedef struct BaseBackupTargetHandle BaseBackupTargetHandle; + +/* + * Extensions can call this function to create new backup targets. + * + * 'name' is the name of the new target. + * + * 'check_detail' is a function that accepts a target name and target detail + * and either throws an error (if the target detail is not valid or some other + * problem, such as a permissions issue, is detected) or returns a pointer to + * the data that will be needed to create a bbsink implementing that target. + * The second argumnt will be NULL if the TARGET_DETAIL option to the + * BASE_BACKUP command was not specified. + * + * 'get_sink' is a function that creates the bbsink. The first argument + * is the successor sink; the sink created by this function should always + * forward to this sink. The second argument is the pointer returned by a + * previous call to the 'check_detail' function. + * + * In practice, a user will type something like "pg_basebackup --target foo:bar + * -Xfetch". That will cause the server to look for a backup target named + * "foo". If one is found, the check_detail callback will be invoked for the + * string "bar", and whatever that callback returns will be passed as the + * second argument to the get_sink callback. + */ +extern void BaseBackupAddTarget(char *name, + void *(*check_detail) (char *, char *), + bbsink *(*get_sink) (bbsink *, void *)); + +/* + * These functions are used by the core code to access base backup targets + * added via BaseBackupAddTarget(). The core code will pass the TARGET and + * TARGET_DETAIL strings obtained from the user to BaseBackupGetTargetHandle, + * which will either throw an error (if the TARGET is not recognized or the + * check_detail hook for that TARGET doesn't like the TARGET_DETAIL) or + * return a BaseBackupTargetHandle object that can later be passed to + * BaseBackupGetSink. + * + * BaseBackupGetSink constructs a bbsink implementing the desired target + * using the BaseBackupTargetHandle and the successor bbsink. It does this + * by arranging to call the get_sink() callback provided by the extension + * that implements the base backup target. + */ +extern BaseBackupTargetHandle *BaseBackupGetTargetHandle(char *target, + char *target_detail); +extern bbsink *BaseBackupGetSink(BaseBackupTargetHandle *handle, + bbsink *next_sink); + +#endif diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h new file mode 100644 index 0000000..49d4ad5 --- /dev/null +++ b/src/include/bootstrap/bootstrap.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * bootstrap.h + * include file for the bootstrapping code + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/bootstrap/bootstrap.h + * + *------------------------------------------------------------------------- + */ +#ifndef BOOTSTRAP_H +#define BOOTSTRAP_H + +#include "nodes/execnodes.h" + + +/* + * MAXATTR is the maximum number of attributes in a relation supported + * at bootstrap time (i.e., the max possible in a system table). + */ +#define MAXATTR 40 + +#define BOOTCOL_NULL_AUTO 1 +#define BOOTCOL_NULL_FORCE_NULL 2 +#define BOOTCOL_NULL_FORCE_NOT_NULL 3 + +extern PGDLLIMPORT Relation boot_reldesc; +extern PGDLLIMPORT Form_pg_attribute attrtypes[MAXATTR]; +extern PGDLLIMPORT int numattr; + + +extern void BootstrapModeMain(int argc, char *argv[], bool check_only) pg_attribute_noreturn(); + +extern void closerel(char *name); +extern void boot_openrel(char *name); + +extern void DefineAttr(char *name, char *type, int attnum, int nullness); +extern void InsertOneTuple(void); +extern void InsertOneValue(char *value, int i); +extern void InsertOneNull(int i); + +extern void index_register(Oid heap, Oid ind, IndexInfo *indexInfo); +extern void build_indices(void); + +extern void boot_get_type_io_data(Oid typid, + int16 *typlen, + bool *typbyval, + char *typalign, + char *typdelim, + Oid *typioparam, + Oid *typinput, + Oid *typoutput); + +extern int boot_yyparse(void); + +extern int boot_yylex(void); +extern void boot_yyerror(const char *str) pg_attribute_noreturn(); + +#endif /* BOOTSTRAP_H */ diff --git a/src/include/c.h b/src/include/c.h new file mode 100644 index 0000000..ffcdb05 --- /dev/null +++ b/src/include/c.h @@ -0,0 +1,1417 @@ +/*------------------------------------------------------------------------- + * + * c.h + * Fundamental C definitions. This is included by every .c file in + * PostgreSQL (via either postgres.h or postgres_fe.h, as appropriate). + * + * Note that the definitions here are not intended to be exposed to clients + * of the frontend interface libraries --- so we don't worry much about + * polluting the namespace with lots of stuff... + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/c.h + * + *------------------------------------------------------------------------- + */ +/* + *---------------------------------------------------------------- + * TABLE OF CONTENTS + * + * When adding stuff to this file, please try to put stuff + * into the relevant section, or add new sections as appropriate. + * + * section description + * ------- ------------------------------------------------ + * 0) pg_config.h and standard system headers + * 1) compiler characteristics + * 2) bool, true, false + * 3) standard system types + * 4) IsValid macros for system types + * 5) offsetof, lengthof, alignment + * 6) assertions + * 7) widely useful macros + * 8) random stuff + * 9) system-specific hacks + * + * NOTE: since this file is included by both frontend and backend modules, + * it's usually wrong to put an "extern" declaration here, unless it's + * ifdef'd so that it's seen in only one case or the other. + * typedefs and macros are the kind of thing that might go here. + * + *---------------------------------------------------------------- + */ +#ifndef C_H +#define C_H + +#include "postgres_ext.h" + +/* Must undef pg_config_ext.h symbols before including pg_config.h */ +#undef PG_INT64_TYPE + +#include "pg_config.h" +#include "pg_config_manual.h" /* must be after pg_config.h */ +#include "pg_config_os.h" /* must be before any system header files */ + +/* System header files that should be available everywhere in Postgres */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <stdarg.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <stdint.h> +#include <sys/types.h> +#include <errno.h> +#if defined(WIN32) || defined(__CYGWIN__) +#include <fcntl.h> /* ensure O_BINARY is available */ +#endif +#include <locale.h> +#ifdef ENABLE_NLS +#include <libintl.h> +#endif + + +/* ---------------------------------------------------------------- + * Section 1: compiler characteristics + * + * type prefixes (const, signed, volatile, inline) are handled in pg_config.h. + * ---------------------------------------------------------------- + */ + +/* + * Disable "inline" if PG_FORCE_DISABLE_INLINE is defined. + * This is used to work around compiler bugs and might also be useful for + * investigatory purposes. + */ +#ifdef PG_FORCE_DISABLE_INLINE +#undef inline +#define inline +#endif + +/* + * Attribute macros + * + * GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html + * GCC: https://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html + * Clang: https://clang.llvm.org/docs/AttributeReference.html + * Sunpro: https://docs.oracle.com/cd/E18659_01/html/821-1384/gjzke.html + * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/function_attributes.html + * XLC: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/language_ref/type_attrib.html + */ + +/* + * For compilers which don't support __has_attribute, we just define + * __has_attribute(x) to 0 so that we can define macros for various + * __attribute__s more easily below. + */ +#ifndef __has_attribute +#define __has_attribute(attribute) 0 +#endif + +/* only GCC supports the unused attribute */ +#ifdef __GNUC__ +#define pg_attribute_unused() __attribute__((unused)) +#else +#define pg_attribute_unused() +#endif + +/* + * pg_nodiscard means the compiler should warn if the result of a function + * call is ignored. The name "nodiscard" is chosen in alignment with + * (possibly future) C and C++ standards. For maximum compatibility, use it + * as a function declaration specifier, so it goes before the return type. + */ +#ifdef __GNUC__ +#define pg_nodiscard __attribute__((warn_unused_result)) +#else +#define pg_nodiscard +#endif + +/* + * Place this macro before functions that should be allowed to make misaligned + * accesses. Think twice before using it on non-x86-specific code! + * Testing can be done with "-fsanitize=alignment -fsanitize-trap=alignment" + * on clang, or "-fsanitize=alignment -fno-sanitize-recover=alignment" on gcc. + */ +#if __clang_major__ >= 7 || __GNUC__ >= 8 +#define pg_attribute_no_sanitize_alignment() __attribute__((no_sanitize("alignment"))) +#else +#define pg_attribute_no_sanitize_alignment() +#endif + +/* + * Append PG_USED_FOR_ASSERTS_ONLY to definitions of variables that are only + * used in assert-enabled builds, to avoid compiler warnings about unused + * variables in assert-disabled builds. + */ +#ifdef USE_ASSERT_CHECKING +#define PG_USED_FOR_ASSERTS_ONLY +#else +#define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused() +#endif + +/* GCC and XLC support format attributes */ +#if defined(__GNUC__) || defined(__IBMC__) +#define pg_attribute_format_arg(a) __attribute__((format_arg(a))) +#define pg_attribute_printf(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE, f, a))) +#else +#define pg_attribute_format_arg(a) +#define pg_attribute_printf(f,a) +#endif + +/* GCC, Sunpro and XLC support aligned, packed and noreturn */ +#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) +#define pg_attribute_aligned(a) __attribute__((aligned(a))) +#define pg_attribute_noreturn() __attribute__((noreturn)) +#define pg_attribute_packed() __attribute__((packed)) +#define HAVE_PG_ATTRIBUTE_NORETURN 1 +#else +/* + * NB: aligned and packed are not given default definitions because they + * affect code functionality; they *must* be implemented by the compiler + * if they are to be used. + */ +#define pg_attribute_noreturn() +#endif + +/* + * Use "pg_attribute_always_inline" in place of "inline" for functions that + * we wish to force inlining of, even when the compiler's heuristics would + * choose not to. But, if possible, don't force inlining in unoptimized + * debug builds. + */ +#if (defined(__GNUC__) && __GNUC__ > 3 && defined(__OPTIMIZE__)) || defined(__SUNPRO_C) || defined(__IBMC__) +/* GCC > 3, Sunpro and XLC support always_inline via __attribute__ */ +#define pg_attribute_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +/* MSVC has a special keyword for this */ +#define pg_attribute_always_inline __forceinline +#else +/* Otherwise, the best we can do is to say "inline" */ +#define pg_attribute_always_inline inline +#endif + +/* + * Forcing a function not to be inlined can be useful if it's the slow path of + * a performance-critical function, or should be visible in profiles to allow + * for proper cost attribution. Note that unlike the pg_attribute_XXX macros + * above, this should be placed before the function's return type and name. + */ +/* GCC, Sunpro and XLC support noinline via __attribute__ */ +#if (defined(__GNUC__) && __GNUC__ > 2) || defined(__SUNPRO_C) || defined(__IBMC__) +#define pg_noinline __attribute__((noinline)) +/* msvc via declspec */ +#elif defined(_MSC_VER) +#define pg_noinline __declspec(noinline) +#else +#define pg_noinline +#endif + +/* + * For now, just define pg_attribute_cold and pg_attribute_hot to be empty + * macros on minGW 8.1. There appears to be a compiler bug that results in + * compilation failure. At this time, we still have at least one buildfarm + * animal running that compiler, so this should make that green again. It's + * likely this compiler is not popular enough to warrant keeping this code + * around forever, so let's just remove it once the last buildfarm animal + * upgrades. + */ +#if defined(__MINGW64__) && __GNUC__ == 8 && __GNUC_MINOR__ == 1 + +#define pg_attribute_cold +#define pg_attribute_hot + +#else +/* + * Marking certain functions as "hot" or "cold" can be useful to assist the + * compiler in arranging the assembly code in a more efficient way. + */ +#if __has_attribute (cold) +#define pg_attribute_cold __attribute__((cold)) +#else +#define pg_attribute_cold +#endif + +#if __has_attribute (hot) +#define pg_attribute_hot __attribute__((hot)) +#else +#define pg_attribute_hot +#endif + +#endif /* defined(__MINGW64__) && __GNUC__ == 8 && + * __GNUC_MINOR__ == 1 */ +/* + * Mark a point as unreachable in a portable fashion. This should preferably + * be something that the compiler understands, to aid code generation. + * In assert-enabled builds, we prefer abort() for debugging reasons. + */ +#if defined(HAVE__BUILTIN_UNREACHABLE) && !defined(USE_ASSERT_CHECKING) +#define pg_unreachable() __builtin_unreachable() +#elif defined(_MSC_VER) && !defined(USE_ASSERT_CHECKING) +#define pg_unreachable() __assume(0) +#else +#define pg_unreachable() abort() +#endif + +/* + * Hints to the compiler about the likelihood of a branch. Both likely() and + * unlikely() return the boolean value of the contained expression. + * + * These should only be used sparingly, in very hot code paths. It's very easy + * to mis-estimate likelihoods. + */ +#if __GNUC__ >= 3 +#define likely(x) __builtin_expect((x) != 0, 1) +#define unlikely(x) __builtin_expect((x) != 0, 0) +#else +#define likely(x) ((x) != 0) +#define unlikely(x) ((x) != 0) +#endif + +/* + * CppAsString + * Convert the argument to a string, using the C preprocessor. + * CppAsString2 + * Convert the argument to a string, after one round of macro expansion. + * CppConcat + * Concatenate two arguments together, using the C preprocessor. + * + * Note: There used to be support here for pre-ANSI C compilers that didn't + * support # and ##. Nowadays, these macros are just for clarity and/or + * backward compatibility with existing PostgreSQL code. + */ +#define CppAsString(identifier) #identifier +#define CppAsString2(x) CppAsString(x) +#define CppConcat(x, y) x##y + +/* + * VA_ARGS_NARGS + * Returns the number of macro arguments it is passed. + * + * An empty argument still counts as an argument, so effectively, this is + * "one more than the number of commas in the argument list". + * + * This works for up to 63 arguments. Internally, VA_ARGS_NARGS_() is passed + * 64+N arguments, and the C99 standard only requires macros to allow up to + * 127 arguments, so we can't portably go higher. The implementation is + * pretty trivial: VA_ARGS_NARGS_() returns its 64th argument, and we set up + * the call so that that is the appropriate one of the list of constants. + * This idea is due to Laurent Deniau. + */ +#define VA_ARGS_NARGS(...) \ + VA_ARGS_NARGS_(__VA_ARGS__, \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define VA_ARGS_NARGS_( \ + _01,_02,_03,_04,_05,_06,_07,_08,_09,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63, N, ...) \ + (N) + +/* + * dummyret is used to set return values in macros that use ?: to make + * assignments. gcc wants these to be void, other compilers like char + */ +#ifdef __GNUC__ /* GNU cc */ +#define dummyret void +#else +#define dummyret char +#endif + +/* + * Generic function pointer. This can be used in the rare cases where it's + * necessary to cast a function pointer to a seemingly incompatible function + * pointer type while avoiding gcc's -Wcast-function-type warnings. + */ +typedef void (*pg_funcptr_t) (void); + +/* + * We require C99, hence the compiler should understand flexible array + * members. However, for documentation purposes we still consider it to be + * project style to write "field[FLEXIBLE_ARRAY_MEMBER]" not just "field[]". + * When computing the size of such an object, use "offsetof(struct s, f)" + * for portability. Don't use "offsetof(struct s, f[0])", as this doesn't + * work with MSVC and with C++ compilers. + */ +#define FLEXIBLE_ARRAY_MEMBER /* empty */ + +/* Which __func__ symbol do we have, if any? */ +#ifdef HAVE_FUNCNAME__FUNC +#define PG_FUNCNAME_MACRO __func__ +#else +#ifdef HAVE_FUNCNAME__FUNCTION +#define PG_FUNCNAME_MACRO __FUNCTION__ +#else +#define PG_FUNCNAME_MACRO NULL +#endif +#endif + +/* + * Does the compiler support #pragma GCC system_header? We optionally use it + * to avoid warnings that we can't fix (e.g. in the perl headers). + * See https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html + * + * Headers for which we do not want to show compiler warnings can, + * conditionally, use #pragma GCC system_header to avoid warnings. Obviously + * this should only be used for external headers over which we do not have + * control. + * + * Support for the pragma is tested here, instead of during configure, as gcc + * also warns about the pragma being used in a .c file. It's surprisingly hard + * to get autoconf to use .h as the file-ending. Looks like gcc has + * implemented the pragma since the 2000, so this test should suffice. + * + * + * Alternatively, we could add the include paths for problematic headers with + * -isystem, but that is a larger hammer and is harder to search for. + * + * A more granular alternative would be to use #pragma GCC diagnostic + * push/ignored/pop, but gcc warns about unknown warnings being ignored, so + * every to-be-ignored-temporarily compiler warning would require its own + * pg_config.h symbol and #ifdef. + */ +#ifdef __GNUC__ +#define HAVE_PRAGMA_GCC_SYSTEM_HEADER 1 +#endif + + +/* ---------------------------------------------------------------- + * Section 2: bool, true, false + * ---------------------------------------------------------------- + */ + +/* + * bool + * Boolean value, either true or false. + * + * We use stdbool.h if available and its bool has size 1. That's useful for + * better compiler and debugger output and for compatibility with third-party + * libraries. But PostgreSQL currently cannot deal with bool of other sizes; + * there are static assertions around the code to prevent that. + * + * For C++ compilers, we assume the compiler has a compatible built-in + * definition of bool. + * + * See also the version of this code in src/interfaces/ecpg/include/ecpglib.h. + */ + +#ifndef __cplusplus + +#ifdef PG_USE_STDBOOL +#include <stdbool.h> +#else + +#ifndef bool +typedef unsigned char bool; +#endif + +#ifndef true +#define true ((bool) 1) +#endif + +#ifndef false +#define false ((bool) 0) +#endif + +#endif /* not PG_USE_STDBOOL */ +#endif /* not C++ */ + + +/* ---------------------------------------------------------------- + * Section 3: standard system types + * ---------------------------------------------------------------- + */ + +/* + * Pointer + * Variable holding address of any memory resident object. + * + * XXX Pointer arithmetic is done with this, so it can't be void * + * under "true" ANSI compilers. + */ +typedef char *Pointer; + +/* + * intN + * Signed integer, EXACTLY N BITS IN SIZE, + * used for numerical computations and the + * frontend/backend protocol. + */ +#ifndef HAVE_INT8 +typedef signed char int8; /* == 8 bits */ +typedef signed short int16; /* == 16 bits */ +typedef signed int int32; /* == 32 bits */ +#endif /* not HAVE_INT8 */ + +/* + * uintN + * Unsigned integer, EXACTLY N BITS IN SIZE, + * used for numerical computations and the + * frontend/backend protocol. + */ +#ifndef HAVE_UINT8 +typedef unsigned char uint8; /* == 8 bits */ +typedef unsigned short uint16; /* == 16 bits */ +typedef unsigned int uint32; /* == 32 bits */ +#endif /* not HAVE_UINT8 */ + +/* + * bitsN + * Unit of bitwise operation, AT LEAST N BITS IN SIZE. + */ +typedef uint8 bits8; /* >= 8 bits */ +typedef uint16 bits16; /* >= 16 bits */ +typedef uint32 bits32; /* >= 32 bits */ + +/* + * 64-bit integers + */ +#ifdef HAVE_LONG_INT_64 +/* Plain "long int" fits, use it */ + +#ifndef HAVE_INT64 +typedef long int int64; +#endif +#ifndef HAVE_UINT64 +typedef unsigned long int uint64; +#endif +#define INT64CONST(x) (x##L) +#define UINT64CONST(x) (x##UL) +#elif defined(HAVE_LONG_LONG_INT_64) +/* We have working support for "long long int", use that */ + +#ifndef HAVE_INT64 +typedef long long int int64; +#endif +#ifndef HAVE_UINT64 +typedef unsigned long long int uint64; +#endif +#define INT64CONST(x) (x##LL) +#define UINT64CONST(x) (x##ULL) +#else +/* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */ +#error must have a working 64-bit integer datatype +#endif + +/* snprintf format strings to use for 64-bit integers */ +#define INT64_FORMAT "%" INT64_MODIFIER "d" +#define UINT64_FORMAT "%" INT64_MODIFIER "u" + +/* + * 128-bit signed and unsigned integers + * There currently is only limited support for such types. + * E.g. 128bit literals and snprintf are not supported; but math is. + * Also, because we exclude such types when choosing MAXIMUM_ALIGNOF, + * it must be possible to coerce the compiler to allocate them on no + * more than MAXALIGN boundaries. + */ +#if defined(PG_INT128_TYPE) +#if defined(pg_attribute_aligned) || ALIGNOF_PG_INT128_TYPE <= MAXIMUM_ALIGNOF +#define HAVE_INT128 1 + +typedef PG_INT128_TYPE int128 +#if defined(pg_attribute_aligned) + pg_attribute_aligned(MAXIMUM_ALIGNOF) +#endif + ; + +typedef unsigned PG_INT128_TYPE uint128 +#if defined(pg_attribute_aligned) + pg_attribute_aligned(MAXIMUM_ALIGNOF) +#endif + ; + +#endif +#endif + +/* + * stdint.h limits aren't guaranteed to have compatible types with our fixed + * width types. So just define our own. + */ +#define PG_INT8_MIN (-0x7F-1) +#define PG_INT8_MAX (0x7F) +#define PG_UINT8_MAX (0xFF) +#define PG_INT16_MIN (-0x7FFF-1) +#define PG_INT16_MAX (0x7FFF) +#define PG_UINT16_MAX (0xFFFF) +#define PG_INT32_MIN (-0x7FFFFFFF-1) +#define PG_INT32_MAX (0x7FFFFFFF) +#define PG_UINT32_MAX (0xFFFFFFFFU) +#define PG_INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1) +#define PG_INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF) +#define PG_UINT64_MAX UINT64CONST(0xFFFFFFFFFFFFFFFF) + +/* + * We now always use int64 timestamps, but keep this symbol defined for the + * benefit of external code that might test it. + */ +#define HAVE_INT64_TIMESTAMP + +/* + * Size + * Size of any memory resident object, as returned by sizeof. + */ +typedef size_t Size; + +/* + * Index + * Index into any memory resident array. + * + * Note: + * Indices are non negative. + */ +typedef unsigned int Index; + +/* + * Offset + * Offset into any memory resident array. + * + * Note: + * This differs from an Index in that an Index is always + * non negative, whereas Offset may be negative. + */ +typedef signed int Offset; + +/* + * Common Postgres datatype names (as used in the catalogs) + */ +typedef float float4; +typedef double float8; + +#ifdef USE_FLOAT8_BYVAL +#define FLOAT8PASSBYVAL true +#else +#define FLOAT8PASSBYVAL false +#endif + +/* + * Oid, RegProcedure, TransactionId, SubTransactionId, MultiXactId, + * CommandId + */ + +/* typedef Oid is in postgres_ext.h */ + +/* + * regproc is the type name used in the include/catalog headers, but + * RegProcedure is the preferred name in C code. + */ +typedef Oid regproc; +typedef regproc RegProcedure; + +typedef uint32 TransactionId; + +typedef uint32 LocalTransactionId; + +typedef uint32 SubTransactionId; + +#define InvalidSubTransactionId ((SubTransactionId) 0) +#define TopSubTransactionId ((SubTransactionId) 1) + +/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */ +typedef TransactionId MultiXactId; + +typedef uint32 MultiXactOffset; + +typedef uint32 CommandId; + +#define FirstCommandId ((CommandId) 0) +#define InvalidCommandId (~(CommandId)0) + + +/* ---------------- + * Variable-length datatypes all share the 'struct varlena' header. + * + * NOTE: for TOASTable types, this is an oversimplification, since the value + * may be compressed or moved out-of-line. However datatype-specific routines + * are mostly content to deal with de-TOASTed values only, and of course + * client-side routines should never see a TOASTed value. But even in a + * de-TOASTed value, beware of touching vl_len_ directly, as its + * representation is no longer convenient. It's recommended that code always + * use macros VARDATA_ANY, VARSIZE_ANY, VARSIZE_ANY_EXHDR, VARDATA, VARSIZE, + * and SET_VARSIZE instead of relying on direct mentions of the struct fields. + * See postgres.h for details of the TOASTed form. + * ---------------- + */ +struct varlena +{ + char vl_len_[4]; /* Do not touch this field directly! */ + char vl_dat[FLEXIBLE_ARRAY_MEMBER]; /* Data content is here */ +}; + +#define VARHDRSZ ((int32) sizeof(int32)) + +/* + * These widely-used datatypes are just a varlena header and the data bytes. + * There is no terminating null or anything like that --- the data length is + * always VARSIZE_ANY_EXHDR(ptr). + */ +typedef struct varlena bytea; +typedef struct varlena text; +typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */ +typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */ + +/* + * Specialized array types. These are physically laid out just the same + * as regular arrays (so that the regular array subscripting code works + * with them). They exist as distinct types mostly for historical reasons: + * they have nonstandard I/O behavior which we don't want to change for fear + * of breaking applications that look at the system catalogs. There is also + * an implementation issue for oidvector: it's part of the primary key for + * pg_proc, and we can't use the normal btree array support routines for that + * without circularity. + */ +typedef struct +{ + int32 vl_len_; /* these fields must match ArrayType! */ + int ndim; /* always 1 for int2vector */ + int32 dataoffset; /* always 0 for int2vector */ + Oid elemtype; + int dim1; + int lbound1; + int16 values[FLEXIBLE_ARRAY_MEMBER]; +} int2vector; + +typedef struct +{ + int32 vl_len_; /* these fields must match ArrayType! */ + int ndim; /* always 1 for oidvector */ + int32 dataoffset; /* always 0 for oidvector */ + Oid elemtype; + int dim1; + int lbound1; + Oid values[FLEXIBLE_ARRAY_MEMBER]; +} oidvector; + +/* + * Representation of a Name: effectively just a C string, but null-padded to + * exactly NAMEDATALEN bytes. The use of a struct is historical. + */ +typedef struct nameData +{ + char data[NAMEDATALEN]; +} NameData; +typedef NameData *Name; + +#define NameStr(name) ((name).data) + + +/* ---------------------------------------------------------------- + * Section 4: IsValid macros for system types + * ---------------------------------------------------------------- + */ +/* + * BoolIsValid + * True iff bool is valid. + */ +#define BoolIsValid(boolean) ((boolean) == false || (boolean) == true) + +/* + * PointerIsValid + * True iff pointer is valid. + */ +#define PointerIsValid(pointer) ((const void*)(pointer) != NULL) + +/* + * PointerIsAligned + * True iff pointer is properly aligned to point to the given type. + */ +#define PointerIsAligned(pointer, type) \ + (((uintptr_t)(pointer) % (sizeof (type))) == 0) + +#define OffsetToPointer(base, offset) \ + ((void *)((char *) base + offset)) + +#define OidIsValid(objectId) ((bool) ((objectId) != InvalidOid)) + +#define RegProcedureIsValid(p) OidIsValid(p) + + +/* ---------------------------------------------------------------- + * Section 5: offsetof, lengthof, alignment + * ---------------------------------------------------------------- + */ +/* + * offsetof + * Offset of a structure/union field within that structure/union. + * + * XXX This is supposed to be part of stddef.h, but isn't on + * some systems (like SunOS 4). + */ +#ifndef offsetof +#define offsetof(type, field) ((long) &((type *)0)->field) +#endif /* offsetof */ + +/* + * lengthof + * Number of elements in an array. + */ +#define lengthof(array) (sizeof (array) / sizeof ((array)[0])) + +/* ---------------- + * Alignment macros: align a length or address appropriately for a given type. + * The fooALIGN() macros round up to a multiple of the required alignment, + * while the fooALIGN_DOWN() macros round down. The latter are more useful + * for problems like "how many X-sized structures will fit in a page?". + * + * NOTE: TYPEALIGN[_DOWN] will not work if ALIGNVAL is not a power of 2. + * That case seems extremely unlikely to be needed in practice, however. + * + * NOTE: MAXIMUM_ALIGNOF, and hence MAXALIGN(), intentionally exclude any + * larger-than-8-byte types the compiler might have. + * ---------------- + */ + +#define TYPEALIGN(ALIGNVAL,LEN) \ + (((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((uintptr_t) ((ALIGNVAL) - 1))) + +#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN)) +#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN)) +#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN)) +#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN)) +#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN)) +/* MAXALIGN covers only built-in types, not buffers */ +#define BUFFERALIGN(LEN) TYPEALIGN(ALIGNOF_BUFFER, (LEN)) +#define CACHELINEALIGN(LEN) TYPEALIGN(PG_CACHE_LINE_SIZE, (LEN)) + +#define TYPEALIGN_DOWN(ALIGNVAL,LEN) \ + (((uintptr_t) (LEN)) & ~((uintptr_t) ((ALIGNVAL) - 1))) + +#define SHORTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_SHORT, (LEN)) +#define INTALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_INT, (LEN)) +#define LONGALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN)) +#define DOUBLEALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN)) +#define MAXALIGN_DOWN(LEN) TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN)) +#define BUFFERALIGN_DOWN(LEN) TYPEALIGN_DOWN(ALIGNOF_BUFFER, (LEN)) + +/* + * The above macros will not work with types wider than uintptr_t, like with + * uint64 on 32-bit platforms. That's not problem for the usual use where a + * pointer or a length is aligned, but for the odd case that you need to + * align something (potentially) wider, use TYPEALIGN64. + */ +#define TYPEALIGN64(ALIGNVAL,LEN) \ + (((uint64) (LEN) + ((ALIGNVAL) - 1)) & ~((uint64) ((ALIGNVAL) - 1))) + +/* we don't currently need wider versions of the other ALIGN macros */ +#define MAXALIGN64(LEN) TYPEALIGN64(MAXIMUM_ALIGNOF, (LEN)) + + +/* ---------------------------------------------------------------- + * Section 6: assertions + * ---------------------------------------------------------------- + */ + +/* + * USE_ASSERT_CHECKING, if defined, turns on all the assertions. + * - plai 9/5/90 + * + * It should _NOT_ be defined in releases or in benchmark copies + */ + +/* + * Assert() can be used in both frontend and backend code. In frontend code it + * just calls the standard assert, if it's available. If use of assertions is + * not configured, it does nothing. + */ +#ifndef USE_ASSERT_CHECKING + +#define Assert(condition) ((void)true) +#define AssertMacro(condition) ((void)true) +#define AssertArg(condition) ((void)true) +#define AssertState(condition) ((void)true) +#define AssertPointerAlignment(ptr, bndr) ((void)true) +#define Trap(condition, errorType) ((void)true) +#define TrapMacro(condition, errorType) (true) + +#elif defined(FRONTEND) + +#include <assert.h> +#define Assert(p) assert(p) +#define AssertMacro(p) ((void) assert(p)) +#define AssertArg(condition) assert(condition) +#define AssertState(condition) assert(condition) +#define AssertPointerAlignment(ptr, bndr) ((void)true) + +#else /* USE_ASSERT_CHECKING && !FRONTEND */ + +/* + * Trap + * Generates an exception if the given condition is true. + */ +#define Trap(condition, errorType) \ + do { \ + if (condition) \ + ExceptionalCondition(#condition, (errorType), \ + __FILE__, __LINE__); \ + } while (0) + +/* + * TrapMacro is the same as Trap but it's intended for use in macros: + * + * #define foo(x) (AssertMacro(x != 0), bar(x)) + * + * Isn't CPP fun? + */ +#define TrapMacro(condition, errorType) \ + ((bool) (! (condition) || \ + (ExceptionalCondition(#condition, (errorType), \ + __FILE__, __LINE__), 0))) + +#define Assert(condition) \ + do { \ + if (!(condition)) \ + ExceptionalCondition(#condition, "FailedAssertion", \ + __FILE__, __LINE__); \ + } while (0) + +#define AssertMacro(condition) \ + ((void) ((condition) || \ + (ExceptionalCondition(#condition, "FailedAssertion", \ + __FILE__, __LINE__), 0))) + +#define AssertArg(condition) \ + do { \ + if (!(condition)) \ + ExceptionalCondition(#condition, "BadArgument", \ + __FILE__, __LINE__); \ + } while (0) + +#define AssertState(condition) \ + do { \ + if (!(condition)) \ + ExceptionalCondition(#condition, "BadState", \ + __FILE__, __LINE__); \ + } while (0) + +/* + * Check that `ptr' is `bndr' aligned. + */ +#define AssertPointerAlignment(ptr, bndr) \ + Trap(TYPEALIGN(bndr, (uintptr_t)(ptr)) != (uintptr_t)(ptr), \ + "UnalignedPointer") + +#endif /* USE_ASSERT_CHECKING && !FRONTEND */ + +/* + * ExceptionalCondition is compiled into the backend whether or not + * USE_ASSERT_CHECKING is defined, so as to support use of extensions + * that are built with that #define with a backend that isn't. Hence, + * we should declare it as long as !FRONTEND. + */ +#ifndef FRONTEND +extern void ExceptionalCondition(const char *conditionName, + const char *errorType, + const char *fileName, int lineNumber) pg_attribute_noreturn(); +#endif + +/* + * Macros to support compile-time assertion checks. + * + * If the "condition" (a compile-time-constant expression) evaluates to false, + * throw a compile error using the "errmessage" (a string literal). + * + * gcc 4.6 and up supports _Static_assert(), but there are bizarre syntactic + * placement restrictions. Macros StaticAssertStmt() and StaticAssertExpr() + * make it safe to use as a statement or in an expression, respectively. + * The macro StaticAssertDecl() is suitable for use at file scope (outside of + * any function). + * + * Otherwise we fall back on a kluge that assumes the compiler will complain + * about a negative width for a struct bit-field. This will not include a + * helpful error message, but it beats not getting an error at all. + */ +#ifndef __cplusplus +#ifdef HAVE__STATIC_ASSERT +#define StaticAssertStmt(condition, errmessage) \ + do { _Static_assert(condition, errmessage); } while(0) +#define StaticAssertExpr(condition, errmessage) \ + ((void) ({ StaticAssertStmt(condition, errmessage); true; })) +#define StaticAssertDecl(condition, errmessage) \ + _Static_assert(condition, errmessage) +#else /* !HAVE__STATIC_ASSERT */ +#define StaticAssertStmt(condition, errmessage) \ + ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; })) +#define StaticAssertExpr(condition, errmessage) \ + StaticAssertStmt(condition, errmessage) +#define StaticAssertDecl(condition, errmessage) \ + extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1]) +#endif /* HAVE__STATIC_ASSERT */ +#else /* C++ */ +#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410 +#define StaticAssertStmt(condition, errmessage) \ + static_assert(condition, errmessage) +#define StaticAssertExpr(condition, errmessage) \ + ({ static_assert(condition, errmessage); }) +#define StaticAssertDecl(condition, errmessage) \ + static_assert(condition, errmessage) +#else /* !__cpp_static_assert */ +#define StaticAssertStmt(condition, errmessage) \ + do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0) +#define StaticAssertExpr(condition, errmessage) \ + ((void) ({ StaticAssertStmt(condition, errmessage); })) +#define StaticAssertDecl(condition, errmessage) \ + extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1]) +#endif /* __cpp_static_assert */ +#endif /* C++ */ + + +/* + * Compile-time checks that a variable (or expression) has the specified type. + * + * AssertVariableIsOfType() can be used as a statement. + * AssertVariableIsOfTypeMacro() is intended for use in macros, eg + * #define foo(x) (AssertVariableIsOfTypeMacro(x, int), bar(x)) + * + * If we don't have __builtin_types_compatible_p, we can still assert that + * the types have the same size. This is far from ideal (especially on 32-bit + * platforms) but it provides at least some coverage. + */ +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define AssertVariableIsOfType(varname, typename) \ + StaticAssertStmt(__builtin_types_compatible_p(__typeof__(varname), typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) +#define AssertVariableIsOfTypeMacro(varname, typename) \ + (StaticAssertExpr(__builtin_types_compatible_p(__typeof__(varname), typename), \ + CppAsString(varname) " does not have type " CppAsString(typename))) +#else /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */ +#define AssertVariableIsOfType(varname, typename) \ + StaticAssertStmt(sizeof(varname) == sizeof(typename), \ + CppAsString(varname) " does not have type " CppAsString(typename)) +#define AssertVariableIsOfTypeMacro(varname, typename) \ + (StaticAssertExpr(sizeof(varname) == sizeof(typename), \ + CppAsString(varname) " does not have type " CppAsString(typename))) +#endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */ + + +/* ---------------------------------------------------------------- + * Section 7: widely useful macros + * ---------------------------------------------------------------- + */ +/* + * Max + * Return the maximum of two numbers. + */ +#define Max(x, y) ((x) > (y) ? (x) : (y)) + +/* + * Min + * Return the minimum of two numbers. + */ +#define Min(x, y) ((x) < (y) ? (x) : (y)) + +/* + * Abs + * Return the absolute value of the argument. + */ +#define Abs(x) ((x) >= 0 ? (x) : -(x)) + + +/* Get a bit mask of the bits set in non-long aligned addresses */ +#define LONG_ALIGN_MASK (sizeof(long) - 1) + +/* + * MemSet + * Exactly the same as standard library function memset(), but considerably + * faster for zeroing small word-aligned structures (such as parsetree nodes). + * This has to be a macro because the main point is to avoid function-call + * overhead. However, we have also found that the loop is faster than + * native libc memset() on some platforms, even those with assembler + * memset() functions. More research needs to be done, perhaps with + * MEMSET_LOOP_LIMIT tests in configure. + */ +#define MemSet(start, val, len) \ + do \ + { \ + /* must be void* because we don't know if it is integer aligned yet */ \ + void *_vstart = (void *) (start); \ + int _val = (val); \ + Size _len = (len); \ +\ + if ((((uintptr_t) _vstart) & LONG_ALIGN_MASK) == 0 && \ + (_len & LONG_ALIGN_MASK) == 0 && \ + _val == 0 && \ + _len <= MEMSET_LOOP_LIMIT && \ + /* \ + * If MEMSET_LOOP_LIMIT == 0, optimizer should find \ + * the whole "if" false at compile time. \ + */ \ + MEMSET_LOOP_LIMIT != 0) \ + { \ + long *_start = (long *) _vstart; \ + long *_stop = (long *) ((char *) _start + _len); \ + while (_start < _stop) \ + *_start++ = 0; \ + } \ + else \ + memset(_vstart, _val, _len); \ + } while (0) + +/* + * MemSetAligned is the same as MemSet except it omits the test to see if + * "start" is word-aligned. This is okay to use if the caller knows a-priori + * that the pointer is suitably aligned (typically, because he just got it + * from palloc(), which always delivers a max-aligned pointer). + */ +#define MemSetAligned(start, val, len) \ + do \ + { \ + long *_start = (long *) (start); \ + int _val = (val); \ + Size _len = (len); \ +\ + if ((_len & LONG_ALIGN_MASK) == 0 && \ + _val == 0 && \ + _len <= MEMSET_LOOP_LIMIT && \ + MEMSET_LOOP_LIMIT != 0) \ + { \ + long *_stop = (long *) ((char *) _start + _len); \ + while (_start < _stop) \ + *_start++ = 0; \ + } \ + else \ + memset(_start, _val, _len); \ + } while (0) + + +/* + * MemSetTest/MemSetLoop are a variant version that allow all the tests in + * MemSet to be done at compile time in cases where "val" and "len" are + * constants *and* we know the "start" pointer must be word-aligned. + * If MemSetTest succeeds, then it is okay to use MemSetLoop, otherwise use + * MemSetAligned. Beware of multiple evaluations of the arguments when using + * this approach. + */ +#define MemSetTest(val, len) \ + ( ((len) & LONG_ALIGN_MASK) == 0 && \ + (len) <= MEMSET_LOOP_LIMIT && \ + MEMSET_LOOP_LIMIT != 0 && \ + (val) == 0 ) + +#define MemSetLoop(start, val, len) \ + do \ + { \ + long * _start = (long *) (start); \ + long * _stop = (long *) ((char *) _start + (Size) (len)); \ + \ + while (_start < _stop) \ + *_start++ = 0; \ + } while (0) + +/* + * Macros for range-checking float values before converting to integer. + * We must be careful here that the boundary values are expressed exactly + * in the float domain. PG_INTnn_MIN is an exact power of 2, so it will + * be represented exactly; but PG_INTnn_MAX isn't, and might get rounded + * off, so avoid using that. + * The input must be rounded to an integer beforehand, typically with rint(), + * else we might draw the wrong conclusion about close-to-the-limit values. + * These macros will do the right thing for Inf, but not necessarily for NaN, + * so check isnan(num) first if that's a possibility. + */ +#define FLOAT4_FITS_IN_INT16(num) \ + ((num) >= (float4) PG_INT16_MIN && (num) < -((float4) PG_INT16_MIN)) +#define FLOAT4_FITS_IN_INT32(num) \ + ((num) >= (float4) PG_INT32_MIN && (num) < -((float4) PG_INT32_MIN)) +#define FLOAT4_FITS_IN_INT64(num) \ + ((num) >= (float4) PG_INT64_MIN && (num) < -((float4) PG_INT64_MIN)) +#define FLOAT8_FITS_IN_INT16(num) \ + ((num) >= (float8) PG_INT16_MIN && (num) < -((float8) PG_INT16_MIN)) +#define FLOAT8_FITS_IN_INT32(num) \ + ((num) >= (float8) PG_INT32_MIN && (num) < -((float8) PG_INT32_MIN)) +#define FLOAT8_FITS_IN_INT64(num) \ + ((num) >= (float8) PG_INT64_MIN && (num) < -((float8) PG_INT64_MIN)) + + +/* ---------------------------------------------------------------- + * Section 8: random stuff + * ---------------------------------------------------------------- + */ + +#ifdef HAVE_STRUCT_SOCKADDR_UN +#define HAVE_UNIX_SOCKETS 1 +#endif + +/* + * Invert the sign of a qsort-style comparison result, ie, exchange negative + * and positive integer values, being careful not to get the wrong answer + * for INT_MIN. The argument should be an integral variable. + */ +#define INVERT_COMPARE_RESULT(var) \ + ((var) = ((var) < 0) ? 1 : -(var)) + +/* + * Use this, not "char buf[BLCKSZ]", to declare a field or local variable + * holding a page buffer, if that page might be accessed as a page and not + * just a string of bytes. Otherwise the variable might be under-aligned, + * causing problems on alignment-picky hardware. (In some places, we use + * this to declare buffers even though we only pass them to read() and + * write(), because copying to/from aligned buffers is usually faster than + * using unaligned buffers.) We include both "double" and "int64" in the + * union to ensure that the compiler knows the value must be MAXALIGN'ed + * (cf. configure's computation of MAXIMUM_ALIGNOF). + */ +typedef union PGAlignedBlock +{ + char data[BLCKSZ]; + double force_align_d; + int64 force_align_i64; +} PGAlignedBlock; + +/* Same, but for an XLOG_BLCKSZ-sized buffer */ +typedef union PGAlignedXLogBlock +{ + char data[XLOG_BLCKSZ]; + double force_align_d; + int64 force_align_i64; +} PGAlignedXLogBlock; + +/* msb for char */ +#define HIGHBIT (0x80) +#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT) + +/* + * Support macros for escaping strings. escape_backslash should be true + * if generating a non-standard-conforming string. Prefixing a string + * with ESCAPE_STRING_SYNTAX guarantees it is non-standard-conforming. + * Beware of multiple evaluation of the "ch" argument! + */ +#define SQL_STR_DOUBLE(ch, escape_backslash) \ + ((ch) == '\'' || ((ch) == '\\' && (escape_backslash))) + +#define ESCAPE_STRING_SYNTAX 'E' + + +#define STATUS_OK (0) +#define STATUS_ERROR (-1) +#define STATUS_EOF (-2) + +/* + * gettext support + */ + +#ifndef ENABLE_NLS +/* stuff we'd otherwise get from <libintl.h> */ +#define gettext(x) (x) +#define dgettext(d,x) (x) +#define ngettext(s,p,n) ((n) == 1 ? (s) : (p)) +#define dngettext(d,s,p,n) ((n) == 1 ? (s) : (p)) +#endif + +#define _(x) gettext(x) + +/* + * Use this to mark string constants as needing translation at some later + * time, rather than immediately. This is useful for cases where you need + * access to the original string and translated string, and for cases where + * immediate translation is not possible, like when initializing global + * variables. + * + * https://www.gnu.org/software/gettext/manual/html_node/Special-cases.html + */ +#define gettext_noop(x) (x) + +/* + * To better support parallel installations of major PostgreSQL + * versions as well as parallel installations of major library soname + * versions, we mangle the gettext domain name by appending those + * version numbers. The coding rule ought to be that wherever the + * domain name is mentioned as a literal, it must be wrapped into + * PG_TEXTDOMAIN(). The macros below do not work on non-literals; but + * that is somewhat intentional because it avoids having to worry + * about multiple states of premangling and postmangling as the values + * are being passed around. + * + * Make sure this matches the installation rules in nls-global.mk. + */ +#ifdef SO_MAJOR_VERSION +#define PG_TEXTDOMAIN(domain) (domain CppAsString2(SO_MAJOR_VERSION) "-" PG_MAJORVERSION) +#else +#define PG_TEXTDOMAIN(domain) (domain "-" PG_MAJORVERSION) +#endif + +/* + * Macro that allows to cast constness and volatile away from an expression, but doesn't + * allow changing the underlying type. Enforcement of the latter + * currently only works for gcc like compilers. + * + * Please note IT IS NOT SAFE to cast constness away if the result will ever + * be modified (it would be undefined behaviour). Doing so anyway can cause + * compiler misoptimizations or runtime crashes (modifying readonly memory). + * It is only safe to use when the result will not be modified, but API + * design or language restrictions prevent you from declaring that + * (e.g. because a function returns both const and non-const variables). + * + * Note that this only works in function scope, not for global variables (it'd + * be nice, but not trivial, to improve that). + */ +#if defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P) +#define unconstify(underlying_type, expr) \ + (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), const underlying_type), \ + "wrong cast"), \ + (underlying_type) (expr)) +#define unvolatize(underlying_type, expr) \ + (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), volatile underlying_type), \ + "wrong cast"), \ + (underlying_type) (expr)) +#else +#define unconstify(underlying_type, expr) \ + ((underlying_type) (expr)) +#define unvolatize(underlying_type, expr) \ + ((underlying_type) (expr)) +#endif + +/* ---------------------------------------------------------------- + * Section 9: system-specific hacks + * + * This should be limited to things that absolutely have to be + * included in every source file. The port-specific header file + * is usually a better place for this sort of thing. + * ---------------------------------------------------------------- + */ + +/* + * NOTE: this is also used for opening text files. + * WIN32 treats Control-Z as EOF in files opened in text mode. + * Therefore, we open files in binary mode on Win32 so we can read + * literal control-Z. The other affect is that we see CRLF, but + * that is OK because we can already handle those cleanly. + */ +#if defined(WIN32) || defined(__CYGWIN__) +#define PG_BINARY O_BINARY +#define PG_BINARY_A "ab" +#define PG_BINARY_R "rb" +#define PG_BINARY_W "wb" +#else +#define PG_BINARY 0 +#define PG_BINARY_A "a" +#define PG_BINARY_R "r" +#define PG_BINARY_W "w" +#endif + +/* + * Provide prototypes for routines not present in a particular machine's + * standard C library. + */ + +#if defined(HAVE_FDATASYNC) && !HAVE_DECL_FDATASYNC +extern int fdatasync(int fildes); +#endif + +/* Older platforms may provide strto[u]ll functionality under other names */ +#if !defined(HAVE_STRTOLL) && defined(HAVE___STRTOLL) +#define strtoll __strtoll +#define HAVE_STRTOLL 1 +#endif + +#if !defined(HAVE_STRTOLL) && defined(HAVE_STRTOQ) +#define strtoll strtoq +#define HAVE_STRTOLL 1 +#endif + +#if !defined(HAVE_STRTOULL) && defined(HAVE___STRTOULL) +#define strtoull __strtoull +#define HAVE_STRTOULL 1 +#endif + +#if !defined(HAVE_STRTOULL) && defined(HAVE_STRTOUQ) +#define strtoull strtouq +#define HAVE_STRTOULL 1 +#endif + +#if defined(HAVE_STRTOLL) && !HAVE_DECL_STRTOLL +extern long long strtoll(const char *str, char **endptr, int base); +#endif + +#if defined(HAVE_STRTOULL) && !HAVE_DECL_STRTOULL +extern unsigned long long strtoull(const char *str, char **endptr, int base); +#endif + +/* + * Thin wrappers that convert strings to exactly 64-bit integers, matching our + * definition of int64. (For the naming, compare that POSIX has + * strtoimax()/strtoumax() which return intmax_t/uintmax_t.) + */ +#ifdef HAVE_LONG_INT_64 +#define strtoi64(str, endptr, base) ((int64) strtol(str, endptr, base)) +#define strtou64(str, endptr, base) ((uint64) strtoul(str, endptr, base)) +#else +#define strtoi64(str, endptr, base) ((int64) strtoll(str, endptr, base)) +#define strtou64(str, endptr, base) ((uint64) strtoull(str, endptr, base)) +#endif + +/* + * Use "extern PGDLLIMPORT ..." to declare variables that are defined + * in the core backend and need to be accessible by loadable modules. + * No special marking is required on most ports. + */ +#ifndef PGDLLIMPORT +#define PGDLLIMPORT +#endif + +/* + * Use "extern PGDLLEXPORT ..." to declare functions that are defined in + * loadable modules and need to be callable by the core backend. (Usually, + * this is not necessary because our build process automatically exports + * such symbols, but sometimes manual marking is required.) + * No special marking is required on most ports. + */ +#ifndef PGDLLEXPORT +#define PGDLLEXPORT +#endif + +/* + * The following is used as the arg list for signal handlers. Any ports + * that take something other than an int argument should override this in + * their pg_config_os.h file. Note that variable names are required + * because it is used in both the prototypes as well as the definitions. + * Note also the long name. We expect that this won't collide with + * other names causing compiler warnings. + */ + +#ifndef SIGNAL_ARGS +#define SIGNAL_ARGS int postgres_signal_arg +#endif + +/* + * When there is no sigsetjmp, its functionality is provided by plain + * setjmp. We now support the case only on Windows. However, it seems + * that MinGW-64 has some longstanding issues in its setjmp support, + * so on that toolchain we cheat and use gcc's builtins. + */ +#ifdef WIN32 +#ifdef __MINGW64__ +typedef intptr_t sigjmp_buf[5]; +#define sigsetjmp(x,y) __builtin_setjmp(x) +#define siglongjmp __builtin_longjmp +#else /* !__MINGW64__ */ +#define sigjmp_buf jmp_buf +#define sigsetjmp(x,y) setjmp(x) +#define siglongjmp longjmp +#endif /* __MINGW64__ */ +#endif /* WIN32 */ + +/* EXEC_BACKEND defines */ +#ifdef EXEC_BACKEND +#define NON_EXEC_STATIC +#else +#define NON_EXEC_STATIC static +#endif + +/* /port compatibility functions */ +#include "port.h" + +#endif /* C_H */ diff --git a/src/include/catalog/.gitignore b/src/include/catalog/.gitignore new file mode 100644 index 0000000..6b83d4c --- /dev/null +++ b/src/include/catalog/.gitignore @@ -0,0 +1,4 @@ +/schemapg.h +/system_fk_info.h +/pg_*_d.h +/header-stamp diff --git a/src/include/catalog/Makefile b/src/include/catalog/Makefile new file mode 100644 index 0000000..9939491 --- /dev/null +++ b/src/include/catalog/Makefile @@ -0,0 +1,28 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/include/catalog +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/include/catalog +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +# 'make reformat-dat-files' is a convenience target for rewriting the +# catalog data files in our standard format. This includes collapsing +# out any entries that are redundant with a BKI_DEFAULT annotation. +reformat-dat-files: + $(PERL) $(srcdir)/reformat_dat_file.pl --output $(srcdir) $(srcdir)/pg_*.dat + +# 'make expand-dat-files' is a convenience target for expanding out all +# default values in the catalog data files. This should be run before +# altering or removing any BKI_DEFAULT annotation. +expand-dat-files: + $(PERL) $(srcdir)/reformat_dat_file.pl --output $(srcdir) $(srcdir)/pg_*.dat --full-tuples + +.PHONY: reformat-dat-files expand-dat-files diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h new file mode 100644 index 0000000..0b6944b --- /dev/null +++ b/src/include/catalog/binary_upgrade.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------- + * + * binary_upgrade.h + * variables used for binary upgrades + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/binary_upgrade.h + * + *------------------------------------------------------------------------- + */ +#ifndef BINARY_UPGRADE_H +#define BINARY_UPGRADE_H + +extern PGDLLIMPORT Oid binary_upgrade_next_pg_tablespace_oid; + +extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_mrng_pg_type_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_mrng_array_pg_type_oid; + +extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_relfilenode; +extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_relfilenode; +extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_class_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_class_relfilenode; + +extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_pg_authid_oid; + +extern PGDLLIMPORT bool binary_upgrade_record_init_privs; + +#endif /* BINARY_UPGRADE_H */ diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h new file mode 100644 index 0000000..60c1215 --- /dev/null +++ b/src/include/catalog/catalog.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * catalog.h + * prototypes for functions in backend/catalog/catalog.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/catalog.h + * + *------------------------------------------------------------------------- + */ +#ifndef CATALOG_H +#define CATALOG_H + +#include "catalog/pg_class.h" +#include "utils/relcache.h" + + +extern bool IsSystemRelation(Relation relation); +extern bool IsToastRelation(Relation relation); +extern bool IsCatalogRelation(Relation relation); + +extern bool IsSystemClass(Oid relid, Form_pg_class reltuple); +extern bool IsToastClass(Form_pg_class reltuple); + +extern bool IsCatalogRelationOid(Oid relid); + +extern bool IsCatalogNamespace(Oid namespaceId); +extern bool IsToastNamespace(Oid namespaceId); + +extern bool IsReservedName(const char *name); + +extern bool IsSharedRelation(Oid relationId); + +extern bool IsPinnedObject(Oid classId, Oid objectId); + +extern Oid GetNewOidWithIndex(Relation relation, Oid indexId, + AttrNumber oidcolumn); +extern Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, + char relpersistence); + +#endif /* CATALOG_H */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h new file mode 100644 index 0000000..c616a25 --- /dev/null +++ b/src/include/catalog/catversion.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * catversion.h + * "Catalog version number" for PostgreSQL. + * + * The catalog version number is used to flag incompatible changes in + * the PostgreSQL system catalogs. Whenever anyone changes the format of + * a system catalog relation, or adds, deletes, or modifies standard + * catalog entries in such a way that an updated backend wouldn't work + * with an old database (or vice versa), the catalog version number + * should be changed. The version number stored in pg_control by initdb + * is checked against the version number compiled into the backend at + * startup time, so that a backend can refuse to run in an incompatible + * database. + * + * The point of this feature is to provide a finer grain of compatibility + * checking than is possible from looking at the major version number + * stored in PG_VERSION. It shouldn't matter to end users, but during + * development cycles we usually make quite a few incompatible changes + * to the contents of the system catalogs, and we don't want to bump the + * major version number for each one. What we can do instead is bump + * this internal version number. This should save some grief for + * developers who might otherwise waste time tracking down "bugs" that + * are really just code-vs-database incompatibilities. + * + * The rule for developers is: if you commit a change that requires + * an initdb, you should update the catalog version number (as well as + * notifying the pgsql-hackers mailing list, which has been the + * informal practice for a long time). + * + * The catalog version number is placed here since modifying files in + * include/catalog is the most common kind of initdb-forcing change. + * But it could be used to protect any kind of incompatible change in + * database contents or layout, such as altering tuple headers. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/catversion.h + * + *------------------------------------------------------------------------- + */ +#ifndef CATVERSION_H +#define CATVERSION_H + +/* + * We could use anything we wanted for version numbers, but I recommend + * following the "YYYYMMDDN" style often used for DNS zone serial numbers. + * YYYYMMDD are the date of the change, and N is the number of the change + * on that day. (Hopefully we'll never commit ten independent sets of + * catalog changes on the same day...) + */ + +/* yyyymmddN */ +#define CATALOG_VERSION_NO 202209061 + +#endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h new file mode 100644 index 0000000..6684933 --- /dev/null +++ b/src/include/catalog/dependency.h @@ -0,0 +1,269 @@ +/*------------------------------------------------------------------------- + * + * dependency.h + * Routines to support inter-object dependencies. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/dependency.h + * + *------------------------------------------------------------------------- + */ +#ifndef DEPENDENCY_H +#define DEPENDENCY_H + +#include "catalog/objectaddress.h" + + +/* + * Precise semantics of a dependency relationship are specified by the + * DependencyType code (which is stored in a "char" field in pg_depend, + * so we assign ASCII-code values to the enumeration members). + * + * In all cases, a dependency relationship indicates that the referenced + * object may not be dropped without also dropping the dependent object. + * However, there are several subflavors; see the description of pg_depend + * in catalogs.sgml for details. + */ + +typedef enum DependencyType +{ + DEPENDENCY_NORMAL = 'n', + DEPENDENCY_AUTO = 'a', + DEPENDENCY_INTERNAL = 'i', + DEPENDENCY_PARTITION_PRI = 'P', + DEPENDENCY_PARTITION_SEC = 'S', + DEPENDENCY_EXTENSION = 'e', + DEPENDENCY_AUTO_EXTENSION = 'x' +} DependencyType; + +/* + * There is also a SharedDependencyType enum type that determines the exact + * semantics of an entry in pg_shdepend. Just like regular dependency entries, + * any pg_shdepend entry means that the referenced object cannot be dropped + * unless the dependent object is dropped at the same time. There are some + * additional rules however: + * + * (a) a SHARED_DEPENDENCY_OWNER entry means that the referenced object is + * the role owning the dependent object. The referenced object must be + * a pg_authid entry. + * + * (b) a SHARED_DEPENDENCY_ACL entry means that the referenced object is + * a role mentioned in the ACL field of the dependent object. The referenced + * object must be a pg_authid entry. (SHARED_DEPENDENCY_ACL entries are not + * created for the owner of an object; hence two objects may be linked by + * one or the other, but not both, of these dependency types.) + * + * (c) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is + * a role mentioned in a policy object. The referenced object must be a + * pg_authid entry. + * + * (d) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced + * object is a tablespace mentioned in a relation without storage. The + * referenced object must be a pg_tablespace entry. (Relations that have + * storage don't need this: they are protected by the existence of a physical + * file in the tablespace.) + * + * SHARED_DEPENDENCY_INVALID is a value used as a parameter in internal + * routines, and is not valid in the catalog itself. + */ +typedef enum SharedDependencyType +{ + SHARED_DEPENDENCY_OWNER = 'o', + SHARED_DEPENDENCY_ACL = 'a', + SHARED_DEPENDENCY_POLICY = 'r', + SHARED_DEPENDENCY_TABLESPACE = 't', + SHARED_DEPENDENCY_INVALID = 0 +} SharedDependencyType; + +/* expansible list of ObjectAddresses (private in dependency.c) */ +typedef struct ObjectAddresses ObjectAddresses; + +/* + * This enum covers all system catalogs whose OIDs can appear in + * pg_depend.classId or pg_shdepend.classId. Keep object_classes[] in sync. + */ +typedef enum ObjectClass +{ + OCLASS_CLASS, /* pg_class */ + OCLASS_PROC, /* pg_proc */ + OCLASS_TYPE, /* pg_type */ + OCLASS_CAST, /* pg_cast */ + OCLASS_COLLATION, /* pg_collation */ + OCLASS_CONSTRAINT, /* pg_constraint */ + OCLASS_CONVERSION, /* pg_conversion */ + OCLASS_DEFAULT, /* pg_attrdef */ + OCLASS_LANGUAGE, /* pg_language */ + OCLASS_LARGEOBJECT, /* pg_largeobject */ + OCLASS_OPERATOR, /* pg_operator */ + OCLASS_OPCLASS, /* pg_opclass */ + OCLASS_OPFAMILY, /* pg_opfamily */ + OCLASS_AM, /* pg_am */ + OCLASS_AMOP, /* pg_amop */ + OCLASS_AMPROC, /* pg_amproc */ + OCLASS_REWRITE, /* pg_rewrite */ + OCLASS_TRIGGER, /* pg_trigger */ + OCLASS_SCHEMA, /* pg_namespace */ + OCLASS_STATISTIC_EXT, /* pg_statistic_ext */ + OCLASS_TSPARSER, /* pg_ts_parser */ + OCLASS_TSDICT, /* pg_ts_dict */ + OCLASS_TSTEMPLATE, /* pg_ts_template */ + OCLASS_TSCONFIG, /* pg_ts_config */ + OCLASS_ROLE, /* pg_authid */ + OCLASS_DATABASE, /* pg_database */ + OCLASS_TBLSPACE, /* pg_tablespace */ + OCLASS_FDW, /* pg_foreign_data_wrapper */ + OCLASS_FOREIGN_SERVER, /* pg_foreign_server */ + OCLASS_USER_MAPPING, /* pg_user_mapping */ + OCLASS_DEFACL, /* pg_default_acl */ + OCLASS_EXTENSION, /* pg_extension */ + OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ + OCLASS_PARAMETER_ACL, /* pg_parameter_acl */ + OCLASS_POLICY, /* pg_policy */ + OCLASS_PUBLICATION, /* pg_publication */ + OCLASS_PUBLICATION_NAMESPACE, /* pg_publication_namespace */ + OCLASS_PUBLICATION_REL, /* pg_publication_rel */ + OCLASS_SUBSCRIPTION, /* pg_subscription */ + OCLASS_TRANSFORM /* pg_transform */ +} ObjectClass; + +#define LAST_OCLASS OCLASS_TRANSFORM + +/* flag bits for performDeletion/performMultipleDeletions: */ +#define PERFORM_DELETION_INTERNAL 0x0001 /* internal action */ +#define PERFORM_DELETION_CONCURRENTLY 0x0002 /* concurrent drop */ +#define PERFORM_DELETION_QUIETLY 0x0004 /* suppress notices */ +#define PERFORM_DELETION_SKIP_ORIGINAL 0x0008 /* keep original obj */ +#define PERFORM_DELETION_SKIP_EXTENSIONS 0x0010 /* keep extensions */ +#define PERFORM_DELETION_CONCURRENT_LOCK 0x0020 /* normal drop with + * concurrent lock mode */ + + +/* in dependency.c */ + +extern void AcquireDeletionLock(const ObjectAddress *object, int flags); + +extern void ReleaseDeletionLock(const ObjectAddress *object); + +extern void performDeletion(const ObjectAddress *object, + DropBehavior behavior, int flags); + +extern void performMultipleDeletions(const ObjectAddresses *objects, + DropBehavior behavior, int flags); + +extern void recordDependencyOnExpr(const ObjectAddress *depender, + Node *expr, List *rtable, + DependencyType behavior); + +extern void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, + Node *expr, Oid relId, + DependencyType behavior, + DependencyType self_behavior, + bool reverse_self); + +extern ObjectClass getObjectClass(const ObjectAddress *object); + +extern ObjectAddresses *new_object_addresses(void); + +extern void add_exact_object_address(const ObjectAddress *object, + ObjectAddresses *addrs); + +extern bool object_address_present(const ObjectAddress *object, + const ObjectAddresses *addrs); + +extern void record_object_address_dependencies(const ObjectAddress *depender, + ObjectAddresses *referenced, + DependencyType behavior); + +extern void sort_object_addresses(ObjectAddresses *addrs); + +extern void free_object_addresses(ObjectAddresses *addrs); + +/* in pg_depend.c */ + +extern void recordDependencyOn(const ObjectAddress *depender, + const ObjectAddress *referenced, + DependencyType behavior); + +extern void recordMultipleDependencies(const ObjectAddress *depender, + const ObjectAddress *referenced, + int nreferenced, + DependencyType behavior); + +extern void recordDependencyOnCurrentExtension(const ObjectAddress *object, + bool isReplace); + +extern void checkMembershipInCurrentExtension(const ObjectAddress *object); + +extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, + bool skipExtensionDeps); + +extern long deleteDependencyRecordsForClass(Oid classId, Oid objectId, + Oid refclassId, char deptype); + +extern long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, + char deptype, + Oid refclassId, Oid refobjectId); + +extern long changeDependencyFor(Oid classId, Oid objectId, + Oid refClassId, Oid oldRefObjectId, + Oid newRefObjectId); + +extern long changeDependenciesOf(Oid classId, Oid oldObjectId, + Oid newObjectId); + +extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, + Oid newRefObjectId); + +extern Oid getExtensionOfObject(Oid classId, Oid objectId); +extern List *getAutoExtensionsOfObject(Oid classId, Oid objectId); + +extern bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId); +extern List *getOwnedSequences(Oid relid); +extern Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok); + +extern Oid get_index_constraint(Oid indexId); + +extern List *get_index_ref_constraints(Oid indexId); + +/* in pg_shdepend.c */ + +extern void recordSharedDependencyOn(ObjectAddress *depender, + ObjectAddress *referenced, + SharedDependencyType deptype); + +extern void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, + int32 objectSubId); + +extern void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner); + +extern void changeDependencyOnOwner(Oid classId, Oid objectId, + Oid newOwnerId); + +extern void recordDependencyOnTablespace(Oid classId, Oid objectId, + Oid tablespace); + +extern void changeDependencyOnTablespace(Oid classId, Oid objectId, + Oid newTablespaceId); + +extern void updateAclDependencies(Oid classId, Oid objectId, int32 objectSubId, + Oid ownerId, + int noldmembers, Oid *oldmembers, + int nnewmembers, Oid *newmembers); + +extern bool checkSharedDependencies(Oid classId, Oid objectId, + char **detail_msg, char **detail_log_msg); + +extern void shdepLockAndCheckObject(Oid classId, Oid objectId); + +extern void copyTemplateDependencies(Oid templateDbId, Oid newDbId); + +extern void dropDatabaseDependencies(Oid databaseId); + +extern void shdepDropOwned(List *relids, DropBehavior behavior); + +extern void shdepReassignOwned(List *relids, Oid newrole); + +#endif /* DEPENDENCY_H */ diff --git a/src/include/catalog/duplicate_oids b/src/include/catalog/duplicate_oids new file mode 100755 index 0000000..e6ee2da --- /dev/null +++ b/src/include/catalog/duplicate_oids @@ -0,0 +1,49 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# duplicate_oids +# Identifies any manually-assigned OIDs that are used multiple times +# in the Postgres catalog data. +# +# While duplicate OIDs would only cause a failure if they appear in +# the same catalog, our project policy is that manually assigned OIDs +# should be globally unique, to avoid confusion. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/duplicate_oids +# +#---------------------------------------------------------------------- + +use strict; +use warnings; + +# Must run in src/include/catalog +use FindBin; +chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n"; + +use lib "$FindBin::RealBin/../../backend/catalog/"; +use Catalog; + +my @input_files = glob("pg_*.h"); + +my $oids = Catalog::FindAllOidsFromHeaders(@input_files); + +my %oidcounts; + +foreach my $oid (@{$oids}) +{ + $oidcounts{$oid}++; +} + +my $found = 0; + +foreach my $oid (sort { $a <=> $b } keys %oidcounts) +{ + next unless $oidcounts{$oid} > 1; + $found = 1; + print "$oid\n"; +} + +exit $found; diff --git a/src/include/catalog/genbki.h b/src/include/catalog/genbki.h new file mode 100644 index 0000000..f7b491f --- /dev/null +++ b/src/include/catalog/genbki.h @@ -0,0 +1,143 @@ +/*------------------------------------------------------------------------- + * + * genbki.h + * Required include file for all POSTGRES catalog header files + * + * genbki.h defines CATALOG(), BKI_BOOTSTRAP and related macros + * so that the catalog header files can be read by the C compiler. + * (These same words are recognized by genbki.pl to build the BKI + * bootstrap file from these header files.) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/genbki.h + * + *------------------------------------------------------------------------- + */ +#ifndef GENBKI_H +#define GENBKI_H + +/* Introduces a catalog's structure definition */ +#define CATALOG(name,oid,oidmacro) typedef struct CppConcat(FormData_,name) + +/* Options that may appear after CATALOG (on the same line) */ +#define BKI_BOOTSTRAP +#define BKI_SHARED_RELATION +#define BKI_ROWTYPE_OID(oid,oidmacro) +#define BKI_SCHEMA_MACRO + +/* Options that may appear after an attribute (on the same line) */ +#define BKI_FORCE_NULL +#define BKI_FORCE_NOT_NULL +/* Specifies a default value for a catalog field */ +#define BKI_DEFAULT(value) +/* Specifies a default value for auto-generated array types */ +#define BKI_ARRAY_DEFAULT(value) +/* + * Indicates that the attribute contains OIDs referencing the named catalog; + * can be applied to columns of oid, regproc, oid[], or oidvector type. + * genbki.pl uses this to know how to perform name lookups in the initial + * data (if any), and it also feeds into regression-test validity checks. + * The _OPT suffix indicates that values can be zero instead of + * a valid OID reference. + */ +#define BKI_LOOKUP(catalog) +#define BKI_LOOKUP_OPT(catalog) + +/* + * These lines are processed by genbki.pl to create the statements + * the bootstrap parser will turn into BootstrapToastTable commands. + * Each line specifies the system catalog that needs a toast table, + * the OID to assign to the toast table, and the OID to assign to the + * toast table's index. The reason we hard-wire these OIDs is that we + * need stable OIDs for shared relations, and that includes toast tables + * of shared relations. + * + * The DECLARE_TOAST_WITH_MACRO variant is used when C macros are needed + * for the toast table/index OIDs (usually only for shared catalogs). + * + * The macro definitions are just to keep the C compiler from spitting up. + */ +#define DECLARE_TOAST(name,toastoid,indexoid) extern int no_such_variable +#define DECLARE_TOAST_WITH_MACRO(name,toastoid,indexoid,toastoidmacro,indexoidmacro) extern int no_such_variable + +/* + * These lines are processed by genbki.pl to create the statements + * the bootstrap parser will turn into DefineIndex calls. + * + * The keyword is DECLARE_INDEX or DECLARE_UNIQUE_INDEX or + * DECLARE_UNIQUE_INDEX_PKEY. ("PKEY" marks the index as being the catalog's + * primary key; currently this is only cosmetically different from a regular + * unique index. By convention, we usually make a catalog's OID column its + * pkey, if it has one.) + * + * The first two arguments are the index's name and OID. The third argument + * is the name of a #define to generate for its OID. References to the index + * in the C code should always use these #defines, not the actual index name + * (much less the numeric OID). The rest is much like a standard 'create + * index' SQL command. + * + * The macro definitions are just to keep the C compiler from spitting up. + */ +#define DECLARE_INDEX(name,oid,oidmacro,decl) extern int no_such_variable +#define DECLARE_UNIQUE_INDEX(name,oid,oidmacro,decl) extern int no_such_variable +#define DECLARE_UNIQUE_INDEX_PKEY(name,oid,oidmacro,decl) extern int no_such_variable + +/* + * These lines inform genbki.pl about manually-assigned OIDs that do not + * correspond to any entry in the catalog *.dat files, but should be subject + * to uniqueness verification and renumber_oids.pl renumbering. A C macro + * to #define the given name is emitted into the corresponding *_d.h file. + */ +#define DECLARE_OID_DEFINING_MACRO(name,oid) extern int no_such_variable + +/* + * These lines are processed by genbki.pl to create a table for use + * by the pg_get_catalog_foreign_keys() function. We do not have any + * mechanism that actually enforces foreign-key relationships in the + * system catalogs, but it is still useful to record the intended + * relationships in a machine-readable form. + * + * The keyword is DECLARE_FOREIGN_KEY[_OPT] or DECLARE_ARRAY_FOREIGN_KEY[_OPT]. + * The first argument is a parenthesized list of the referencing columns; + * the second, the name of the referenced table; the third, a parenthesized + * list of the referenced columns. Use of the ARRAY macros means that the + * last referencing column is an array, each of whose elements is supposed + * to match some entry in the last referenced column. Use of the OPT suffix + * indicates that the referencing column(s) can be zero instead of a valid + * reference. + * + * Columns that are marked with a BKI_LOOKUP rule do not need an explicit + * DECLARE_FOREIGN_KEY macro, as genbki.pl can infer the FK relationship + * from that. Thus, these macros are only needed in special cases. + * + * The macro definitions are just to keep the C compiler from spitting up. + */ +#define DECLARE_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_ARRAY_FOREIGN_KEY(cols,reftbl,refcols) extern int no_such_variable +#define DECLARE_ARRAY_FOREIGN_KEY_OPT(cols,reftbl,refcols) extern int no_such_variable + +/* The following are never defined; they are here only for documentation. */ + +/* + * Variable-length catalog fields (except possibly the first not nullable one) + * should not be visible in C structures, so they are made invisible by #ifdefs + * of an undefined symbol. See also the BOOTCOL_NULL_AUTO code in bootstrap.c + * for how this is handled. + */ +#undef CATALOG_VARLEN + +/* + * There is code in some catalog headers that needs to be visible to clients, + * but we don't want clients to include the full header because of safety + * issues with other code in the header. To handle that, surround code that + * should be visible to clients with "#ifdef EXPOSE_TO_CLIENT_CODE". That + * instructs genbki.pl to copy the section when generating the corresponding + * "_d" header, which can be included by both client and backend code. + */ +#undef EXPOSE_TO_CLIENT_CODE + +#endif /* GENBKI_H */ diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h new file mode 100644 index 0000000..07c5b88 --- /dev/null +++ b/src/include/catalog/heap.h @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------- + * + * heap.h + * prototypes for functions in backend/catalog/heap.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/heap.h + * + *------------------------------------------------------------------------- + */ +#ifndef HEAP_H +#define HEAP_H + +#include "catalog/indexing.h" +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" + + +/* flag bits for CheckAttributeType/CheckAttributeNamesTypes */ +#define CHKATYPE_ANYARRAY 0x01 /* allow ANYARRAY */ +#define CHKATYPE_ANYRECORD 0x02 /* allow RECORD and RECORD[] */ +#define CHKATYPE_IS_PARTKEY 0x04 /* attname is part key # not column */ + +typedef struct RawColumnDefault +{ + AttrNumber attnum; /* attribute to attach default to */ + Node *raw_default; /* default value (untransformed parse tree) */ + bool missingMode; /* true if part of add column processing */ + char generated; /* attgenerated setting */ +} RawColumnDefault; + +typedef struct CookedConstraint +{ + ConstrType contype; /* CONSTR_DEFAULT or CONSTR_CHECK */ + Oid conoid; /* constr OID if created, otherwise Invalid */ + char *name; /* name, or NULL if none */ + AttrNumber attnum; /* which attr (only for DEFAULT) */ + Node *expr; /* transformed default or check expr */ + bool skip_validation; /* skip validation? (only for CHECK) */ + bool is_local; /* constraint has local (non-inherited) def */ + int inhcount; /* number of times constraint is inherited */ + bool is_no_inherit; /* constraint has local def and cannot be + * inherited */ +} CookedConstraint; + +extern Relation heap_create(const char *relname, + Oid relnamespace, + Oid reltablespace, + Oid relid, + Oid relfilenode, + Oid accessmtd, + TupleDesc tupDesc, + char relkind, + char relpersistence, + bool shared_relation, + bool mapped_relation, + bool allow_system_table_mods, + TransactionId *relfrozenxid, + MultiXactId *relminmxid, + bool create_storage); + +extern Oid heap_create_with_catalog(const char *relname, + Oid relnamespace, + Oid reltablespace, + Oid relid, + Oid reltypeid, + Oid reloftypeid, + Oid ownerid, + Oid accessmtd, + TupleDesc tupdesc, + List *cooked_constraints, + char relkind, + char relpersistence, + bool shared_relation, + bool mapped_relation, + OnCommitAction oncommit, + Datum reloptions, + bool use_user_acl, + bool allow_system_table_mods, + bool is_internal, + Oid relrewrite, + ObjectAddress *typaddress); + +extern void heap_drop_with_catalog(Oid relid); + +extern void heap_truncate(List *relids); + +extern void heap_truncate_one_rel(Relation rel); + +extern void heap_truncate_check_FKs(List *relations, bool tempTables); + +extern List *heap_truncate_find_FKs(List *relationIds); + +extern void InsertPgAttributeTuples(Relation pg_attribute_rel, + TupleDesc tupdesc, + Oid new_rel_oid, + Datum *attoptions, + CatalogIndexState indstate); + +extern void InsertPgClassTuple(Relation pg_class_desc, + Relation new_rel_desc, + Oid new_rel_oid, + Datum relacl, + Datum reloptions); + +extern List *AddRelationNewConstraints(Relation rel, + List *newColDefaults, + List *newConstraints, + bool allow_merge, + bool is_local, + bool is_internal, + const char *queryString); + +extern void RelationClearMissing(Relation rel); +extern void SetAttrMissing(Oid relid, char *attname, char *value); + +extern Node *cookDefault(ParseState *pstate, + Node *raw_default, + Oid atttypid, + int32 atttypmod, + const char *attname, + char attgenerated); + +extern void DeleteRelationTuple(Oid relid); +extern void DeleteAttributeTuples(Oid relid); +extern void DeleteSystemAttributeTuples(Oid relid); +extern void RemoveAttributeById(Oid relid, AttrNumber attnum); + +extern void CopyStatistics(Oid fromrelid, Oid torelid); +extern void RemoveStatistics(Oid relid, AttrNumber attnum); + +extern const FormData_pg_attribute *SystemAttributeDefinition(AttrNumber attno); + +extern const FormData_pg_attribute *SystemAttributeByName(const char *attname); + +extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind, + int flags); + +extern void CheckAttributeType(const char *attname, + Oid atttypid, Oid attcollation, + List *containing_rowtypes, + int flags); + +/* pg_partitioned_table catalog manipulation functions */ +extern void StorePartitionKey(Relation rel, + char strategy, + int16 partnatts, + AttrNumber *partattrs, + List *partexprs, + Oid *partopclass, + Oid *partcollation); +extern void RemovePartitionKeyByRelId(Oid relid); +extern void StorePartitionBound(Relation rel, Relation parent, + PartitionBoundSpec *bound); + +#endif /* HEAP_H */ diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h new file mode 100644 index 0000000..a1d6e3b --- /dev/null +++ b/src/include/catalog/index.h @@ -0,0 +1,214 @@ +/*------------------------------------------------------------------------- + * + * index.h + * prototypes for catalog/index.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/index.h + * + *------------------------------------------------------------------------- + */ +#ifndef INDEX_H +#define INDEX_H + +#include "catalog/objectaddress.h" +#include "nodes/execnodes.h" + + +#define DEFAULT_INDEX_TYPE "btree" + +/* Action code for index_set_state_flags */ +typedef enum +{ + INDEX_CREATE_SET_READY, + INDEX_CREATE_SET_VALID, + INDEX_DROP_CLEAR_VALID, + INDEX_DROP_SET_DEAD +} IndexStateFlagsAction; + +/* options for REINDEX */ +typedef struct ReindexParams +{ + bits32 options; /* bitmask of REINDEXOPT_* */ + Oid tablespaceOid; /* New tablespace to move indexes to. + * InvalidOid to do nothing. */ +} ReindexParams; + +/* flag bits for ReindexParams->flags */ +#define REINDEXOPT_VERBOSE 0x01 /* print progress info */ +#define REINDEXOPT_REPORT_PROGRESS 0x02 /* report pgstat progress */ +#define REINDEXOPT_MISSING_OK 0x04 /* skip missing relations */ +#define REINDEXOPT_CONCURRENTLY 0x08 /* concurrent mode */ + +/* state info for validate_index bulkdelete callback */ +typedef struct ValidateIndexState +{ + Tuplesortstate *tuplesort; /* for sorting the index TIDs */ + /* statistics (for debug purposes only): */ + double htups, + itups, + tups_inserted; +} ValidateIndexState; + +extern void index_check_primary_key(Relation heapRel, + IndexInfo *indexInfo, + bool is_alter_table, + IndexStmt *stmt); + +#define INDEX_CREATE_IS_PRIMARY (1 << 0) +#define INDEX_CREATE_ADD_CONSTRAINT (1 << 1) +#define INDEX_CREATE_SKIP_BUILD (1 << 2) +#define INDEX_CREATE_CONCURRENT (1 << 3) +#define INDEX_CREATE_IF_NOT_EXISTS (1 << 4) +#define INDEX_CREATE_PARTITIONED (1 << 5) +#define INDEX_CREATE_INVALID (1 << 6) + +extern Oid index_create(Relation heapRelation, + const char *indexRelationName, + Oid indexRelationId, + Oid parentIndexRelid, + Oid parentConstraintId, + Oid relFileNode, + IndexInfo *indexInfo, + List *indexColNames, + Oid accessMethodObjectId, + Oid tableSpaceId, + Oid *collationObjectId, + Oid *classObjectId, + int16 *coloptions, + Datum reloptions, + bits16 flags, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal, + Oid *constraintId); + +#define INDEX_CONSTR_CREATE_MARK_AS_PRIMARY (1 << 0) +#define INDEX_CONSTR_CREATE_DEFERRABLE (1 << 1) +#define INDEX_CONSTR_CREATE_INIT_DEFERRED (1 << 2) +#define INDEX_CONSTR_CREATE_UPDATE_INDEX (1 << 3) +#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS (1 << 4) + +extern Oid index_concurrently_create_copy(Relation heapRelation, + Oid oldIndexId, + Oid tablespaceOid, + const char *newName); + +extern void index_concurrently_build(Oid heapRelationId, + Oid indexRelationId); + +extern void index_concurrently_swap(Oid newIndexId, + Oid oldIndexId, + const char *oldName); + +extern void index_concurrently_set_dead(Oid heapId, + Oid indexId); + +extern ObjectAddress index_constraint_create(Relation heapRelation, + Oid indexRelationId, + Oid parentConstraintId, + IndexInfo *indexInfo, + const char *constraintName, + char constraintType, + bits16 constr_flags, + bool allow_system_table_mods, + bool is_internal); + +extern void index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode); + +extern IndexInfo *BuildIndexInfo(Relation index); + +extern IndexInfo *BuildDummyIndexInfo(Relation index); + +extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, + Oid *collations1, Oid *collations2, + Oid *opfamilies1, Oid *opfamilies2, + AttrMap *attmap); + +extern void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii); + +extern void FormIndexDatum(IndexInfo *indexInfo, + TupleTableSlot *slot, + EState *estate, + Datum *values, + bool *isnull); + +extern void index_build(Relation heapRelation, + Relation indexRelation, + IndexInfo *indexInfo, + bool isreindex, + bool parallel); + +extern void validate_index(Oid heapId, Oid indexId, Snapshot snapshot); + +extern void index_set_state_flags(Oid indexId, IndexStateFlagsAction action); + +extern Oid IndexGetRelation(Oid indexId, bool missing_ok); + +extern void reindex_index(Oid indexId, bool skip_constraint_checks, + char relpersistence, ReindexParams *params); + +/* Flag bits for reindex_relation(): */ +#define REINDEX_REL_PROCESS_TOAST 0x01 +#define REINDEX_REL_SUPPRESS_INDEX_USE 0x02 +#define REINDEX_REL_CHECK_CONSTRAINTS 0x04 +#define REINDEX_REL_FORCE_INDEXES_UNLOGGED 0x08 +#define REINDEX_REL_FORCE_INDEXES_PERMANENT 0x10 + +extern bool reindex_relation(Oid relid, int flags, ReindexParams *params); + +extern bool ReindexIsProcessingHeap(Oid heapOid); +extern bool ReindexIsProcessingIndex(Oid indexOid); + +extern void ResetReindexState(int nestLevel); +extern Size EstimateReindexStateSpace(void); +extern void SerializeReindexState(Size maxsize, char *start_address); +extern void RestoreReindexState(void *reindexstate); + +extern void IndexSetParentIndex(Relation idx, Oid parentOid); + + +/* + * itemptr_encode - Encode ItemPointer as int64/int8 + * + * This representation must produce values encoded as int64 that sort in the + * same order as their corresponding original TID values would (using the + * default int8 opclass to produce a result equivalent to the default TID + * opclass). + * + * As noted in validate_index(), this can be significantly faster. + */ +static inline int64 +itemptr_encode(ItemPointer itemptr) +{ + BlockNumber block = ItemPointerGetBlockNumber(itemptr); + OffsetNumber offset = ItemPointerGetOffsetNumber(itemptr); + int64 encoded; + + /* + * Use the 16 least significant bits for the offset. 32 adjacent bits are + * used for the block number. Since remaining bits are unused, there + * cannot be negative encoded values (We assume a two's complement + * representation). + */ + encoded = ((uint64) block << 16) | (uint16) offset; + + return encoded; +} + +/* + * itemptr_decode - Decode int64/int8 representation back to ItemPointer + */ +static inline void +itemptr_decode(ItemPointer itemptr, int64 encoded) +{ + BlockNumber block = (BlockNumber) (encoded >> 16); + OffsetNumber offset = (OffsetNumber) (encoded & 0xFFFF); + + ItemPointerSet(itemptr, block, offset); +} + +#endif /* INDEX_H */ diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h new file mode 100644 index 0000000..3fe769b --- /dev/null +++ b/src/include/catalog/indexing.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * indexing.h + * This file provides some definitions to support indexing + * on system catalogs + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/indexing.h + * + *------------------------------------------------------------------------- + */ +#ifndef INDEXING_H +#define INDEXING_H + +#include "access/htup.h" +#include "nodes/execnodes.h" +#include "utils/relcache.h" + +/* + * The state object used by CatalogOpenIndexes and friends is actually the + * same as the executor's ResultRelInfo, but we give it another type name + * to decouple callers from that fact. + */ +typedef struct ResultRelInfo *CatalogIndexState; + +/* + * Cap the maximum amount of bytes allocated for multi-inserts with system + * catalogs, limiting the number of slots used. + */ +#define MAX_CATALOG_MULTI_INSERT_BYTES 65535 + +/* + * indexing.c prototypes + */ +extern CatalogIndexState CatalogOpenIndexes(Relation heapRel); +extern void CatalogCloseIndexes(CatalogIndexState indstate); +extern void CatalogTupleInsert(Relation heapRel, HeapTuple tup); +extern void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, + CatalogIndexState indstate); +extern void CatalogTuplesMultiInsertWithInfo(Relation heapRel, + TupleTableSlot **slot, + int ntuples, + CatalogIndexState indstate); +extern void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, + HeapTuple tup); +extern void CatalogTupleUpdateWithInfo(Relation heapRel, + ItemPointer otid, HeapTuple tup, + CatalogIndexState indstate); +extern void CatalogTupleDelete(Relation heapRel, ItemPointer tid); + +#endif /* INDEXING_H */ diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h new file mode 100644 index 0000000..1bc55c0 --- /dev/null +++ b/src/include/catalog/namespace.h @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * + * namespace.h + * prototypes for functions in backend/catalog/namespace.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/namespace.h + * + *------------------------------------------------------------------------- + */ +#ifndef NAMESPACE_H +#define NAMESPACE_H + +#include "nodes/primnodes.h" +#include "storage/lock.h" + + +/* + * This structure holds a list of possible functions or operators + * found by namespace lookup. Each function/operator is identified + * by OID and by argument types; the list must be pruned by type + * resolution rules that are embodied in the parser, not here. + * See FuncnameGetCandidates's comments for more info. + */ +typedef struct _FuncCandidateList +{ + struct _FuncCandidateList *next; + int pathpos; /* for internal use of namespace lookup */ + Oid oid; /* the function or operator's OID */ + int nominalnargs; /* either pronargs or length(proallargtypes) */ + int nargs; /* number of arg types returned */ + int nvargs; /* number of args to become variadic array */ + int ndargs; /* number of defaulted args */ + int *argnumbers; /* args' positional indexes, if named call */ + Oid args[FLEXIBLE_ARRAY_MEMBER]; /* arg types */ +} *FuncCandidateList; + +/* + * Result of checkTempNamespaceStatus + */ +typedef enum TempNamespaceStatus +{ + TEMP_NAMESPACE_NOT_TEMP, /* nonexistent, or non-temp namespace */ + TEMP_NAMESPACE_IDLE, /* exists, belongs to no active session */ + TEMP_NAMESPACE_IN_USE /* belongs to some active session */ +} TempNamespaceStatus; + +/* + * Structure for xxxOverrideSearchPath functions + * + * The generation counter is private to namespace.c and shouldn't be touched + * by other code. It can be initialized to zero if necessary (that means + * "not known equal to the current active path"). + */ +typedef struct OverrideSearchPath +{ + List *schemas; /* OIDs of explicitly named schemas */ + bool addCatalog; /* implicitly prepend pg_catalog? */ + bool addTemp; /* implicitly prepend temp schema? */ + uint64 generation; /* for quick detection of equality to active */ +} OverrideSearchPath; + +/* + * Option flag bits for RangeVarGetRelidExtended(). + */ +typedef enum RVROption +{ + RVR_MISSING_OK = 1 << 0, /* don't error if relation doesn't exist */ + RVR_NOWAIT = 1 << 1, /* error if relation cannot be locked */ + RVR_SKIP_LOCKED = 1 << 2 /* skip if relation cannot be locked */ +} RVROption; + +typedef void (*RangeVarGetRelidCallback) (const RangeVar *relation, Oid relId, + Oid oldRelId, void *callback_arg); + +#define RangeVarGetRelid(relation, lockmode, missing_ok) \ + RangeVarGetRelidExtended(relation, lockmode, \ + (missing_ok) ? RVR_MISSING_OK : 0, NULL, NULL) + +extern Oid RangeVarGetRelidExtended(const RangeVar *relation, + LOCKMODE lockmode, uint32 flags, + RangeVarGetRelidCallback callback, + void *callback_arg); +extern Oid RangeVarGetCreationNamespace(const RangeVar *newRelation); +extern Oid RangeVarGetAndCheckCreationNamespace(RangeVar *newRelation, + LOCKMODE lockmode, + Oid *existing_relation_id); +extern void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid); +extern Oid RelnameGetRelid(const char *relname); +extern bool RelationIsVisible(Oid relid); + +extern Oid TypenameGetTypid(const char *typname); +extern Oid TypenameGetTypidExtended(const char *typname, bool temp_ok); +extern bool TypeIsVisible(Oid typid); + +extern FuncCandidateList FuncnameGetCandidates(List *names, + int nargs, List *argnames, + bool expand_variadic, + bool expand_defaults, + bool include_out_arguments, + bool missing_ok); +extern bool FunctionIsVisible(Oid funcid); + +extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright); +extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind, + bool missing_schema_ok); +extern bool OperatorIsVisible(Oid oprid); + +extern Oid OpclassnameGetOpcid(Oid amid, const char *opcname); +extern bool OpclassIsVisible(Oid opcid); + +extern Oid OpfamilynameGetOpfid(Oid amid, const char *opfname); +extern bool OpfamilyIsVisible(Oid opfid); + +extern Oid CollationGetCollid(const char *collname); +extern bool CollationIsVisible(Oid collid); + +extern Oid ConversionGetConid(const char *conname); +extern bool ConversionIsVisible(Oid conid); + +extern Oid get_statistics_object_oid(List *names, bool missing_ok); +extern bool StatisticsObjIsVisible(Oid relid); + +extern Oid get_ts_parser_oid(List *names, bool missing_ok); +extern bool TSParserIsVisible(Oid prsId); + +extern Oid get_ts_dict_oid(List *names, bool missing_ok); +extern bool TSDictionaryIsVisible(Oid dictId); + +extern Oid get_ts_template_oid(List *names, bool missing_ok); +extern bool TSTemplateIsVisible(Oid tmplId); + +extern Oid get_ts_config_oid(List *names, bool missing_ok); +extern bool TSConfigIsVisible(Oid cfgid); + +extern void DeconstructQualifiedName(List *names, + char **nspname_p, + char **objname_p); +extern Oid LookupNamespaceNoError(const char *nspname); +extern Oid LookupExplicitNamespace(const char *nspname, bool missing_ok); +extern Oid get_namespace_oid(const char *nspname, bool missing_ok); + +extern Oid LookupCreationNamespace(const char *nspname); +extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid); +extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); +extern RangeVar *makeRangeVarFromNameList(List *names); +extern char *NameListToString(List *names); +extern char *NameListToQuotedString(List *names); + +extern bool isTempNamespace(Oid namespaceId); +extern bool isTempToastNamespace(Oid namespaceId); +extern bool isTempOrTempToastNamespace(Oid namespaceId); +extern bool isAnyTempNamespace(Oid namespaceId); +extern bool isOtherTempNamespace(Oid namespaceId); +extern TempNamespaceStatus checkTempNamespaceStatus(Oid namespaceId); +extern int GetTempNamespaceBackendId(Oid namespaceId); +extern Oid GetTempToastNamespace(void); +extern void GetTempNamespaceState(Oid *tempNamespaceId, + Oid *tempToastNamespaceId); +extern void SetTempNamespaceState(Oid tempNamespaceId, + Oid tempToastNamespaceId); +extern void ResetTempTableNamespace(void); + +extern OverrideSearchPath *GetOverrideSearchPath(MemoryContext context); +extern OverrideSearchPath *CopyOverrideSearchPath(OverrideSearchPath *path); +extern bool OverrideSearchPathMatchesCurrent(OverrideSearchPath *path); +extern void PushOverrideSearchPath(OverrideSearchPath *newpath); +extern void PopOverrideSearchPath(void); + +extern Oid get_collation_oid(List *collname, bool missing_ok); +extern Oid get_conversion_oid(List *conname, bool missing_ok); +extern Oid FindDefaultConversionProc(int32 for_encoding, int32 to_encoding); + + +/* initialization & transaction cleanup code */ +extern void InitializeSearchPath(void); +extern void AtEOXact_Namespace(bool isCommit, bool parallel); +extern void AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid, + SubTransactionId parentSubid); + +/* stuff for search_path GUC variable */ +extern PGDLLIMPORT char *namespace_search_path; + +extern List *fetch_search_path(bool includeImplicit); +extern int fetch_search_path_array(Oid *sarray, int sarray_len); + +#endif /* NAMESPACE_H */ diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h new file mode 100644 index 0000000..567ab63 --- /dev/null +++ b/src/include/catalog/objectaccess.h @@ -0,0 +1,265 @@ +/* + * objectaccess.h + * + * Object access hooks. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ + +#ifndef OBJECTACCESS_H +#define OBJECTACCESS_H + +/* + * Object access hooks are intended to be called just before or just after + * performing certain actions on a SQL object. This is intended as + * infrastructure for security or logging plugins. + * + * OAT_POST_CREATE should be invoked just after the object is created. + * Typically, this is done after inserting the primary catalog records and + * associated dependencies. + * + * OAT_DROP should be invoked just before deletion of objects; typically + * deleteOneObject(). Its arguments are packed within ObjectAccessDrop. + * + * OAT_POST_ALTER should be invoked just after the object is altered, + * but before the command counter is incremented. An extension using the + * hook can use a current MVCC snapshot to get the old version of the tuple, + * and can use SnapshotSelf to get the new version of the tuple. + * + * OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under + * a particular namespace. This event is equivalent to usage permission + * on a schema under the default access control mechanism. + * + * OAT_FUNCTION_EXECUTE should be invoked prior to function execution. + * This event is almost equivalent to execute permission on functions, + * except for the case when execute permission is checked during object + * creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are + * sufficient for extensions to track these kind of checks. + * + * OAT_TRUNCATE should be invoked just before truncation of objects. This + * event is equivalent to truncate permission on a relation under the + * default access control mechanism. + * + * Other types may be added in the future. + */ +typedef enum ObjectAccessType +{ + OAT_POST_CREATE, + OAT_DROP, + OAT_POST_ALTER, + OAT_NAMESPACE_SEARCH, + OAT_FUNCTION_EXECUTE, + OAT_TRUNCATE +} ObjectAccessType; + +/* + * Arguments of OAT_POST_CREATE event + */ +typedef struct +{ + /* + * This flag informs extensions whether the context of this creation is + * invoked by user's operations, or not. E.g, it shall be dealt as + * internal stuff on toast tables or indexes due to type changes. + */ + bool is_internal; +} ObjectAccessPostCreate; + +/* + * Arguments of OAT_DROP event + */ +typedef struct +{ + /* + * Flags to inform extensions the context of this deletion. Also see + * PERFORM_DELETION_* in dependency.h + */ + int dropflags; +} ObjectAccessDrop; + +/* + * Arguments of OAT_POST_ALTER event + */ +typedef struct +{ + /* + * This identifier is used when system catalog takes two IDs to identify a + * particular tuple of the catalog. It is only used when the caller want + * to identify an entry of pg_inherits, pg_db_role_setting or + * pg_user_mapping. Elsewhere, InvalidOid should be set. + */ + Oid auxiliary_id; + + /* + * If this flag is set, the user hasn't requested that the object be + * altered, but we're doing it anyway for some internal reason. + * Permissions-checking hooks may want to skip checks if, say, we're alter + * the constraints of a temporary heap during CLUSTER. + */ + bool is_internal; +} ObjectAccessPostAlter; + +/* + * Arguments of OAT_NAMESPACE_SEARCH + */ +typedef struct +{ + /* + * If true, hook should report an error when permission to search this + * schema is denied. + */ + bool ereport_on_violation; + + /* + * This is, in essence, an out parameter. Core code should initialize + * this to true, and any extension that wants to deny access should reset + * it to false. But an extension should be careful never to store a true + * value here, so that in case there are multiple extensions access is + * only allowed if all extensions agree. + */ + bool result; +} ObjectAccessNamespaceSearch; + +/* Plugin provides a hook function matching one or both of these signatures. */ +typedef void (*object_access_hook_type) (ObjectAccessType access, + Oid classId, + Oid objectId, + int subId, + void *arg); + +typedef void (*object_access_hook_type_str) (ObjectAccessType access, + Oid classId, + const char *objectStr, + int subId, + void *arg); + +/* Plugin sets this variable to a suitable hook function. */ +extern PGDLLIMPORT object_access_hook_type object_access_hook; +extern PGDLLIMPORT object_access_hook_type_str object_access_hook_str; + + +/* Core code uses these functions to call the hook (see macros below). */ +extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId, + bool is_internal); +extern void RunObjectDropHook(Oid classId, Oid objectId, int subId, + int dropflags); +extern void RunObjectTruncateHook(Oid objectId); +extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, + Oid auxiliaryId, bool is_internal); +extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation); +extern void RunFunctionExecuteHook(Oid objectId); + +/* String versions */ +extern void RunObjectPostCreateHookStr(Oid classId, const char *objectStr, int subId, + bool is_internal); +extern void RunObjectDropHookStr(Oid classId, const char *objectStr, int subId, + int dropflags); +extern void RunObjectTruncateHookStr(const char *objectStr); +extern void RunObjectPostAlterHookStr(Oid classId, const char *objectStr, int subId, + Oid auxiliaryId, bool is_internal); +extern bool RunNamespaceSearchHookStr(const char *objectStr, bool ereport_on_violation); +extern void RunFunctionExecuteHookStr(const char *objectStr); + + +/* + * The following macros are wrappers around the functions above; these should + * normally be used to invoke the hook in lieu of calling the above functions + * directly. + */ + +#define InvokeObjectPostCreateHook(classId,objectId,subId) \ + InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false) +#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \ + do { \ + if (object_access_hook) \ + RunObjectPostCreateHook((classId),(objectId),(subId), \ + (is_internal)); \ + } while(0) + +#define InvokeObjectDropHook(classId,objectId,subId) \ + InvokeObjectDropHookArg((classId),(objectId),(subId),0) +#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags) \ + do { \ + if (object_access_hook) \ + RunObjectDropHook((classId),(objectId),(subId), \ + (dropflags)); \ + } while(0) + +#define InvokeObjectTruncateHook(objectId) \ + do { \ + if (object_access_hook) \ + RunObjectTruncateHook(objectId); \ + } while(0) + +#define InvokeObjectPostAlterHook(classId,objectId,subId) \ + InvokeObjectPostAlterHookArg((classId),(objectId),(subId), \ + InvalidOid,false) +#define InvokeObjectPostAlterHookArg(classId,objectId,subId, \ + auxiliaryId,is_internal) \ + do { \ + if (object_access_hook) \ + RunObjectPostAlterHook((classId),(objectId),(subId), \ + (auxiliaryId),(is_internal)); \ + } while(0) + +#define InvokeNamespaceSearchHook(objectId, ereport_on_violation) \ + (!object_access_hook \ + ? true \ + : RunNamespaceSearchHook((objectId), (ereport_on_violation))) + +#define InvokeFunctionExecuteHook(objectId) \ + do { \ + if (object_access_hook) \ + RunFunctionExecuteHook(objectId); \ + } while(0) + + +#define InvokeObjectPostCreateHookStr(classId,objectName,subId) \ + InvokeObjectPostCreateHookArgStr((classId),(objectName),(subId),false) +#define InvokeObjectPostCreateHookArgStr(classId,objectName,subId,is_internal) \ + do { \ + if (object_access_hook_str) \ + RunObjectPostCreateHookStr((classId),(objectName),(subId), \ + (is_internal)); \ + } while(0) + +#define InvokeObjectDropHookStr(classId,objectName,subId) \ + InvokeObjectDropHookArgStr((classId),(objectName),(subId),0) +#define InvokeObjectDropHookArgStr(classId,objectName,subId,dropflags) \ + do { \ + if (object_access_hook_str) \ + RunObjectDropHookStr((classId),(objectName),(subId), \ + (dropflags)); \ + } while(0) + +#define InvokeObjectTruncateHookStr(objectName) \ + do { \ + if (object_access_hook_str) \ + RunObjectTruncateHookStr(objectName); \ + } while(0) + +#define InvokeObjectPostAlterHookStr(classId,objectName,subId) \ + InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId), \ + InvalidOid,false) +#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId, \ + auxiliaryId,is_internal) \ + do { \ + if (object_access_hook_str) \ + RunObjectPostAlterHookStr((classId),(objectName),(subId), \ + (auxiliaryId),(is_internal)); \ + } while(0) + +#define InvokeNamespaceSearchHookStr(objectName, ereport_on_violation) \ + (!object_access_hook_str \ + ? true \ + : RunNamespaceSearchHookStr((objectName), (ereport_on_violation))) + +#define InvokeFunctionExecuteHookStr(objectName) \ + do { \ + if (object_access_hook_str) \ + RunFunctionExecuteHookStr(objectName); \ + } while(0) + + +#endif /* OBJECTACCESS_H */ diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h new file mode 100644 index 0000000..cf4d8b3 --- /dev/null +++ b/src/include/catalog/objectaddress.h @@ -0,0 +1,89 @@ +/*------------------------------------------------------------------------- + * + * objectaddress.h + * functions for working with object addresses + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/objectaddress.h + * + *------------------------------------------------------------------------- + */ +#ifndef OBJECTADDRESS_H +#define OBJECTADDRESS_H + +#include "access/htup.h" +#include "nodes/parsenodes.h" +#include "storage/lockdefs.h" +#include "utils/relcache.h" + +/* + * An ObjectAddress represents a database object of any type. + */ +typedef struct ObjectAddress +{ + Oid classId; /* Class Id from pg_class */ + Oid objectId; /* OID of the object */ + int32 objectSubId; /* Subitem within object (eg column), or 0 */ +} ObjectAddress; + +extern PGDLLIMPORT const ObjectAddress InvalidObjectAddress; + +#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id) \ + do { \ + (addr).classId = (class_id); \ + (addr).objectId = (object_id); \ + (addr).objectSubId = (object_sub_id); \ + } while (0) + +#define ObjectAddressSet(addr, class_id, object_id) \ + ObjectAddressSubSet(addr, class_id, object_id, 0) + +extern ObjectAddress get_object_address(ObjectType objtype, Node *object, + Relation *relp, + LOCKMODE lockmode, bool missing_ok); + +extern ObjectAddress get_object_address_rv(ObjectType objtype, RangeVar *rel, + List *object, Relation *relp, + LOCKMODE lockmode, bool missing_ok); + +extern void check_object_ownership(Oid roleid, + ObjectType objtype, ObjectAddress address, + Node *object, Relation relation); + +extern Oid get_object_namespace(const ObjectAddress *address); + +extern bool is_objectclass_supported(Oid class_id); +extern const char *get_object_class_descr(Oid class_id); +extern Oid get_object_oid_index(Oid class_id); +extern int get_object_catcache_oid(Oid class_id); +extern int get_object_catcache_name(Oid class_id); +extern AttrNumber get_object_attnum_oid(Oid class_id); +extern AttrNumber get_object_attnum_name(Oid class_id); +extern AttrNumber get_object_attnum_namespace(Oid class_id); +extern AttrNumber get_object_attnum_owner(Oid class_id); +extern AttrNumber get_object_attnum_acl(Oid class_id); +extern ObjectType get_object_type(Oid class_id, Oid object_id); +extern bool get_object_namensp_unique(Oid class_id); + +extern HeapTuple get_catalog_object_by_oid(Relation catalog, + AttrNumber oidcol, Oid objectId); + +extern char *getObjectDescription(const ObjectAddress *object, + bool missing_ok); +extern char *getObjectDescriptionOids(Oid classid, Oid objid); + +extern int read_objtype_from_string(const char *objtype); +extern char *getObjectTypeDescription(const ObjectAddress *object, + bool missing_ok); +extern char *getObjectIdentity(const ObjectAddress *address, + bool missing_ok); +extern char *getObjectIdentityParts(const ObjectAddress *address, + List **objname, List **objargs, + bool missing_ok); +extern struct ArrayType *strlist_to_textarray(List *list); + +extern ObjectType get_relkind_objtype(char relkind); + +#endif /* OBJECTADDRESS_H */ diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h new file mode 100644 index 0000000..b29df66 --- /dev/null +++ b/src/include/catalog/partition.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * partition.h + * Header file for structures and utility functions related to + * partitioning + * + * Copyright (c) 2007-2022, PostgreSQL Global Development Group + * + * src/include/catalog/partition.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTITION_H +#define PARTITION_H + +#include "partitioning/partdefs.h" +#include "utils/relcache.h" + +/* Seed for the extended hash function */ +#define HASH_PARTITION_SEED UINT64CONST(0x7A5B22367996DCFD) + +extern Oid get_partition_parent(Oid relid, bool even_if_detached); +extern List *get_partition_ancestors(Oid relid); +extern Oid index_get_partition(Relation partition, Oid indexId); +extern List *map_partition_varattnos(List *expr, int fromrel_varno, + Relation to_rel, Relation from_rel); +extern bool has_partition_attrs(Relation rel, Bitmapset *attnums, + bool *used_in_expr); + +extern Oid get_default_partition_oid(Oid parentId); +extern void update_default_partition_oid(Oid parentId, Oid defaultPartId); +extern List *get_proposed_default_constraint(List *new_part_constraints); + +#endif /* PARTITION_H */ diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat new file mode 100644 index 0000000..b9110a5 --- /dev/null +++ b/src/include/catalog/pg_aggregate.dat @@ -0,0 +1,628 @@ +#---------------------------------------------------------------------- +# +# pg_aggregate.dat +# Initial contents of the pg_aggregate system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_aggregate.dat +# +#---------------------------------------------------------------------- + +[ + +# avg +{ aggfnoid => 'avg(int8)', aggtransfn => 'int8_avg_accum', + aggfinalfn => 'numeric_poly_avg', aggcombinefn => 'int8_avg_combine', + aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize', + aggmtransfn => 'int8_avg_accum', aggminvtransfn => 'int8_avg_accum_inv', + aggmfinalfn => 'numeric_poly_avg', aggtranstype => 'internal', + aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'avg(int4)', aggtransfn => 'int4_avg_accum', + aggfinalfn => 'int8_avg', aggcombinefn => 'int4_avg_combine', + aggmtransfn => 'int4_avg_accum', aggminvtransfn => 'int4_avg_accum_inv', + aggmfinalfn => 'int8_avg', aggtranstype => '_int8', aggmtranstype => '_int8', + agginitval => '{0,0}', aggminitval => '{0,0}' }, +{ aggfnoid => 'avg(int2)', aggtransfn => 'int2_avg_accum', + aggfinalfn => 'int8_avg', aggcombinefn => 'int4_avg_combine', + aggmtransfn => 'int2_avg_accum', aggminvtransfn => 'int2_avg_accum_inv', + aggmfinalfn => 'int8_avg', aggtranstype => '_int8', aggmtranstype => '_int8', + agginitval => '{0,0}', aggminitval => '{0,0}' }, +{ aggfnoid => 'avg(numeric)', aggtransfn => 'numeric_avg_accum', + aggfinalfn => 'numeric_avg', aggcombinefn => 'numeric_avg_combine', + aggserialfn => 'numeric_avg_serialize', + aggdeserialfn => 'numeric_avg_deserialize', + aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_avg', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'avg(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'avg(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'avg(interval)', aggtransfn => 'interval_accum', + aggfinalfn => 'interval_avg', aggcombinefn => 'interval_combine', + aggmtransfn => 'interval_accum', aggminvtransfn => 'interval_accum_inv', + aggmfinalfn => 'interval_avg', aggtranstype => '_interval', + aggmtranstype => '_interval', agginitval => '{0 second,0 second}', + aggminitval => '{0 second,0 second}' }, + +# sum +{ aggfnoid => 'sum(int8)', aggtransfn => 'int8_avg_accum', + aggfinalfn => 'numeric_poly_sum', aggcombinefn => 'int8_avg_combine', + aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize', + aggmtransfn => 'int8_avg_accum', aggminvtransfn => 'int8_avg_accum_inv', + aggmfinalfn => 'numeric_poly_sum', aggtranstype => 'internal', + aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'sum(int4)', aggtransfn => 'int4_sum', aggcombinefn => 'int8pl', + aggmtransfn => 'int4_avg_accum', aggminvtransfn => 'int4_avg_accum_inv', + aggmfinalfn => 'int2int4_sum', aggtranstype => 'int8', + aggmtranstype => '_int8', aggminitval => '{0,0}' }, +{ aggfnoid => 'sum(int2)', aggtransfn => 'int2_sum', aggcombinefn => 'int8pl', + aggmtransfn => 'int2_avg_accum', aggminvtransfn => 'int2_avg_accum_inv', + aggmfinalfn => 'int2int4_sum', aggtranstype => 'int8', + aggmtranstype => '_int8', aggminitval => '{0,0}' }, +{ aggfnoid => 'sum(float4)', aggtransfn => 'float4pl', + aggcombinefn => 'float4pl', aggtranstype => 'float4' }, +{ aggfnoid => 'sum(float8)', aggtransfn => 'float8pl', + aggcombinefn => 'float8pl', aggtranstype => 'float8' }, +{ aggfnoid => 'sum(money)', aggtransfn => 'cash_pl', aggcombinefn => 'cash_pl', + aggmtransfn => 'cash_pl', aggminvtransfn => 'cash_mi', + aggtranstype => 'money', aggmtranstype => 'money' }, +{ aggfnoid => 'sum(interval)', aggtransfn => 'interval_pl', + aggcombinefn => 'interval_pl', aggmtransfn => 'interval_pl', + aggminvtransfn => 'interval_mi', aggtranstype => 'interval', + aggmtranstype => 'interval' }, +{ aggfnoid => 'sum(numeric)', aggtransfn => 'numeric_avg_accum', + aggfinalfn => 'numeric_sum', aggcombinefn => 'numeric_avg_combine', + aggserialfn => 'numeric_avg_serialize', + aggdeserialfn => 'numeric_avg_deserialize', + aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_sum', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# max +{ aggfnoid => 'max(int8)', aggtransfn => 'int8larger', + aggcombinefn => 'int8larger', aggsortop => '>(int8,int8)', + aggtranstype => 'int8' }, +{ aggfnoid => 'max(int4)', aggtransfn => 'int4larger', + aggcombinefn => 'int4larger', aggsortop => '>(int4,int4)', + aggtranstype => 'int4' }, +{ aggfnoid => 'max(int2)', aggtransfn => 'int2larger', + aggcombinefn => 'int2larger', aggsortop => '>(int2,int2)', + aggtranstype => 'int2' }, +{ aggfnoid => 'max(oid)', aggtransfn => 'oidlarger', + aggcombinefn => 'oidlarger', aggsortop => '>(oid,oid)', + aggtranstype => 'oid' }, +{ aggfnoid => 'max(float4)', aggtransfn => 'float4larger', + aggcombinefn => 'float4larger', aggsortop => '>(float4,float4)', + aggtranstype => 'float4' }, +{ aggfnoid => 'max(float8)', aggtransfn => 'float8larger', + aggcombinefn => 'float8larger', aggsortop => '>(float8,float8)', + aggtranstype => 'float8' }, +{ aggfnoid => 'max(date)', aggtransfn => 'date_larger', + aggcombinefn => 'date_larger', aggsortop => '>(date,date)', + aggtranstype => 'date' }, +{ aggfnoid => 'max(time)', aggtransfn => 'time_larger', + aggcombinefn => 'time_larger', aggsortop => '>(time,time)', + aggtranstype => 'time' }, +{ aggfnoid => 'max(timetz)', aggtransfn => 'timetz_larger', + aggcombinefn => 'timetz_larger', aggsortop => '>(timetz,timetz)', + aggtranstype => 'timetz' }, +{ aggfnoid => 'max(money)', aggtransfn => 'cashlarger', + aggcombinefn => 'cashlarger', aggsortop => '>(money,money)', + aggtranstype => 'money' }, +{ aggfnoid => 'max(timestamp)', aggtransfn => 'timestamp_larger', + aggcombinefn => 'timestamp_larger', aggsortop => '>(timestamp,timestamp)', + aggtranstype => 'timestamp' }, +{ aggfnoid => 'max(timestamptz)', aggtransfn => 'timestamptz_larger', + aggcombinefn => 'timestamptz_larger', + aggsortop => '>(timestamptz,timestamptz)', aggtranstype => 'timestamptz' }, +{ aggfnoid => 'max(interval)', aggtransfn => 'interval_larger', + aggcombinefn => 'interval_larger', aggsortop => '>(interval,interval)', + aggtranstype => 'interval' }, +{ aggfnoid => 'max(text)', aggtransfn => 'text_larger', + aggcombinefn => 'text_larger', aggsortop => '>(text,text)', + aggtranstype => 'text' }, +{ aggfnoid => 'max(numeric)', aggtransfn => 'numeric_larger', + aggcombinefn => 'numeric_larger', aggsortop => '>(numeric,numeric)', + aggtranstype => 'numeric' }, +{ aggfnoid => 'max(anyarray)', aggtransfn => 'array_larger', + aggcombinefn => 'array_larger', aggsortop => '>(anyarray,anyarray)', + aggtranstype => 'anyarray' }, +{ aggfnoid => 'max(bpchar)', aggtransfn => 'bpchar_larger', + aggcombinefn => 'bpchar_larger', aggsortop => '>(bpchar,bpchar)', + aggtranstype => 'bpchar' }, +{ aggfnoid => 'max(tid)', aggtransfn => 'tidlarger', + aggcombinefn => 'tidlarger', aggsortop => '>(tid,tid)', + aggtranstype => 'tid' }, +{ aggfnoid => 'max(anyenum)', aggtransfn => 'enum_larger', + aggcombinefn => 'enum_larger', aggsortop => '>(anyenum,anyenum)', + aggtranstype => 'anyenum' }, +{ aggfnoid => 'max(inet)', aggtransfn => 'network_larger', + aggcombinefn => 'network_larger', aggsortop => '>(inet,inet)', + aggtranstype => 'inet' }, +{ aggfnoid => 'max(pg_lsn)', aggtransfn => 'pg_lsn_larger', + aggcombinefn => 'pg_lsn_larger', aggsortop => '>(pg_lsn,pg_lsn)', + aggtranstype => 'pg_lsn' }, +{ aggfnoid => 'max(xid8)', aggtransfn => 'xid8_larger', + aggcombinefn => 'xid8_larger', aggsortop => '>(xid8,xid8)', + aggtranstype => 'xid8' }, + +# min +{ aggfnoid => 'min(int8)', aggtransfn => 'int8smaller', + aggcombinefn => 'int8smaller', aggsortop => '<(int8,int8)', + aggtranstype => 'int8' }, +{ aggfnoid => 'min(int4)', aggtransfn => 'int4smaller', + aggcombinefn => 'int4smaller', aggsortop => '<(int4,int4)', + aggtranstype => 'int4' }, +{ aggfnoid => 'min(int2)', aggtransfn => 'int2smaller', + aggcombinefn => 'int2smaller', aggsortop => '<(int2,int2)', + aggtranstype => 'int2' }, +{ aggfnoid => 'min(oid)', aggtransfn => 'oidsmaller', + aggcombinefn => 'oidsmaller', aggsortop => '<(oid,oid)', + aggtranstype => 'oid' }, +{ aggfnoid => 'min(float4)', aggtransfn => 'float4smaller', + aggcombinefn => 'float4smaller', aggsortop => '<(float4,float4)', + aggtranstype => 'float4' }, +{ aggfnoid => 'min(float8)', aggtransfn => 'float8smaller', + aggcombinefn => 'float8smaller', aggsortop => '<(float8,float8)', + aggtranstype => 'float8' }, +{ aggfnoid => 'min(date)', aggtransfn => 'date_smaller', + aggcombinefn => 'date_smaller', aggsortop => '<(date,date)', + aggtranstype => 'date' }, +{ aggfnoid => 'min(time)', aggtransfn => 'time_smaller', + aggcombinefn => 'time_smaller', aggsortop => '<(time,time)', + aggtranstype => 'time' }, +{ aggfnoid => 'min(timetz)', aggtransfn => 'timetz_smaller', + aggcombinefn => 'timetz_smaller', aggsortop => '<(timetz,timetz)', + aggtranstype => 'timetz' }, +{ aggfnoid => 'min(money)', aggtransfn => 'cashsmaller', + aggcombinefn => 'cashsmaller', aggsortop => '<(money,money)', + aggtranstype => 'money' }, +{ aggfnoid => 'min(timestamp)', aggtransfn => 'timestamp_smaller', + aggcombinefn => 'timestamp_smaller', aggsortop => '<(timestamp,timestamp)', + aggtranstype => 'timestamp' }, +{ aggfnoid => 'min(timestamptz)', aggtransfn => 'timestamptz_smaller', + aggcombinefn => 'timestamptz_smaller', + aggsortop => '<(timestamptz,timestamptz)', aggtranstype => 'timestamptz' }, +{ aggfnoid => 'min(interval)', aggtransfn => 'interval_smaller', + aggcombinefn => 'interval_smaller', aggsortop => '<(interval,interval)', + aggtranstype => 'interval' }, +{ aggfnoid => 'min(text)', aggtransfn => 'text_smaller', + aggcombinefn => 'text_smaller', aggsortop => '<(text,text)', + aggtranstype => 'text' }, +{ aggfnoid => 'min(numeric)', aggtransfn => 'numeric_smaller', + aggcombinefn => 'numeric_smaller', aggsortop => '<(numeric,numeric)', + aggtranstype => 'numeric' }, +{ aggfnoid => 'min(anyarray)', aggtransfn => 'array_smaller', + aggcombinefn => 'array_smaller', aggsortop => '<(anyarray,anyarray)', + aggtranstype => 'anyarray' }, +{ aggfnoid => 'min(bpchar)', aggtransfn => 'bpchar_smaller', + aggcombinefn => 'bpchar_smaller', aggsortop => '<(bpchar,bpchar)', + aggtranstype => 'bpchar' }, +{ aggfnoid => 'min(tid)', aggtransfn => 'tidsmaller', + aggcombinefn => 'tidsmaller', aggsortop => '<(tid,tid)', + aggtranstype => 'tid' }, +{ aggfnoid => 'min(anyenum)', aggtransfn => 'enum_smaller', + aggcombinefn => 'enum_smaller', aggsortop => '<(anyenum,anyenum)', + aggtranstype => 'anyenum' }, +{ aggfnoid => 'min(inet)', aggtransfn => 'network_smaller', + aggcombinefn => 'network_smaller', aggsortop => '<(inet,inet)', + aggtranstype => 'inet' }, +{ aggfnoid => 'min(pg_lsn)', aggtransfn => 'pg_lsn_smaller', + aggcombinefn => 'pg_lsn_smaller', aggsortop => '<(pg_lsn,pg_lsn)', + aggtranstype => 'pg_lsn' }, +{ aggfnoid => 'min(xid8)', aggtransfn => 'xid8_smaller', + aggcombinefn => 'xid8_smaller', aggsortop => '<(xid8,xid8)', + aggtranstype => 'xid8' }, + +# count +{ aggfnoid => 'count(any)', aggtransfn => 'int8inc_any', + aggcombinefn => 'int8pl', aggmtransfn => 'int8inc_any', + aggminvtransfn => 'int8dec_any', aggtranstype => 'int8', + aggmtranstype => 'int8', agginitval => '0', aggminitval => '0' }, +{ aggfnoid => 'count()', aggtransfn => 'int8inc', aggcombinefn => 'int8pl', + aggmtransfn => 'int8inc', aggminvtransfn => 'int8dec', aggtranstype => 'int8', + aggmtranstype => 'int8', agginitval => '0', aggminitval => '0' }, + +# var_pop +{ aggfnoid => 'var_pop(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_var_pop', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_var_pop', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'var_pop(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_var_pop', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_pop', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'var_pop(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_var_pop', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_pop', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'var_pop(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_var_pop', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'var_pop(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_var_pop', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'var_pop(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_var_pop', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_var_pop', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# var_samp +{ aggfnoid => 'var_samp(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'var_samp(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'var_samp(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'var_samp(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'var_samp(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'var_samp(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# variance: historical Postgres syntax for var_samp +{ aggfnoid => 'variance(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'variance(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'variance(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'variance(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'variance(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'variance(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# stddev_pop +{ aggfnoid => 'stddev_pop(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_stddev_pop', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_stddev_pop', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'stddev_pop(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_stddev_pop', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_pop', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev_pop(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_stddev_pop', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_pop', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev_pop(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_stddev_pop', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev_pop(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_stddev_pop', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev_pop(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_stddev_pop', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_stddev_pop', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# stddev_samp +{ aggfnoid => 'stddev_samp(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'stddev_samp(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_stddev_samp', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev_samp(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_stddev_samp', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev_samp(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev_samp(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev_samp(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# stddev: historical Postgres syntax for stddev_samp +{ aggfnoid => 'stddev(int8)', aggtransfn => 'int8_accum', + aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv', + aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, +{ aggfnoid => 'stddev(int4)', aggtransfn => 'int4_accum', + aggfinalfn => 'numeric_poly_stddev_samp', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum', + aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev(int2)', aggtransfn => 'int2_accum', + aggfinalfn => 'numeric_poly_stddev_samp', + aggcombinefn => 'numeric_poly_combine', + aggserialfn => 'numeric_poly_serialize', + aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum', + aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp', + aggtranstype => 'internal', aggtransspace => '48', + aggmtranstype => 'internal', aggmtransspace => '48' }, +{ aggfnoid => 'stddev(float4)', aggtransfn => 'float4_accum', + aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev(float8)', aggtransfn => 'float8_accum', + aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine', + aggtranstype => '_float8', agginitval => '{0,0,0}' }, +{ aggfnoid => 'stddev(numeric)', aggtransfn => 'numeric_accum', + aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine', + aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize', + aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv', + aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal', + aggtransspace => '128', aggmtranstype => 'internal', + aggmtransspace => '128' }, + +# SQL2003 binary regression aggregates +{ aggfnoid => 'regr_count', aggtransfn => 'int8inc_float8_float8', + aggcombinefn => 'int8pl', aggtranstype => 'int8', agginitval => '0' }, +{ aggfnoid => 'regr_sxx', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_sxx', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_syy', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_syy', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_sxy', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_sxy', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_avgx', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_avgx', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_avgy', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_avgy', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_r2', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_r2', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_slope', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_slope', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'regr_intercept', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_regr_intercept', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'covar_pop', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_covar_pop', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'covar_samp', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_covar_samp', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, +{ aggfnoid => 'corr', aggtransfn => 'float8_regr_accum', + aggfinalfn => 'float8_corr', aggcombinefn => 'float8_regr_combine', + aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' }, + +# boolean-and and boolean-or +{ aggfnoid => 'bool_and', aggtransfn => 'booland_statefunc', + aggcombinefn => 'booland_statefunc', aggmtransfn => 'bool_accum', + aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_alltrue', + aggsortop => '<(bool,bool)', aggtranstype => 'bool', + aggmtranstype => 'internal', aggmtransspace => '16' }, +{ aggfnoid => 'bool_or', aggtransfn => 'boolor_statefunc', + aggcombinefn => 'boolor_statefunc', aggmtransfn => 'bool_accum', + aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_anytrue', + aggsortop => '>(bool,bool)', aggtranstype => 'bool', + aggmtranstype => 'internal', aggmtransspace => '16' }, +{ aggfnoid => 'every', aggtransfn => 'booland_statefunc', + aggcombinefn => 'booland_statefunc', aggmtransfn => 'bool_accum', + aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_alltrue', + aggsortop => '<(bool,bool)', aggtranstype => 'bool', + aggmtranstype => 'internal', aggmtransspace => '16' }, + +# bitwise integer +{ aggfnoid => 'bit_and(int2)', aggtransfn => 'int2and', + aggcombinefn => 'int2and', aggtranstype => 'int2' }, +{ aggfnoid => 'bit_or(int2)', aggtransfn => 'int2or', aggcombinefn => 'int2or', + aggtranstype => 'int2' }, +{ aggfnoid => 'bit_xor(int2)', aggtransfn => 'int2xor', + aggcombinefn => 'int2xor', aggtranstype => 'int2' }, +{ aggfnoid => 'bit_and(int4)', aggtransfn => 'int4and', + aggcombinefn => 'int4and', aggtranstype => 'int4' }, +{ aggfnoid => 'bit_or(int4)', aggtransfn => 'int4or', aggcombinefn => 'int4or', + aggtranstype => 'int4' }, +{ aggfnoid => 'bit_xor(int4)', aggtransfn => 'int4xor', + aggcombinefn => 'int4xor', aggtranstype => 'int4' }, +{ aggfnoid => 'bit_and(int8)', aggtransfn => 'int8and', + aggcombinefn => 'int8and', aggtranstype => 'int8' }, +{ aggfnoid => 'bit_or(int8)', aggtransfn => 'int8or', aggcombinefn => 'int8or', + aggtranstype => 'int8' }, +{ aggfnoid => 'bit_xor(int8)', aggtransfn => 'int8xor', + aggcombinefn => 'int8xor', aggtranstype => 'int8' }, +{ aggfnoid => 'bit_and(bit)', aggtransfn => 'bitand', aggcombinefn => 'bitand', + aggtranstype => 'bit' }, +{ aggfnoid => 'bit_or(bit)', aggtransfn => 'bitor', aggcombinefn => 'bitor', + aggtranstype => 'bit' }, +{ aggfnoid => 'bit_xor(bit)', aggtransfn => 'bitxor', aggcombinefn => 'bitxor', + aggtranstype => 'bit' }, + +# xml +{ aggfnoid => 'xmlagg', aggtransfn => 'xmlconcat2', aggtranstype => 'xml' }, + +# array +{ aggfnoid => 'array_agg(anynonarray)', aggtransfn => 'array_agg_transfn', + aggfinalfn => 'array_agg_finalfn', aggfinalextra => 't', + aggtranstype => 'internal' }, +{ aggfnoid => 'array_agg(anyarray)', aggtransfn => 'array_agg_array_transfn', + aggfinalfn => 'array_agg_array_finalfn', aggfinalextra => 't', + aggtranstype => 'internal' }, + +# text +{ aggfnoid => 'string_agg(text,text)', aggtransfn => 'string_agg_transfn', + aggfinalfn => 'string_agg_finalfn', aggtranstype => 'internal' }, + +# bytea +{ aggfnoid => 'string_agg(bytea,bytea)', + aggtransfn => 'bytea_string_agg_transfn', + aggfinalfn => 'bytea_string_agg_finalfn', aggtranstype => 'internal' }, + +# range +{ aggfnoid => 'range_intersect_agg(anyrange)', + aggtransfn => 'range_intersect_agg_transfn', + aggcombinefn => 'range_intersect_agg_transfn', aggtranstype => 'anyrange' }, +{ aggfnoid => 'range_intersect_agg(anymultirange)', + aggtransfn => 'multirange_intersect_agg_transfn', + aggcombinefn => 'multirange_intersect_agg_transfn', + aggtranstype => 'anymultirange' }, +{ aggfnoid => 'range_agg(anyrange)', aggtransfn => 'range_agg_transfn', + aggfinalfn => 'range_agg_finalfn', aggfinalextra => 't', + aggtranstype => 'internal' }, +{ aggfnoid => 'range_agg(anymultirange)', + aggtransfn => 'multirange_agg_transfn', + aggfinalfn => 'multirange_agg_finalfn', aggfinalextra => 't', + aggtranstype => 'internal' }, + +# json +{ aggfnoid => 'json_agg', aggtransfn => 'json_agg_transfn', + aggfinalfn => 'json_agg_finalfn', aggtranstype => 'internal' }, +{ aggfnoid => 'json_object_agg', aggtransfn => 'json_object_agg_transfn', + aggfinalfn => 'json_object_agg_finalfn', aggtranstype => 'internal' }, + +# jsonb +{ aggfnoid => 'jsonb_agg', aggtransfn => 'jsonb_agg_transfn', + aggfinalfn => 'jsonb_agg_finalfn', aggtranstype => 'internal' }, +{ aggfnoid => 'jsonb_object_agg', aggtransfn => 'jsonb_object_agg_transfn', + aggfinalfn => 'jsonb_object_agg_finalfn', aggtranstype => 'internal' }, + +# ordered-set and hypothetical-set aggregates +{ aggfnoid => 'percentile_disc(float8,anyelement)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_disc_final', aggfinalextra => 't', + aggfinalmodify => 's', aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'percentile_cont(float8,float8)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_cont_float8_final', aggfinalmodify => 's', + aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'percentile_cont(float8,interval)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_cont_interval_final', aggfinalmodify => 's', + aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'percentile_disc(_float8,anyelement)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_disc_multi_final', aggfinalextra => 't', + aggfinalmodify => 's', aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'percentile_cont(_float8,float8)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_cont_float8_multi_final', aggfinalmodify => 's', + aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'percentile_cont(_float8,interval)', aggkind => 'o', + aggnumdirectargs => '1', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'percentile_cont_interval_multi_final', aggfinalmodify => 's', + aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'mode', aggkind => 'o', aggtransfn => 'ordered_set_transition', + aggfinalfn => 'mode_final', aggfinalextra => 't', aggfinalmodify => 's', + aggmfinalmodify => 's', aggtranstype => 'internal' }, +{ aggfnoid => 'rank(any)', aggkind => 'h', aggnumdirectargs => '1', + aggtransfn => 'ordered_set_transition_multi', aggfinalfn => 'rank_final', + aggfinalextra => 't', aggfinalmodify => 'w', aggmfinalmodify => 'w', + aggtranstype => 'internal' }, +{ aggfnoid => 'percent_rank(any)', aggkind => 'h', aggnumdirectargs => '1', + aggtransfn => 'ordered_set_transition_multi', + aggfinalfn => 'percent_rank_final', aggfinalextra => 't', + aggfinalmodify => 'w', aggmfinalmodify => 'w', aggtranstype => 'internal' }, +{ aggfnoid => 'cume_dist(any)', aggkind => 'h', aggnumdirectargs => '1', + aggtransfn => 'ordered_set_transition_multi', aggfinalfn => 'cume_dist_final', + aggfinalextra => 't', aggfinalmodify => 'w', aggmfinalmodify => 'w', + aggtranstype => 'internal' }, +{ aggfnoid => 'dense_rank(any)', aggkind => 'h', aggnumdirectargs => '1', + aggtransfn => 'ordered_set_transition_multi', + aggfinalfn => 'dense_rank_final', aggfinalextra => 't', aggfinalmodify => 'w', + aggmfinalmodify => 'w', aggtranstype => 'internal' }, + +] diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h new file mode 100644 index 0000000..593da9f --- /dev/null +++ b/src/include/catalog/pg_aggregate.h @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- + * + * pg_aggregate.h + * definition of the "aggregate" system catalog (pg_aggregate) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_aggregate.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AGGREGATE_H +#define PG_AGGREGATE_H + +#include "catalog/genbki.h" +#include "catalog/pg_aggregate_d.h" + +#include "catalog/objectaddress.h" +#include "nodes/pg_list.h" + +/* ---------------------------------------------------------------- + * pg_aggregate definition. + * cpp turns this into typedef struct FormData_pg_aggregate + * ---------------------------------------------------------------- + */ +CATALOG(pg_aggregate,2600,AggregateRelationId) +{ + /* pg_proc OID of the aggregate itself */ + regproc aggfnoid BKI_LOOKUP(pg_proc); + + /* aggregate kind, see AGGKIND_ categories below */ + char aggkind BKI_DEFAULT(n); + + /* number of arguments that are "direct" arguments */ + int16 aggnumdirectargs BKI_DEFAULT(0); + + /* transition function */ + regproc aggtransfn BKI_LOOKUP(pg_proc); + + /* final function (0 if none) */ + regproc aggfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* combine function (0 if none) */ + regproc aggcombinefn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* function to convert transtype to bytea (0 if none) */ + regproc aggserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* function to convert bytea to transtype (0 if none) */ + regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* forward function for moving-aggregate mode (0 if none) */ + regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* inverse function for moving-aggregate mode (0 if none) */ + regproc aggminvtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* final function for moving-aggregate mode (0 if none) */ + regproc aggmfinalfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* true to pass extra dummy arguments to aggfinalfn */ + bool aggfinalextra BKI_DEFAULT(f); + + /* true to pass extra dummy arguments to aggmfinalfn */ + bool aggmfinalextra BKI_DEFAULT(f); + + /* tells whether aggfinalfn modifies transition state */ + char aggfinalmodify BKI_DEFAULT(r); + + /* tells whether aggmfinalfn modifies transition state */ + char aggmfinalmodify BKI_DEFAULT(r); + + /* associated sort operator (0 if none) */ + Oid aggsortop BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); + + /* type of aggregate's transition (state) data */ + Oid aggtranstype BKI_LOOKUP(pg_type); + + /* estimated size of state data (0 for default estimate) */ + int32 aggtransspace BKI_DEFAULT(0); + + /* type of moving-aggregate state data (0 if none) */ + Oid aggmtranstype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* estimated size of moving-agg state (0 for default est) */ + int32 aggmtransspace BKI_DEFAULT(0); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + /* initial value for transition state (can be NULL) */ + text agginitval BKI_DEFAULT(_null_); + + /* initial value for moving-agg state (can be NULL) */ + text aggminitval BKI_DEFAULT(_null_); +#endif +} FormData_pg_aggregate; + +/* ---------------- + * Form_pg_aggregate corresponds to a pointer to a tuple with + * the format of pg_aggregate relation. + * ---------------- + */ +typedef FormData_pg_aggregate *Form_pg_aggregate; + +DECLARE_TOAST(pg_aggregate, 4159, 4160); + +DECLARE_UNIQUE_INDEX_PKEY(pg_aggregate_fnoid_index, 2650, AggregateFnoidIndexId, on pg_aggregate using btree(aggfnoid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Symbolic values for aggkind column. We distinguish normal aggregates + * from ordered-set aggregates (which have two sets of arguments, namely + * direct and aggregated arguments) and from hypothetical-set aggregates + * (which are a subclass of ordered-set aggregates in which the last + * direct arguments have to match up in number and datatypes with the + * aggregated arguments). + */ +#define AGGKIND_NORMAL 'n' +#define AGGKIND_ORDERED_SET 'o' +#define AGGKIND_HYPOTHETICAL 'h' + +/* Use this macro to test for "ordered-set agg including hypothetical case" */ +#define AGGKIND_IS_ORDERED_SET(kind) ((kind) != AGGKIND_NORMAL) + +/* + * Symbolic values for aggfinalmodify and aggmfinalmodify columns. + * Preferably, finalfns do not modify the transition state value at all, + * but in some cases that would cost too much performance. We distinguish + * "pure read only" and "trashes it arbitrarily" cases, as well as the + * intermediate case where multiple finalfn calls are allowed but the + * transfn cannot be applied anymore after the first finalfn call. + */ +#define AGGMODIFY_READ_ONLY 'r' +#define AGGMODIFY_SHAREABLE 's' +#define AGGMODIFY_READ_WRITE 'w' + +#endif /* EXPOSE_TO_CLIENT_CODE */ + + +extern ObjectAddress AggregateCreate(const char *aggName, + Oid aggNamespace, + bool replace, + char aggKind, + int numArgs, + int numDirectArgs, + oidvector *parameterTypes, + Datum allParameterTypes, + Datum parameterModes, + Datum parameterNames, + List *parameterDefaults, + Oid variadicArgType, + List *aggtransfnName, + List *aggfinalfnName, + List *aggcombinefnName, + List *aggserialfnName, + List *aggdeserialfnName, + List *aggmtransfnName, + List *aggminvtransfnName, + List *aggmfinalfnName, + bool finalfnExtraArgs, + bool mfinalfnExtraArgs, + char finalfnModify, + char mfinalfnModify, + List *aggsortopName, + Oid aggTransType, + int32 aggTransSpace, + Oid aggmTransType, + int32 aggmTransSpace, + const char *agginitval, + const char *aggminitval, + char proparallel); + +#endif /* PG_AGGREGATE_H */ diff --git a/src/include/catalog/pg_am.dat b/src/include/catalog/pg_am.dat new file mode 100644 index 0000000..3d6653e --- /dev/null +++ b/src/include/catalog/pg_am.dat @@ -0,0 +1,37 @@ +#---------------------------------------------------------------------- +# +# pg_am.dat +# Initial contents of the pg_am system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_am.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '2', oid_symbol => 'HEAP_TABLE_AM_OID', + descr => 'heap table access method', + amname => 'heap', amhandler => 'heap_tableam_handler', amtype => 't' }, +{ oid => '403', oid_symbol => 'BTREE_AM_OID', + descr => 'b-tree index access method', + amname => 'btree', amhandler => 'bthandler', amtype => 'i' }, +{ oid => '405', oid_symbol => 'HASH_AM_OID', + descr => 'hash index access method', + amname => 'hash', amhandler => 'hashhandler', amtype => 'i' }, +{ oid => '783', oid_symbol => 'GIST_AM_OID', + descr => 'GiST index access method', + amname => 'gist', amhandler => 'gisthandler', amtype => 'i' }, +{ oid => '2742', oid_symbol => 'GIN_AM_OID', + descr => 'GIN index access method', + amname => 'gin', amhandler => 'ginhandler', amtype => 'i' }, +{ oid => '4000', oid_symbol => 'SPGIST_AM_OID', + descr => 'SP-GiST index access method', + amname => 'spgist', amhandler => 'spghandler', amtype => 'i' }, +{ oid => '3580', oid_symbol => 'BRIN_AM_OID', + descr => 'block range index (BRIN) access method', + amname => 'brin', amhandler => 'brinhandler', amtype => 'i' }, + +] diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h new file mode 100644 index 0000000..50a68fe --- /dev/null +++ b/src/include/catalog/pg_am.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * pg_am.h + * definition of the "access method" system catalog (pg_am) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_am.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AM_H +#define PG_AM_H + +#include "catalog/genbki.h" +#include "catalog/pg_am_d.h" + +/* ---------------- + * pg_am definition. cpp turns this into + * typedef struct FormData_pg_am + * ---------------- + */ +CATALOG(pg_am,2601,AccessMethodRelationId) +{ + Oid oid; /* oid */ + + /* access method name */ + NameData amname; + + /* handler function */ + regproc amhandler BKI_LOOKUP(pg_proc); + + /* see AMTYPE_xxx constants below */ + char amtype; +} FormData_pg_am; + +/* ---------------- + * Form_pg_am corresponds to a pointer to a tuple with + * the format of pg_am relation. + * ---------------- + */ +typedef FormData_pg_am *Form_pg_am; + +DECLARE_UNIQUE_INDEX(pg_am_name_index, 2651, AmNameIndexId, on pg_am using btree(amname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_am_oid_index, 2652, AmOidIndexId, on pg_am using btree(oid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Allowed values for amtype + */ +#define AMTYPE_INDEX 'i' /* index access method */ +#define AMTYPE_TABLE 't' /* table access method */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_AM_H */ diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat new file mode 100644 index 0000000..61cd591 --- /dev/null +++ b/src/include/catalog/pg_amop.dat @@ -0,0 +1,3230 @@ +#---------------------------------------------------------------------- +# +# pg_amop.dat +# Initial contents of the pg_amop system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_amop.dat +# +#---------------------------------------------------------------------- + +[ + +# btree integer_ops + +# default operators int2 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int2,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int2,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int2,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int2,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int2,int2)', + amopmethod => 'btree' }, + +# crosstype operators int24 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int2,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int2,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int2,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int2,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int2,int4)', + amopmethod => 'btree' }, + +# crosstype operators int28 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int2,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int2,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int2,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int2,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int2,int8)', + amopmethod => 'btree' }, + +# default operators int4 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int4,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int4,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int4,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int4,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int4,int4)', + amopmethod => 'btree' }, + +# crosstype operators int42 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int4,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int4,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int4,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int4,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int4,int2)', + amopmethod => 'btree' }, + +# crosstype operators int48 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int4,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int4,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int4,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int4,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int4,int8)', + amopmethod => 'btree' }, + +# default operators int8 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int8,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int8,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int8,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int8,int8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int8,int8)', + amopmethod => 'btree' }, + +# crosstype operators int82 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int8,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int8,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int8,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int8,int2)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int8,int2)', + amopmethod => 'btree' }, + +# crosstype operators int84 +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int8,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int8,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int8,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int8,int4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int8,int4)', + amopmethod => 'btree' }, + +# btree oid_ops + +{ amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '1', amopopr => '<(oid,oid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '2', amopopr => '<=(oid,oid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '3', amopopr => '=(oid,oid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '4', amopopr => '>=(oid,oid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '5', amopopr => '>(oid,oid)', amopmethod => 'btree' }, + +# btree xid8_ops + +{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '1', amopopr => '<(xid8,xid8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '2', amopopr => '<=(xid8,xid8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '3', amopopr => '=(xid8,xid8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '4', amopopr => '>=(xid8,xid8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '5', amopopr => '>(xid8,xid8)', + amopmethod => 'btree' }, + +# btree tid_ops + +{ amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '1', amopopr => '<(tid,tid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '2', amopopr => '<=(tid,tid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '3', amopopr => '=(tid,tid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '4', amopopr => '>=(tid,tid)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '5', amopopr => '>(tid,tid)', amopmethod => 'btree' }, + +# btree oidvector_ops + +{ amopfamily => 'btree/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '1', + amopopr => '<(oidvector,oidvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '2', + amopopr => '<=(oidvector,oidvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '3', + amopopr => '=(oidvector,oidvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '4', + amopopr => '>=(oidvector,oidvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '5', + amopopr => '>(oidvector,oidvector)', amopmethod => 'btree' }, + +# btree float_ops + +# default operators float4 +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float4,float4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float4,float4)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float4,float4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float4,float4)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float4,float4)', + amopmethod => 'btree' }, + +# crosstype operators float48 +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float4,float8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float4,float8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float4,float8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float4,float8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float4,float8)', + amopmethod => 'btree' }, + +# default operators float8 +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float8,float8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float8,float8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float8,float8)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float8,float8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float8,float8)', + amopmethod => 'btree' }, + +# crosstype operators float84 +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float8,float4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float8,float4)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float8,float4)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float8,float4)', amopmethod => 'btree' }, +{ amopfamily => 'btree/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float8,float4)', + amopmethod => 'btree' }, + +# btree char_ops + +{ amopfamily => 'btree/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '1', amopopr => '<(char,char)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '2', amopopr => '<=(char,char)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '3', amopopr => '=(char,char)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '4', amopopr => '>=(char,char)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '5', amopopr => '>(char,char)', + amopmethod => 'btree' }, + +# btree text_ops + +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '<(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '2', amopopr => '<=(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '3', amopopr => '=(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '4', amopopr => '>=(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '5', amopopr => '>(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '1', amopopr => '<(name,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '2', amopopr => '<=(name,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '3', amopopr => '=(name,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '4', amopopr => '>=(name,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '5', amopopr => '>(name,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '1', amopopr => '<(name,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '2', amopopr => '<=(name,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '3', amopopr => '=(name,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '4', amopopr => '>=(name,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '5', amopopr => '>(name,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '1', amopopr => '<(text,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '2', amopopr => '<=(text,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '3', amopopr => '=(text,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '4', amopopr => '>=(text,name)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '5', amopopr => '>(text,name)', + amopmethod => 'btree' }, + +# btree bpchar_ops + +{ amopfamily => 'btree/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '<(bpchar,bpchar)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '2', + amopopr => '<=(bpchar,bpchar)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '3', amopopr => '=(bpchar,bpchar)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '4', + amopopr => '>=(bpchar,bpchar)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '5', amopopr => '>(bpchar,bpchar)', + amopmethod => 'btree' }, + +# btree bytea_ops + +{ amopfamily => 'btree/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '1', amopopr => '<(bytea,bytea)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '2', amopopr => '<=(bytea,bytea)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '3', amopopr => '=(bytea,bytea)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '4', amopopr => '>=(bytea,bytea)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '5', amopopr => '>(bytea,bytea)', + amopmethod => 'btree' }, + +# btree datetime_ops + +# default operators date +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(date,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(date,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(date,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(date,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(date,date)', + amopmethod => 'btree' }, + +# crosstype operators vs timestamp +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(date,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(date,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(date,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(date,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(date,timestamp)', amopmethod => 'btree' }, + +# crosstype operators vs timestamptz +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(date,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(date,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(date,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(date,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(date,timestamptz)', amopmethod => 'btree' }, + +# default operators timestamp +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamp,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamp,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamp,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamp,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamp,timestamp)', amopmethod => 'btree' }, + +# crosstype operators vs date +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(timestamp,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(timestamp,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(timestamp,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(timestamp,date)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(timestamp,date)', + amopmethod => 'btree' }, + +# crosstype operators vs timestamptz +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamp,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamp,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamp,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamp,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamp,timestamptz)', amopmethod => 'btree' }, + +# default operators timestamptz +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamptz,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamptz,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamptz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamptz,timestamptz)', amopmethod => 'btree' }, + +# crosstype operators vs date +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '1', + amopopr => '<(timestamptz,date)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '2', + amopopr => '<=(timestamptz,date)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '3', + amopopr => '=(timestamptz,date)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '4', + amopopr => '>=(timestamptz,date)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '5', + amopopr => '>(timestamptz,date)', amopmethod => 'btree' }, + +# crosstype operators vs timestamp +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamptz,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamptz,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamp)', amopmethod => 'btree' }, +{ amopfamily => 'btree/datetime_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamptz,timestamp)', amopmethod => 'btree' }, + +# btree time_ops + +{ amopfamily => 'btree/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '1', amopopr => '<(time,time)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '2', amopopr => '<=(time,time)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '3', amopopr => '=(time,time)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '4', amopopr => '>=(time,time)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '5', amopopr => '>(time,time)', + amopmethod => 'btree' }, + +# btree timetz_ops + +{ amopfamily => 'btree/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '1', amopopr => '<(timetz,timetz)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '2', + amopopr => '<=(timetz,timetz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '3', amopopr => '=(timetz,timetz)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '4', + amopopr => '>=(timetz,timetz)', amopmethod => 'btree' }, +{ amopfamily => 'btree/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '5', amopopr => '>(timetz,timetz)', + amopmethod => 'btree' }, + +# btree interval_ops + +{ amopfamily => 'btree/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '1', + amopopr => '<(interval,interval)', amopmethod => 'btree' }, +{ amopfamily => 'btree/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '2', + amopopr => '<=(interval,interval)', amopmethod => 'btree' }, +{ amopfamily => 'btree/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '3', + amopopr => '=(interval,interval)', amopmethod => 'btree' }, +{ amopfamily => 'btree/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '4', + amopopr => '>=(interval,interval)', amopmethod => 'btree' }, +{ amopfamily => 'btree/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '5', + amopopr => '>(interval,interval)', amopmethod => 'btree' }, + +# btree macaddr + +{ amopfamily => 'btree/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '1', + amopopr => '<(macaddr,macaddr)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '2', + amopopr => '<=(macaddr,macaddr)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '3', + amopopr => '=(macaddr,macaddr)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '4', + amopopr => '>=(macaddr,macaddr)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '5', + amopopr => '>(macaddr,macaddr)', amopmethod => 'btree' }, + +# btree macaddr8 + +{ amopfamily => 'btree/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '1', + amopopr => '<(macaddr8,macaddr8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '2', + amopopr => '<=(macaddr8,macaddr8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '3', + amopopr => '=(macaddr8,macaddr8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '4', + amopopr => '>=(macaddr8,macaddr8)', amopmethod => 'btree' }, +{ amopfamily => 'btree/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '5', + amopopr => '>(macaddr8,macaddr8)', amopmethod => 'btree' }, + +# btree network + +{ amopfamily => 'btree/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '1', amopopr => '<(inet,inet)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '2', amopopr => '<=(inet,inet)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '=(inet,inet)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '4', amopopr => '>=(inet,inet)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '5', amopopr => '>(inet,inet)', + amopmethod => 'btree' }, + +# btree numeric + +{ amopfamily => 'btree/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '1', + amopopr => '<(numeric,numeric)', amopmethod => 'btree' }, +{ amopfamily => 'btree/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '2', + amopopr => '<=(numeric,numeric)', amopmethod => 'btree' }, +{ amopfamily => 'btree/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '3', + amopopr => '=(numeric,numeric)', amopmethod => 'btree' }, +{ amopfamily => 'btree/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '4', + amopopr => '>=(numeric,numeric)', amopmethod => 'btree' }, +{ amopfamily => 'btree/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '5', + amopopr => '>(numeric,numeric)', amopmethod => 'btree' }, + +# btree bool + +{ amopfamily => 'btree/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '1', amopopr => '<(bool,bool)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '2', amopopr => '<=(bool,bool)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '3', amopopr => '=(bool,bool)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '4', amopopr => '>=(bool,bool)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '5', amopopr => '>(bool,bool)', + amopmethod => 'btree' }, + +# btree bit + +{ amopfamily => 'btree/bit_ops', amoplefttype => 'bit', amoprighttype => 'bit', + amopstrategy => '1', amopopr => '<(bit,bit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bit_ops', amoplefttype => 'bit', amoprighttype => 'bit', + amopstrategy => '2', amopopr => '<=(bit,bit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bit_ops', amoplefttype => 'bit', amoprighttype => 'bit', + amopstrategy => '3', amopopr => '=(bit,bit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bit_ops', amoplefttype => 'bit', amoprighttype => 'bit', + amopstrategy => '4', amopopr => '>=(bit,bit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bit_ops', amoplefttype => 'bit', amoprighttype => 'bit', + amopstrategy => '5', amopopr => '>(bit,bit)', amopmethod => 'btree' }, + +# btree varbit + +{ amopfamily => 'btree/varbit_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '1', amopopr => '<(varbit,varbit)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/varbit_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '2', + amopopr => '<=(varbit,varbit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/varbit_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '3', amopopr => '=(varbit,varbit)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/varbit_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '4', + amopopr => '>=(varbit,varbit)', amopmethod => 'btree' }, +{ amopfamily => 'btree/varbit_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '5', amopopr => '>(varbit,varbit)', + amopmethod => 'btree' }, + +# btree text pattern + +{ amopfamily => 'btree/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '~<~(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '2', amopopr => '~<=~(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '3', amopopr => '=(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '4', amopopr => '~>=~(text,text)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '5', amopopr => '~>~(text,text)', + amopmethod => 'btree' }, + +# btree bpchar pattern + +{ amopfamily => 'btree/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', + amopopr => '~<~(bpchar,bpchar)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '2', + amopopr => '~<=~(bpchar,bpchar)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '3', amopopr => '=(bpchar,bpchar)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '4', + amopopr => '~>=~(bpchar,bpchar)', amopmethod => 'btree' }, +{ amopfamily => 'btree/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '5', + amopopr => '~>~(bpchar,bpchar)', amopmethod => 'btree' }, + +# btree money_ops + +{ amopfamily => 'btree/money_ops', amoplefttype => 'money', + amoprighttype => 'money', amopstrategy => '1', amopopr => '<(money,money)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/money_ops', amoplefttype => 'money', + amoprighttype => 'money', amopstrategy => '2', amopopr => '<=(money,money)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/money_ops', amoplefttype => 'money', + amoprighttype => 'money', amopstrategy => '3', amopopr => '=(money,money)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/money_ops', amoplefttype => 'money', + amoprighttype => 'money', amopstrategy => '4', amopopr => '>=(money,money)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/money_ops', amoplefttype => 'money', + amoprighttype => 'money', amopstrategy => '5', amopopr => '>(money,money)', + amopmethod => 'btree' }, + +# btree array_ops + +{ amopfamily => 'btree/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '1', + amopopr => '<(anyarray,anyarray)', amopmethod => 'btree' }, +{ amopfamily => 'btree/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '2', + amopopr => '<=(anyarray,anyarray)', amopmethod => 'btree' }, +{ amopfamily => 'btree/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '3', + amopopr => '=(anyarray,anyarray)', amopmethod => 'btree' }, +{ amopfamily => 'btree/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '4', + amopopr => '>=(anyarray,anyarray)', amopmethod => 'btree' }, +{ amopfamily => 'btree/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '5', + amopopr => '>(anyarray,anyarray)', amopmethod => 'btree' }, + +# btree record_ops + +{ amopfamily => 'btree/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '1', amopopr => '<(record,record)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '2', + amopopr => '<=(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '3', amopopr => '=(record,record)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '4', + amopopr => '>=(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '5', amopopr => '>(record,record)', + amopmethod => 'btree' }, + +# btree record_image_ops + +{ amopfamily => 'btree/record_image_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '1', + amopopr => '*<(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_image_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '2', + amopopr => '*<=(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_image_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '3', + amopopr => '*=(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_image_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '4', + amopopr => '*>=(record,record)', amopmethod => 'btree' }, +{ amopfamily => 'btree/record_image_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '5', + amopopr => '*>(record,record)', amopmethod => 'btree' }, + +# btree uuid_ops + +{ amopfamily => 'btree/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '1', amopopr => '<(uuid,uuid)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '2', amopopr => '<=(uuid,uuid)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '3', amopopr => '=(uuid,uuid)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '4', amopopr => '>=(uuid,uuid)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '5', amopopr => '>(uuid,uuid)', + amopmethod => 'btree' }, + +# btree pg_lsn_ops + +{ amopfamily => 'btree/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '<(pg_lsn,pg_lsn)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '2', + amopopr => '<=(pg_lsn,pg_lsn)', amopmethod => 'btree' }, +{ amopfamily => 'btree/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '3', amopopr => '=(pg_lsn,pg_lsn)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '4', + amopopr => '>=(pg_lsn,pg_lsn)', amopmethod => 'btree' }, +{ amopfamily => 'btree/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '5', amopopr => '>(pg_lsn,pg_lsn)', + amopmethod => 'btree' }, + +# hash index_ops + +# bpchar_ops +{ amopfamily => 'hash/bpchar_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '=(bpchar,bpchar)', + amopmethod => 'hash' }, + +# char_ops +{ amopfamily => 'hash/char_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '1', amopopr => '=(char,char)', + amopmethod => 'hash' }, + +# date_ops +{ amopfamily => 'hash/date_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '1', amopopr => '=(date,date)', + amopmethod => 'hash' }, + +# float_ops +{ amopfamily => 'hash/float_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '=(float4,float4)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/float_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '=(float8,float8)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/float_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '=(float4,float8)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/float_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '=(float8,float4)', + amopmethod => 'hash' }, + +# network_ops +{ amopfamily => 'hash/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '1', amopopr => '=(inet,inet)', + amopmethod => 'hash' }, + +# integer_ops +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '=(int2,int2)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '=(int4,int4)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '=(int8,int8)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '=(int2,int4)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '=(int2,int8)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '=(int4,int2)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '=(int4,int8)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '=(int8,int2)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/integer_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '=(int8,int4)', + amopmethod => 'hash' }, + +# interval_ops +{ amopfamily => 'hash/interval_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '1', + amopopr => '=(interval,interval)', amopmethod => 'hash' }, + +# macaddr_ops +{ amopfamily => 'hash/macaddr_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '1', + amopopr => '=(macaddr,macaddr)', amopmethod => 'hash' }, + +# macaddr8_ops +{ amopfamily => 'hash/macaddr8_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '1', + amopopr => '=(macaddr8,macaddr8)', amopmethod => 'hash' }, + +# oid_ops +{ amopfamily => 'hash/oid_ops', amoplefttype => 'oid', amoprighttype => 'oid', + amopstrategy => '1', amopopr => '=(oid,oid)', amopmethod => 'hash' }, + +# oidvector_ops +{ amopfamily => 'hash/oidvector_ops', amoplefttype => 'oidvector', + amoprighttype => 'oidvector', amopstrategy => '1', + amopopr => '=(oidvector,oidvector)', amopmethod => 'hash' }, + +# record_ops +{ amopfamily => 'hash/record_ops', amoplefttype => 'record', + amoprighttype => 'record', amopstrategy => '1', amopopr => '=(record,record)', + amopmethod => 'hash' }, + +# text_ops +{ amopfamily => 'hash/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '=(text,text)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/text_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '1', amopopr => '=(name,name)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/text_ops', amoplefttype => 'name', + amoprighttype => 'text', amopstrategy => '1', amopopr => '=(name,text)', + amopmethod => 'hash' }, +{ amopfamily => 'hash/text_ops', amoplefttype => 'text', + amoprighttype => 'name', amopstrategy => '1', amopopr => '=(text,name)', + amopmethod => 'hash' }, + +# time_ops +{ amopfamily => 'hash/time_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '1', amopopr => '=(time,time)', + amopmethod => 'hash' }, + +# timestamptz_ops +{ amopfamily => 'hash/timestamptz_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '=(timestamptz,timestamptz)', amopmethod => 'hash' }, + +# timetz_ops +{ amopfamily => 'hash/timetz_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '1', amopopr => '=(timetz,timetz)', + amopmethod => 'hash' }, + +# timestamp_ops +{ amopfamily => 'hash/timestamp_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '=(timestamp,timestamp)', amopmethod => 'hash' }, + +# bool_ops +{ amopfamily => 'hash/bool_ops', amoplefttype => 'bool', + amoprighttype => 'bool', amopstrategy => '1', amopopr => '=(bool,bool)', + amopmethod => 'hash' }, + +# bytea_ops +{ amopfamily => 'hash/bytea_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '1', amopopr => '=(bytea,bytea)', + amopmethod => 'hash' }, + +# xid_ops +{ amopfamily => 'hash/xid_ops', amoplefttype => 'xid', amoprighttype => 'xid', + amopstrategy => '1', amopopr => '=(xid,xid)', amopmethod => 'hash' }, + +# xid8_ops +{ amopfamily => 'hash/xid8_ops', amoplefttype => 'xid8', + amoprighttype => 'xid8', amopstrategy => '1', amopopr => '=(xid8,xid8)', + amopmethod => 'hash' }, + +# cid_ops +{ amopfamily => 'hash/cid_ops', amoplefttype => 'cid', amoprighttype => 'cid', + amopstrategy => '1', amopopr => '=(cid,cid)', amopmethod => 'hash' }, + +# tid_ops +{ amopfamily => 'hash/tid_ops', amoplefttype => 'tid', amoprighttype => 'tid', + amopstrategy => '1', amopopr => '=(tid,tid)', amopmethod => 'hash' }, + +# text_pattern_ops +{ amopfamily => 'hash/text_pattern_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '=(text,text)', + amopmethod => 'hash' }, + +# bpchar_pattern_ops +{ amopfamily => 'hash/bpchar_pattern_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '=(bpchar,bpchar)', + amopmethod => 'hash' }, + +# aclitem_ops +{ amopfamily => 'hash/aclitem_ops', amoplefttype => 'aclitem', + amoprighttype => 'aclitem', amopstrategy => '1', + amopopr => '=(aclitem,aclitem)', amopmethod => 'hash' }, + +# uuid_ops +{ amopfamily => 'hash/uuid_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '1', amopopr => '=(uuid,uuid)', + amopmethod => 'hash' }, + +# pg_lsn_ops +{ amopfamily => 'hash/pg_lsn_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '=(pg_lsn,pg_lsn)', + amopmethod => 'hash' }, + +# numeric_ops +{ amopfamily => 'hash/numeric_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '1', + amopopr => '=(numeric,numeric)', amopmethod => 'hash' }, + +# array_ops +{ amopfamily => 'hash/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '1', + amopopr => '=(anyarray,anyarray)', amopmethod => 'hash' }, + +# gist box_ops +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '1', amopopr => '<<(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '2', amopopr => '&<(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '3', amopopr => '&&(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '4', amopopr => '&>(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '5', amopopr => '>>(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '6', amopopr => '~=(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '7', amopopr => '@>(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '8', amopopr => '<@(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '9', amopopr => '&<|(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '10', amopopr => '<<|(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '11', amopopr => '|>>(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '12', amopopr => '|&>(box,box)', amopmethod => 'gist' }, +{ amopfamily => 'gist/box_ops', amoplefttype => 'box', amoprighttype => 'point', + amopstrategy => '15', amoppurpose => 'o', amopopr => '<->(box,point)', + amopmethod => 'gist', amopsortfamily => 'btree/float_ops' }, + +# gist point_ops +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '11', amopopr => '|>>(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '30', amopopr => '>^(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '1', amopopr => '<<(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '5', amopopr => '>>(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '10', amopopr => '<<|(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '29', amopopr => '<^(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '6', amopopr => '~=(point,point)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(point,point)', amopmethod => 'gist', + amopsortfamily => 'btree/float_ops' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'box', amopstrategy => '28', amopopr => '<@(point,box)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'polygon', amopstrategy => '48', + amopopr => '<@(point,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/point_ops', amoplefttype => 'point', + amoprighttype => 'circle', amopstrategy => '68', + amopopr => '<@(point,circle)', amopmethod => 'gist' }, + +# gist poly_ops (supports polygons) +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '1', + amopopr => '<<(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '2', + amopopr => '&<(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '3', + amopopr => '&&(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '4', + amopopr => '&>(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '5', + amopopr => '>>(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '6', + amopopr => '~=(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '7', + amopopr => '@>(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '8', + amopopr => '<@(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '9', + amopopr => '&<|(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '10', + amopopr => '<<|(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '11', + amopopr => '|>>(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '12', + amopopr => '|&>(polygon,polygon)', amopmethod => 'gist' }, +{ amopfamily => 'gist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(polygon,point)', amopmethod => 'gist', + amopsortfamily => 'btree/float_ops' }, + +# gist circle_ops +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '1', + amopopr => '<<(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '2', + amopopr => '&<(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '3', + amopopr => '&&(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '4', + amopopr => '&>(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '5', + amopopr => '>>(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '6', + amopopr => '~=(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '7', + amopopr => '@>(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '8', + amopopr => '<@(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '9', + amopopr => '&<|(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '10', + amopopr => '<<|(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '11', + amopopr => '|>>(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'circle', amopstrategy => '12', + amopopr => '|&>(circle,circle)', amopmethod => 'gist' }, +{ amopfamily => 'gist/circle_ops', amoplefttype => 'circle', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(circle,point)', amopmethod => 'gist', + amopsortfamily => 'btree/float_ops' }, + +# gin array_ops +{ amopfamily => 'gin/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '1', + amopopr => '&&(anyarray,anyarray)', amopmethod => 'gin' }, +{ amopfamily => 'gin/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '2', + amopopr => '@>(anyarray,anyarray)', amopmethod => 'gin' }, +{ amopfamily => 'gin/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '3', + amopopr => '<@(anyarray,anyarray)', amopmethod => 'gin' }, +{ amopfamily => 'gin/array_ops', amoplefttype => 'anyarray', + amoprighttype => 'anyarray', amopstrategy => '4', + amopopr => '=(anyarray,anyarray)', amopmethod => 'gin' }, + +# btree enum_ops +{ amopfamily => 'btree/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '1', + amopopr => '<(anyenum,anyenum)', amopmethod => 'btree' }, +{ amopfamily => 'btree/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '2', + amopopr => '<=(anyenum,anyenum)', amopmethod => 'btree' }, +{ amopfamily => 'btree/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '3', + amopopr => '=(anyenum,anyenum)', amopmethod => 'btree' }, +{ amopfamily => 'btree/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '4', + amopopr => '>=(anyenum,anyenum)', amopmethod => 'btree' }, +{ amopfamily => 'btree/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '5', + amopopr => '>(anyenum,anyenum)', amopmethod => 'btree' }, + +# hash enum_ops +{ amopfamily => 'hash/enum_ops', amoplefttype => 'anyenum', + amoprighttype => 'anyenum', amopstrategy => '1', + amopopr => '=(anyenum,anyenum)', amopmethod => 'hash' }, + +# btree tsvector_ops +{ amopfamily => 'btree/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsvector', amopstrategy => '1', + amopopr => '<(tsvector,tsvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsvector', amopstrategy => '2', + amopopr => '<=(tsvector,tsvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsvector', amopstrategy => '3', + amopopr => '=(tsvector,tsvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsvector', amopstrategy => '4', + amopopr => '>=(tsvector,tsvector)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsvector', amopstrategy => '5', + amopopr => '>(tsvector,tsvector)', amopmethod => 'btree' }, + +# GiST tsvector_ops +{ amopfamily => 'gist/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsquery', amopstrategy => '1', + amopopr => '@@(tsvector,tsquery)', amopmethod => 'gist' }, + +# GIN tsvector_ops +{ amopfamily => 'gin/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsquery', amopstrategy => '1', + amopopr => '@@(tsvector,tsquery)', amopmethod => 'gin' }, +{ amopfamily => 'gin/tsvector_ops', amoplefttype => 'tsvector', + amoprighttype => 'tsquery', amopstrategy => '2', + amopopr => '@@@(tsvector,tsquery)', amopmethod => 'gin' }, + +# btree tsquery_ops +{ amopfamily => 'btree/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '1', + amopopr => '<(tsquery,tsquery)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '2', + amopopr => '<=(tsquery,tsquery)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '3', + amopopr => '=(tsquery,tsquery)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '4', + amopopr => '>=(tsquery,tsquery)', amopmethod => 'btree' }, +{ amopfamily => 'btree/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '5', + amopopr => '>(tsquery,tsquery)', amopmethod => 'btree' }, + +# GiST tsquery_ops +{ amopfamily => 'gist/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '7', + amopopr => '@>(tsquery,tsquery)', amopmethod => 'gist' }, +{ amopfamily => 'gist/tsquery_ops', amoplefttype => 'tsquery', + amoprighttype => 'tsquery', amopstrategy => '8', + amopopr => '<@(tsquery,tsquery)', amopmethod => 'gist' }, + +# btree range_ops +{ amopfamily => 'btree/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<(anyrange,anyrange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '<=(anyrange,anyrange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '=(anyrange,anyrange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '>=(anyrange,anyrange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>(anyrange,anyrange)', amopmethod => 'btree' }, + +# hash range_ops +{ amopfamily => 'hash/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '=(anyrange,anyrange)', amopmethod => 'hash' }, + +# GiST range_ops +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<<(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '<<(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '&<(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '2', + amopopr => '&<(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '&&(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '3', + amopopr => '&&(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '&>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '4', + amopopr => '&>(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '5', + amopopr => '>>(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '6', + amopopr => '-|-(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '6', + amopopr => '-|-(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '7', + amopopr => '@>(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '7', + amopopr => '@>(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '8', + amopopr => '<@(anyrange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anymultirange', amopstrategy => '8', + amopopr => '<@(anyrange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyelement', amopstrategy => '16', + amopopr => '@>(anyrange,anyelement)', amopmethod => 'gist' }, +{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '18', + amopopr => '=(anyrange,anyrange)', amopmethod => 'gist' }, + +# GiST multirange_ops +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '<<(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<<(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '2', + amopopr => '&<(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '&<(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '3', + amopopr => '&&(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '&&(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '4', + amopopr => '&>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '&>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '5', + amopopr => '>>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '6', + amopopr => '-|-(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '6', + amopopr => '-|-(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '7', + amopopr => '@>(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '7', + amopopr => '@>(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '8', + amopopr => '<@(anymultirange,anymultirange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyrange', amopstrategy => '8', + amopopr => '<@(anymultirange,anyrange)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anyelement', amopstrategy => '16', + amopopr => '@>(anymultirange,anyelement)', amopmethod => 'gist' }, +{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '18', + amopopr => '=(anymultirange,anymultirange)', amopmethod => 'gist' }, + +# btree multirange_ops +{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '<(anymultirange,anymultirange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '2', + amopopr => '<=(anymultirange,anymultirange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '3', + amopopr => '=(anymultirange,anymultirange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '4', + amopopr => '>=(anymultirange,anymultirange)', amopmethod => 'btree' }, +{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '5', + amopopr => '>(anymultirange,anymultirange)', amopmethod => 'btree' }, + +# hash multirange_ops +{ amopfamily => 'hash/multirange_ops', amoplefttype => 'anymultirange', + amoprighttype => 'anymultirange', amopstrategy => '1', + amopopr => '=(anymultirange,anymultirange)', amopmethod => 'hash' }, + +# SP-GiST quad_point_ops +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '11', amopopr => '|>>(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '30', amopopr => '>^(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '1', amopopr => '<<(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '5', amopopr => '>>(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '10', amopopr => '<<|(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '29', amopopr => '<^(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '6', amopopr => '~=(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'box', amopstrategy => '8', amopopr => '<@(point,box)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(point,point)', amopmethod => 'spgist', + amopsortfamily => 'btree/float_ops' }, + +# SP-GiST kd_point_ops +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '11', amopopr => '|>>(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '30', amopopr => '>^(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '1', amopopr => '<<(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '5', amopopr => '>>(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '10', amopopr => '<<|(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '29', amopopr => '<^(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '6', amopopr => '~=(point,point)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'box', amopstrategy => '8', amopopr => '<@(point,box)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/kd_point_ops', amoplefttype => 'point', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(point,point)', amopmethod => 'spgist', + amopsortfamily => 'btree/float_ops' }, + +# SP-GiST text_ops +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '~<~(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '2', amopopr => '~<=~(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '3', amopopr => '=(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '4', amopopr => '~>=~(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '5', amopopr => '~>~(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '11', amopopr => '<(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '12', amopopr => '<=(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '14', amopopr => '>=(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '15', amopopr => '>(text,text)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/text_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '28', amopopr => '^@(text,text)', + amopmethod => 'spgist' }, + +# btree jsonb_ops +{ amopfamily => 'btree/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '1', amopopr => '<(jsonb,jsonb)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '2', amopopr => '<=(jsonb,jsonb)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '3', amopopr => '=(jsonb,jsonb)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '4', amopopr => '>=(jsonb,jsonb)', + amopmethod => 'btree' }, +{ amopfamily => 'btree/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '5', amopopr => '>(jsonb,jsonb)', + amopmethod => 'btree' }, + +# hash jsonb_ops +{ amopfamily => 'hash/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '1', amopopr => '=(jsonb,jsonb)', + amopmethod => 'hash' }, + +# GIN jsonb_ops +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '7', amopopr => '@>(jsonb,jsonb)', + amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'text', amopstrategy => '9', amopopr => '?(jsonb,text)', + amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => '_text', amopstrategy => '10', amopopr => '?|(jsonb,_text)', + amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => '_text', amopstrategy => '11', amopopr => '?&(jsonb,_text)', + amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonpath', amopstrategy => '15', + amopopr => '@?(jsonb,jsonpath)', amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonpath', amopstrategy => '16', + amopopr => '@@(jsonb,jsonpath)', amopmethod => 'gin' }, + +# GIN jsonb_path_ops +{ amopfamily => 'gin/jsonb_path_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonb', amopstrategy => '7', amopopr => '@>(jsonb,jsonb)', + amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_path_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonpath', amopstrategy => '15', + amopopr => '@?(jsonb,jsonpath)', amopmethod => 'gin' }, +{ amopfamily => 'gin/jsonb_path_ops', amoplefttype => 'jsonb', + amoprighttype => 'jsonpath', amopstrategy => '16', + amopopr => '@@(jsonb,jsonpath)', amopmethod => 'gin' }, + +# SP-GiST range_ops +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<<(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '&<(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '&&(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '&>(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>>(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '6', + amopopr => '-|-(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '7', + amopopr => '@>(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '8', + amopopr => '<@(anyrange,anyrange)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyelement', amopstrategy => '16', + amopopr => '@>(anyrange,anyelement)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/range_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '18', + amopopr => '=(anyrange,anyrange)', amopmethod => 'spgist' }, + +# SP-GiST box_ops +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '1', amopopr => '<<(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '2', amopopr => '&<(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '3', amopopr => '&&(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '4', amopopr => '&>(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '5', amopopr => '>>(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '6', amopopr => '~=(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '7', amopopr => '@>(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '8', amopopr => '<@(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '9', amopopr => '&<|(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '10', amopopr => '<<|(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '11', amopopr => '|>>(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', amoprighttype => 'box', + amopstrategy => '12', amopopr => '|&>(box,box)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/box_ops', amoplefttype => 'box', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(box,point)', amopmethod => 'spgist', + amopsortfamily => 'btree/float_ops' }, + +# SP-GiST poly_ops (supports polygons) +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '1', + amopopr => '<<(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '2', + amopopr => '&<(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '3', + amopopr => '&&(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '4', + amopopr => '&>(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '5', + amopopr => '>>(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '6', + amopopr => '~=(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '7', + amopopr => '@>(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '8', + amopopr => '<@(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '9', + amopopr => '&<|(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '10', + amopopr => '<<|(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '11', + amopopr => '|>>(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'polygon', amopstrategy => '12', + amopopr => '|&>(polygon,polygon)', amopmethod => 'spgist' }, +{ amopfamily => 'spgist/poly_ops', amoplefttype => 'polygon', + amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o', + amopopr => '<->(polygon,point)', amopmethod => 'spgist', + amopsortfamily => 'btree/float_ops' }, + +# GiST inet_ops +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '&&(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '18', amopopr => '=(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '19', amopopr => '<>(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '20', amopopr => '<(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '21', amopopr => '<=(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '22', amopopr => '>(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '23', amopopr => '>=(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '24', amopopr => '<<(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '25', amopopr => '<<=(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '26', amopopr => '>>(inet,inet)', + amopmethod => 'gist' }, +{ amopfamily => 'gist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '27', amopopr => '>>=(inet,inet)', + amopmethod => 'gist' }, + +# SP-GiST inet_ops +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '&&(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '18', amopopr => '=(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '19', amopopr => '<>(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '20', amopopr => '<(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '21', amopopr => '<=(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '22', amopopr => '>(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '23', amopopr => '>=(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '24', amopopr => '<<(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '25', amopopr => '<<=(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '26', amopopr => '>>(inet,inet)', + amopmethod => 'spgist' }, +{ amopfamily => 'spgist/network_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '27', amopopr => '>>=(inet,inet)', + amopmethod => 'spgist' }, + +# BRIN opclasses + +# minmax bytea +{ amopfamily => 'brin/bytea_minmax_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '1', amopopr => '<(bytea,bytea)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bytea_minmax_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '2', amopopr => '<=(bytea,bytea)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bytea_minmax_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '3', amopopr => '=(bytea,bytea)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bytea_minmax_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '4', amopopr => '>=(bytea,bytea)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bytea_minmax_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '5', amopopr => '>(bytea,bytea)', + amopmethod => 'brin' }, + +# bloom bytea +{ amopfamily => 'brin/bytea_bloom_ops', amoplefttype => 'bytea', + amoprighttype => 'bytea', amopstrategy => '1', amopopr => '=(bytea,bytea)', + amopmethod => 'brin' }, + +# minmax "char" +{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '1', amopopr => '<(char,char)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '2', amopopr => '<=(char,char)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '3', amopopr => '=(char,char)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '4', amopopr => '>=(char,char)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/char_minmax_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '5', amopopr => '>(char,char)', + amopmethod => 'brin' }, + +# bloom "char" +{ amopfamily => 'brin/char_bloom_ops', amoplefttype => 'char', + amoprighttype => 'char', amopstrategy => '1', amopopr => '=(char,char)', + amopmethod => 'brin' }, + +# minmax name +{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '1', amopopr => '<(name,name)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '2', amopopr => '<=(name,name)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '3', amopopr => '=(name,name)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '4', amopopr => '>=(name,name)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/name_minmax_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '5', amopopr => '>(name,name)', + amopmethod => 'brin' }, + +# bloom name +{ amopfamily => 'brin/name_bloom_ops', amoplefttype => 'name', + amoprighttype => 'name', amopstrategy => '1', amopopr => '=(name,name)', + amopmethod => 'brin' }, + +# minmax integer + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int8,int8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int8,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int8,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int2,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int2,int8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int2,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int4,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int4,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int4,int8)', + amopmethod => 'brin' }, + +# minmax multi integer + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int8,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int8,int8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int8,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int8,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int8,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int8', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int8,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int2,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int2,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int2,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int2,int8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int2,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int2', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int2,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '<(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '2', amopopr => '<=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '3', amopopr => '=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '4', amopopr => '>=(int4,int4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '5', amopopr => '>(int4,int4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '<(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '2', amopopr => '<=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '3', amopopr => '=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '4', amopopr => '>=(int4,int2)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int2', amopstrategy => '5', amopopr => '>(int4,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '<(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '2', amopopr => '<=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '3', amopopr => '=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '4', amopopr => '>=(int4,int8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/integer_minmax_multi_ops', amoplefttype => 'int4', + amoprighttype => 'int8', amopstrategy => '5', amopopr => '>(int4,int8)', + amopmethod => 'brin' }, + +# bloom integer + +{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int8', + amoprighttype => 'int8', amopstrategy => '1', amopopr => '=(int8,int8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int2', + amoprighttype => 'int2', amopstrategy => '1', amopopr => '=(int2,int2)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/integer_bloom_ops', amoplefttype => 'int4', + amoprighttype => 'int4', amopstrategy => '1', amopopr => '=(int4,int4)', + amopmethod => 'brin' }, + +# minmax text +{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '<(text,text)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '2', amopopr => '<=(text,text)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '3', amopopr => '=(text,text)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '4', amopopr => '>=(text,text)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/text_minmax_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '5', amopopr => '>(text,text)', + amopmethod => 'brin' }, + +# bloom text +{ amopfamily => 'brin/text_bloom_ops', amoplefttype => 'text', + amoprighttype => 'text', amopstrategy => '1', amopopr => '=(text,text)', + amopmethod => 'brin' }, + +# minmax oid +{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '1', amopopr => '<(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '2', amopopr => '<=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '3', amopopr => '=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '4', amopopr => '>=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '5', amopopr => '>(oid,oid)', + amopmethod => 'brin' }, + +# minmax multi oid +{ amopfamily => 'brin/oid_minmax_multi_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '1', amopopr => '<(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_multi_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '2', amopopr => '<=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_multi_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '3', amopopr => '=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_multi_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '4', amopopr => '>=(oid,oid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/oid_minmax_multi_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '5', amopopr => '>(oid,oid)', + amopmethod => 'brin' }, + +# bloom oid +{ amopfamily => 'brin/oid_bloom_ops', amoplefttype => 'oid', + amoprighttype => 'oid', amopstrategy => '1', amopopr => '=(oid,oid)', + amopmethod => 'brin' }, + +# minmax tid +{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '1', amopopr => '<(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '2', amopopr => '<=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '3', amopopr => '=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '4', amopopr => '>=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '5', amopopr => '>(tid,tid)', + amopmethod => 'brin' }, + +# tid oid +{ amopfamily => 'brin/tid_bloom_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '1', amopopr => '=(tid,tid)', + amopmethod => 'brin' }, +# minmax multi tid +{ amopfamily => 'brin/tid_minmax_multi_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '1', amopopr => '<(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_multi_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '2', amopopr => '<=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_multi_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '3', amopopr => '=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_multi_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '4', amopopr => '>=(tid,tid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/tid_minmax_multi_ops', amoplefttype => 'tid', + amoprighttype => 'tid', amopstrategy => '5', amopopr => '>(tid,tid)', + amopmethod => 'brin' }, + +# minmax float (float4, float8) + +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float4,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float4,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float4,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float4,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float4,float4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float4,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float4,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float4,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float4,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float4,float8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float8,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float8,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float8,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float8,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float8,float4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float8,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float8,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float8,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float8,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float8,float8)', + amopmethod => 'brin' }, + +# minmax multi float (float4, float8) + +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float4,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float4,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float4,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float4,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float4,float4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float4,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float4,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float4,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float4,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float4', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float4,float8)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '<(float8,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '2', + amopopr => '<=(float8,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '3', amopopr => '=(float8,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '4', + amopopr => '>=(float8,float4)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float4', amopstrategy => '5', amopopr => '>(float8,float4)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '<(float8,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '2', + amopopr => '<=(float8,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '3', amopopr => '=(float8,float8)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '4', + amopopr => '>=(float8,float8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/float_minmax_multi_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '5', amopopr => '>(float8,float8)', + amopmethod => 'brin' }, + +# bloom float +{ amopfamily => 'brin/float_bloom_ops', amoplefttype => 'float4', + amoprighttype => 'float4', amopstrategy => '1', amopopr => '=(float4,float4)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/float_bloom_ops', amoplefttype => 'float8', + amoprighttype => 'float8', amopstrategy => '1', amopopr => '=(float8,float8)', + amopmethod => 'brin' }, + +# minmax macaddr +{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '1', + amopopr => '<(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '2', + amopopr => '<=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '3', + amopopr => '=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '4', + amopopr => '>=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '5', + amopopr => '>(macaddr,macaddr)', amopmethod => 'brin' }, + +# minmax multi macaddr +{ amopfamily => 'brin/macaddr_minmax_multi_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '1', + amopopr => '<(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_multi_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '2', + amopopr => '<=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_multi_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '3', + amopopr => '=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_multi_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '4', + amopopr => '>=(macaddr,macaddr)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr_minmax_multi_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '5', + amopopr => '>(macaddr,macaddr)', amopmethod => 'brin' }, + +# bloom macaddr +{ amopfamily => 'brin/macaddr_bloom_ops', amoplefttype => 'macaddr', + amoprighttype => 'macaddr', amopstrategy => '1', + amopopr => '=(macaddr,macaddr)', amopmethod => 'brin' }, + +# minmax macaddr8 +{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '1', + amopopr => '<(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '2', + amopopr => '<=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '3', + amopopr => '=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '4', + amopopr => '>=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '5', + amopopr => '>(macaddr8,macaddr8)', amopmethod => 'brin' }, + +# minmax multi macaddr8 +{ amopfamily => 'brin/macaddr8_minmax_multi_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '1', + amopopr => '<(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_multi_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '2', + amopopr => '<=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_multi_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '3', + amopopr => '=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_multi_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '4', + amopopr => '>=(macaddr8,macaddr8)', amopmethod => 'brin' }, +{ amopfamily => 'brin/macaddr8_minmax_multi_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '5', + amopopr => '>(macaddr8,macaddr8)', amopmethod => 'brin' }, + +# bloom macaddr8 +{ amopfamily => 'brin/macaddr8_bloom_ops', amoplefttype => 'macaddr8', + amoprighttype => 'macaddr8', amopstrategy => '1', + amopopr => '=(macaddr8,macaddr8)', amopmethod => 'brin' }, + +# minmax inet +{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '1', amopopr => '<(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '2', amopopr => '<=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '4', amopopr => '>=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '5', amopopr => '>(inet,inet)', + amopmethod => 'brin' }, + +# minmax multi inet +{ amopfamily => 'brin/network_minmax_multi_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '1', amopopr => '<(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_multi_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '2', amopopr => '<=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_multi_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_multi_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '4', amopopr => '>=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_minmax_multi_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '5', amopopr => '>(inet,inet)', + amopmethod => 'brin' }, + +# bloom inet +{ amopfamily => 'brin/network_bloom_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '1', amopopr => '=(inet,inet)', + amopmethod => 'brin' }, + +# inclusion inet +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '3', amopopr => '&&(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '7', amopopr => '>>=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '8', amopopr => '<<=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '18', amopopr => '=(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '24', amopopr => '>>(inet,inet)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/network_inclusion_ops', amoplefttype => 'inet', + amoprighttype => 'inet', amopstrategy => '26', amopopr => '<<(inet,inet)', + amopmethod => 'brin' }, + +# minmax character +{ amopfamily => 'brin/bpchar_minmax_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '<(bpchar,bpchar)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bpchar_minmax_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '2', + amopopr => '<=(bpchar,bpchar)', amopmethod => 'brin' }, +{ amopfamily => 'brin/bpchar_minmax_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '3', amopopr => '=(bpchar,bpchar)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bpchar_minmax_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '4', + amopopr => '>=(bpchar,bpchar)', amopmethod => 'brin' }, +{ amopfamily => 'brin/bpchar_minmax_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '5', amopopr => '>(bpchar,bpchar)', + amopmethod => 'brin' }, + +# bloom character +{ amopfamily => 'brin/bpchar_bloom_ops', amoplefttype => 'bpchar', + amoprighttype => 'bpchar', amopstrategy => '1', amopopr => '=(bpchar,bpchar)', + amopmethod => 'brin' }, + +# minmax time without time zone +{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '1', amopopr => '<(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '2', amopopr => '<=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '3', amopopr => '=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '4', amopopr => '>=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '5', amopopr => '>(time,time)', + amopmethod => 'brin' }, + +# minmax multi time without time zone +{ amopfamily => 'brin/time_minmax_multi_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '1', amopopr => '<(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_multi_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '2', amopopr => '<=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_multi_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '3', amopopr => '=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_multi_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '4', amopopr => '>=(time,time)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/time_minmax_multi_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '5', amopopr => '>(time,time)', + amopmethod => 'brin' }, + +# bloom time without time zone +{ amopfamily => 'brin/time_bloom_ops', amoplefttype => 'time', + amoprighttype => 'time', amopstrategy => '1', amopopr => '=(time,time)', + amopmethod => 'brin' }, + +# minmax datetime (date, timestamp, timestamptz) + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamp,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(timestamp,date)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamp,timestamptz)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(date,date)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(date,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(date,timestamptz)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '1', + amopopr => '<(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '2', + amopopr => '<=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '3', + amopopr => '=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '4', + amopopr => '>=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '5', + amopopr => '>(timestamptz,date)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamptz,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamptz,timestamptz)', amopmethod => 'brin' }, + +# minmax multi datetime (date, timestamp, timestamptz) + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamp,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamp,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(timestamp,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(timestamp,date)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamp,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamp,timestamptz)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '1', amopopr => '<(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '2', amopopr => '<=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '3', amopopr => '=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '4', amopopr => '>=(date,date)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '5', amopopr => '>(date,date)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(date,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(date,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(date,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'date', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(date,timestamptz)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '1', + amopopr => '<(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '2', + amopopr => '<=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '3', + amopopr => '=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '4', + amopopr => '>=(timestamptz,date)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'date', amopstrategy => '5', + amopopr => '>(timestamptz,date)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '<(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '3', + amopopr => '=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamp)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamp', amopstrategy => '5', + amopopr => '>(timestamptz,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '<(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '2', + amopopr => '<=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '3', + amopopr => '=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '4', + amopopr => '>=(timestamptz,timestamptz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/datetime_minmax_multi_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '5', + amopopr => '>(timestamptz,timestamptz)', amopmethod => 'brin' }, + +# bloom datetime (date, timestamp, timestamptz) + +{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'timestamp', + amoprighttype => 'timestamp', amopstrategy => '1', + amopopr => '=(timestamp,timestamp)', amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'date', + amoprighttype => 'date', amopstrategy => '1', amopopr => '=(date,date)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/datetime_bloom_ops', amoplefttype => 'timestamptz', + amoprighttype => 'timestamptz', amopstrategy => '1', + amopopr => '=(timestamptz,timestamptz)', amopmethod => 'brin' }, + +# minmax interval +{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '1', + amopopr => '<(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '2', + amopopr => '<=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '3', + amopopr => '=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '4', + amopopr => '>=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '5', + amopopr => '>(interval,interval)', amopmethod => 'brin' }, + +# minmax multi interval +{ amopfamily => 'brin/interval_minmax_multi_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '1', + amopopr => '<(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_multi_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '2', + amopopr => '<=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_multi_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '3', + amopopr => '=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_multi_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '4', + amopopr => '>=(interval,interval)', amopmethod => 'brin' }, +{ amopfamily => 'brin/interval_minmax_multi_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '5', + amopopr => '>(interval,interval)', amopmethod => 'brin' }, + +# bloom interval +{ amopfamily => 'brin/interval_bloom_ops', amoplefttype => 'interval', + amoprighttype => 'interval', amopstrategy => '1', + amopopr => '=(interval,interval)', amopmethod => 'brin' }, + +# minmax time with time zone +{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '1', amopopr => '<(timetz,timetz)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '2', + amopopr => '<=(timetz,timetz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '3', amopopr => '=(timetz,timetz)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '4', + amopopr => '>=(timetz,timetz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '5', amopopr => '>(timetz,timetz)', + amopmethod => 'brin' }, + +# minmax multi time with time zone +{ amopfamily => 'brin/timetz_minmax_multi_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '1', amopopr => '<(timetz,timetz)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_multi_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '2', + amopopr => '<=(timetz,timetz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_multi_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '3', amopopr => '=(timetz,timetz)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_multi_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '4', + amopopr => '>=(timetz,timetz)', amopmethod => 'brin' }, +{ amopfamily => 'brin/timetz_minmax_multi_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '5', amopopr => '>(timetz,timetz)', + amopmethod => 'brin' }, + +# bloom time with time zone +{ amopfamily => 'brin/timetz_bloom_ops', amoplefttype => 'timetz', + amoprighttype => 'timetz', amopstrategy => '1', amopopr => '=(timetz,timetz)', + amopmethod => 'brin' }, + +# minmax bit +{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit', + amoprighttype => 'bit', amopstrategy => '1', amopopr => '<(bit,bit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit', + amoprighttype => 'bit', amopstrategy => '2', amopopr => '<=(bit,bit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit', + amoprighttype => 'bit', amopstrategy => '3', amopopr => '=(bit,bit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit', + amoprighttype => 'bit', amopstrategy => '4', amopopr => '>=(bit,bit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/bit_minmax_ops', amoplefttype => 'bit', + amoprighttype => 'bit', amopstrategy => '5', amopopr => '>(bit,bit)', + amopmethod => 'brin' }, + +# minmax bit varying +{ amopfamily => 'brin/varbit_minmax_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '1', amopopr => '<(varbit,varbit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/varbit_minmax_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '2', + amopopr => '<=(varbit,varbit)', amopmethod => 'brin' }, +{ amopfamily => 'brin/varbit_minmax_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '3', amopopr => '=(varbit,varbit)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/varbit_minmax_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '4', + amopopr => '>=(varbit,varbit)', amopmethod => 'brin' }, +{ amopfamily => 'brin/varbit_minmax_ops', amoplefttype => 'varbit', + amoprighttype => 'varbit', amopstrategy => '5', amopopr => '>(varbit,varbit)', + amopmethod => 'brin' }, + +# minmax numeric +{ amopfamily => 'brin/numeric_minmax_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '1', + amopopr => '<(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '2', + amopopr => '<=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '3', + amopopr => '=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '4', + amopopr => '>=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '5', + amopopr => '>(numeric,numeric)', amopmethod => 'brin' }, + +# minmax multi numeric +{ amopfamily => 'brin/numeric_minmax_multi_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '1', + amopopr => '<(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_multi_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '2', + amopopr => '<=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_multi_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '3', + amopopr => '=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_multi_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '4', + amopopr => '>=(numeric,numeric)', amopmethod => 'brin' }, +{ amopfamily => 'brin/numeric_minmax_multi_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '5', + amopopr => '>(numeric,numeric)', amopmethod => 'brin' }, + +# bloom numeric +{ amopfamily => 'brin/numeric_bloom_ops', amoplefttype => 'numeric', + amoprighttype => 'numeric', amopstrategy => '1', + amopopr => '=(numeric,numeric)', amopmethod => 'brin' }, + +# minmax uuid +{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '1', amopopr => '<(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '2', amopopr => '<=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '3', amopopr => '=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '4', amopopr => '>=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '5', amopopr => '>(uuid,uuid)', + amopmethod => 'brin' }, + +# minmax multi uuid +{ amopfamily => 'brin/uuid_minmax_multi_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '1', amopopr => '<(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_multi_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '2', amopopr => '<=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_multi_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '3', amopopr => '=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_multi_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '4', amopopr => '>=(uuid,uuid)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/uuid_minmax_multi_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '5', amopopr => '>(uuid,uuid)', + amopmethod => 'brin' }, + +# bloom uuid +{ amopfamily => 'brin/uuid_bloom_ops', amoplefttype => 'uuid', + amoprighttype => 'uuid', amopstrategy => '1', amopopr => '=(uuid,uuid)', + amopmethod => 'brin' }, + +# inclusion range types +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '1', + amopopr => '<<(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '2', + amopopr => '&<(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '3', + amopopr => '&&(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '4', + amopopr => '&>(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '5', + amopopr => '>>(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '7', + amopopr => '@>(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '8', + amopopr => '<@(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyelement', amopstrategy => '16', + amopopr => '@>(anyrange,anyelement)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '17', + amopopr => '-|-(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '18', + amopopr => '=(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '20', + amopopr => '<(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '21', + amopopr => '<=(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '22', + amopopr => '>(anyrange,anyrange)', amopmethod => 'brin' }, +{ amopfamily => 'brin/range_inclusion_ops', amoplefttype => 'anyrange', + amoprighttype => 'anyrange', amopstrategy => '23', + amopopr => '>=(anyrange,anyrange)', amopmethod => 'brin' }, + +# minmax pg_lsn +{ amopfamily => 'brin/pg_lsn_minmax_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '<(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '2', + amopopr => '<=(pg_lsn,pg_lsn)', amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '3', amopopr => '=(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '4', + amopopr => '>=(pg_lsn,pg_lsn)', amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '5', amopopr => '>(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, + +# minmax multi pg_lsn +{ amopfamily => 'brin/pg_lsn_minmax_multi_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '<(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_multi_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '2', + amopopr => '<=(pg_lsn,pg_lsn)', amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_multi_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '3', amopopr => '=(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_multi_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '4', + amopopr => '>=(pg_lsn,pg_lsn)', amopmethod => 'brin' }, +{ amopfamily => 'brin/pg_lsn_minmax_multi_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '5', amopopr => '>(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, + +# bloom pg_lsn +{ amopfamily => 'brin/pg_lsn_bloom_ops', amoplefttype => 'pg_lsn', + amoprighttype => 'pg_lsn', amopstrategy => '1', amopopr => '=(pg_lsn,pg_lsn)', + amopmethod => 'brin' }, + +# inclusion box +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '1', amopopr => '<<(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '2', amopopr => '&<(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '3', amopopr => '&&(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '4', amopopr => '&>(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '5', amopopr => '>>(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '6', amopopr => '~=(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '7', amopopr => '@>(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '8', amopopr => '<@(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '9', amopopr => '&<|(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '10', amopopr => '<<|(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '11', amopopr => '|>>(box,box)', + amopmethod => 'brin' }, +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'box', amopstrategy => '12', amopopr => '|&>(box,box)', + amopmethod => 'brin' }, + +{ amopfamily => 'brin/box_inclusion_ops', amoplefttype => 'box', + amoprighttype => 'point', amopstrategy => '7', amopopr => '@>(box,point)', + amopmethod => 'brin' }, + +] diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h new file mode 100644 index 0000000..6c714b6 --- /dev/null +++ b/src/include/catalog/pg_amop.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------- + * + * pg_amop.h + * definition of the "access method operator" system catalog (pg_amop) + * + * The amop table identifies the operators associated with each index operator + * family and operator class (classes are subsets of families). An associated + * operator can be either a search operator or an ordering operator, as + * identified by amoppurpose. + * + * The primary key for this table is <amopfamily, amoplefttype, amoprighttype, + * amopstrategy>. amoplefttype and amoprighttype are just copies of the + * operator's oprleft/oprright, ie its declared input data types. The + * "default" operators for a particular opclass within the family are those + * with amoplefttype = amoprighttype = opclass's opcintype. An opfamily may + * also contain other operators, typically cross-data-type operators. All the + * operators within a family are supposed to be compatible, in a way that is + * defined by each individual index AM. + * + * We also keep a unique index on <amopopr, amoppurpose, amopfamily>, so that + * we can use a syscache to quickly answer questions of the form "is this + * operator in this opfamily, and if so what are its semantics with respect to + * the family?" This implies that the same operator cannot be listed for + * multiple strategy numbers within a single opfamily, with the exception that + * it's possible to list it for both search and ordering purposes (with + * different strategy numbers for the two purposes). + * + * amopmethod is a copy of the owning opfamily's opfmethod field. This is an + * intentional denormalization of the catalogs to buy lookup speed. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_amop.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AMOP_H +#define PG_AMOP_H + +#include "catalog/genbki.h" +#include "catalog/pg_amop_d.h" + +/* ---------------- + * pg_amop definition. cpp turns this into + * typedef struct FormData_pg_amop + * ---------------- + */ +CATALOG(pg_amop,2602,AccessMethodOperatorRelationId) +{ + Oid oid; /* oid */ + + /* the index opfamily this entry is for */ + Oid amopfamily BKI_LOOKUP(pg_opfamily); + + /* operator's left input data type */ + Oid amoplefttype BKI_LOOKUP(pg_type); + + /* operator's right input data type */ + Oid amoprighttype BKI_LOOKUP(pg_type); + + /* operator strategy number */ + int16 amopstrategy; + + /* is operator for 's'earch or 'o'rdering? */ + char amoppurpose BKI_DEFAULT(s); + + /* the operator's pg_operator OID */ + Oid amopopr BKI_LOOKUP(pg_operator); + + /* the index access method this entry is for */ + Oid amopmethod BKI_LOOKUP(pg_am); + + /* ordering opfamily OID, or 0 if search op */ + Oid amopsortfamily BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_opfamily); +} FormData_pg_amop; + +/* ---------------- + * Form_pg_amop corresponds to a pointer to a tuple with + * the format of pg_amop relation. + * ---------------- + */ +typedef FormData_pg_amop *Form_pg_amop; + +DECLARE_UNIQUE_INDEX(pg_amop_fam_strat_index, 2653, AccessMethodStrategyIndexId, on pg_amop using btree(amopfamily oid_ops, amoplefttype oid_ops, amoprighttype oid_ops, amopstrategy int2_ops)); +DECLARE_UNIQUE_INDEX(pg_amop_opr_fam_index, 2654, AccessMethodOperatorIndexId, on pg_amop using btree(amopopr oid_ops, amoppurpose char_ops, amopfamily oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_amop_oid_index, 2756, AccessMethodOperatorOidIndexId, on pg_amop using btree(oid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* allowed values of amoppurpose: */ +#define AMOP_SEARCH 's' /* operator is for search */ +#define AMOP_ORDER 'o' /* operator is for ordering */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_AMOP_H */ diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat new file mode 100644 index 0000000..135caee --- /dev/null +++ b/src/include/catalog/pg_amproc.dat @@ -0,0 +1,1982 @@ +#---------------------------------------------------------------------- +# +# pg_amproc.dat +# Initial contents of the pg_amproc system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_amproc.dat +# +#---------------------------------------------------------------------- + +[ + +# btree +{ amprocfamily => 'btree/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '1', amproc => 'btarraycmp' }, +{ amprocfamily => 'btree/bit_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '1', amproc => 'bitcmp' }, +{ amprocfamily => 'btree/bit_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/bool_ops', amproclefttype => 'bool', + amprocrighttype => 'bool', amprocnum => '1', amproc => 'btboolcmp' }, +{ amprocfamily => 'btree/bool_ops', amproclefttype => 'bool', + amprocrighttype => 'bool', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/bpchar_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', amproc => 'bpcharcmp' }, +{ amprocfamily => 'btree/bpchar_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'bpchar_sortsupport' }, +{ amprocfamily => 'btree/bpchar_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '4', + amproc => 'btvarstrequalimage' }, +{ amprocfamily => 'btree/bytea_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '1', amproc => 'byteacmp' }, +{ amprocfamily => 'btree/bytea_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '2', amproc => 'bytea_sortsupport' }, +{ amprocfamily => 'btree/bytea_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/char_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '1', amproc => 'btcharcmp' }, +{ amprocfamily => 'btree/char_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '1', amproc => 'date_cmp' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '2', amproc => 'date_sortsupport' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'timestamp', amprocnum => '1', + amproc => 'date_cmp_timestamp' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'date_cmp_timestamptz' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '1', amproc => 'timestamp_cmp' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '2', + amproc => 'timestamp_sortsupport' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'date', amprocnum => '1', amproc => 'timestamp_cmp_date' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'timestamp_cmp_timestamptz' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'timestamptz_cmp' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '2', + amproc => 'timestamp_sortsupport' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '4', + amproc => 'btequalimage' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'date', amprocnum => '1', + amproc => 'timestamptz_cmp_date' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamp', amprocnum => '1', + amproc => 'timestamptz_cmp_timestamp' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'date', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(date,date,interval,bool,bool)' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamp', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(timestamp,timestamp,interval,bool,bool)' }, +{ amprocfamily => 'btree/datetime_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(timestamptz,timestamptz,interval,bool,bool)' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '1', amproc => 'btfloat4cmp' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '2', + amproc => 'btfloat4sortsupport' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float8', amprocnum => '1', amproc => 'btfloat48cmp' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '1', amproc => 'btfloat8cmp' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '2', + amproc => 'btfloat8sortsupport' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float4', amprocnum => '1', amproc => 'btfloat84cmp' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '3', + amproc => 'in_range(float8,float8,float8,bool,bool)' }, +{ amprocfamily => 'btree/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float8', amprocnum => '3', + amproc => 'in_range(float4,float4,float8,bool,bool)' }, +{ amprocfamily => 'btree/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', amproc => 'network_cmp' }, +{ amprocfamily => 'btree/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', + amproc => 'network_sortsupport' }, +{ amprocfamily => 'btree/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '1', amproc => 'btint2cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '2', amproc => 'btint2sortsupport' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int4', amprocnum => '1', amproc => 'btint24cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int8', amprocnum => '1', amproc => 'btint28cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'in_range(int2,int2,int8,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int4', amprocnum => '3', + amproc => 'in_range(int2,int2,int4,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '3', + amproc => 'in_range(int2,int2,int2,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '1', amproc => 'btint4cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '2', amproc => 'btint4sortsupport' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int8', amprocnum => '1', amproc => 'btint48cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int2', amprocnum => '1', amproc => 'btint42cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'in_range(int4,int4,int8,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '3', + amproc => 'in_range(int4,int4,int4,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int2', amprocnum => '3', + amproc => 'in_range(int4,int4,int2,bool,bool)' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '1', amproc => 'btint8cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '2', amproc => 'btint8sortsupport' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int4', amprocnum => '1', amproc => 'btint84cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int2', amprocnum => '1', amproc => 'btint82cmp' }, +{ amprocfamily => 'btree/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'in_range(int8,int8,int8,bool,bool)' }, +{ amprocfamily => 'btree/interval_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '1', amproc => 'interval_cmp' }, +{ amprocfamily => 'btree/interval_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(interval,interval,interval,bool,bool)' }, +{ amprocfamily => 'btree/macaddr_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '1', amproc => 'macaddr_cmp' }, +{ amprocfamily => 'btree/macaddr_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '2', + amproc => 'macaddr_sortsupport' }, +{ amprocfamily => 'btree/macaddr_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/numeric_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '1', amproc => 'numeric_cmp' }, +{ amprocfamily => 'btree/numeric_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '2', + amproc => 'numeric_sortsupport' }, +{ amprocfamily => 'btree/numeric_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '3', + amproc => 'in_range(numeric,numeric,numeric,bool,bool)' }, +{ amprocfamily => 'btree/oid_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '1', amproc => 'btoidcmp' }, +{ amprocfamily => 'btree/oid_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '2', amproc => 'btoidsortsupport' }, +{ amprocfamily => 'btree/oid_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/oidvector_ops', amproclefttype => 'oidvector', + amprocrighttype => 'oidvector', amprocnum => '1', + amproc => 'btoidvectorcmp' }, +{ amprocfamily => 'btree/oidvector_ops', amproclefttype => 'oidvector', + amprocrighttype => 'oidvector', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'bttextcmp' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', amproc => 'bttextsortsupport' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '4', amproc => 'btvarstrequalimage' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '1', amproc => 'btnamecmp' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '2', amproc => 'btnamesortsupport' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '4', amproc => 'btvarstrequalimage' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'name', + amprocrighttype => 'text', amprocnum => '1', amproc => 'btnametextcmp' }, +{ amprocfamily => 'btree/text_ops', amproclefttype => 'text', + amprocrighttype => 'name', amprocnum => '1', amproc => 'bttextnamecmp' }, +{ amprocfamily => 'btree/time_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '1', amproc => 'time_cmp' }, +{ amprocfamily => 'btree/time_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/time_ops', amproclefttype => 'time', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(time,time,interval,bool,bool)' }, +{ amprocfamily => 'btree/timetz_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '1', amproc => 'timetz_cmp' }, +{ amprocfamily => 'btree/timetz_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/timetz_ops', amproclefttype => 'timetz', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'in_range(timetz,timetz,interval,bool,bool)' }, +{ amprocfamily => 'btree/varbit_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '1', amproc => 'varbitcmp' }, +{ amprocfamily => 'btree/varbit_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/text_pattern_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'bttext_pattern_cmp' }, +{ amprocfamily => 'btree/text_pattern_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', + amproc => 'bttext_pattern_sortsupport' }, +{ amprocfamily => 'btree/text_pattern_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/bpchar_pattern_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', + amproc => 'btbpchar_pattern_cmp' }, +{ amprocfamily => 'btree/bpchar_pattern_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'btbpchar_pattern_sortsupport' }, +{ amprocfamily => 'btree/bpchar_pattern_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/money_ops', amproclefttype => 'money', + amprocrighttype => 'money', amprocnum => '1', amproc => 'cash_cmp' }, +{ amprocfamily => 'btree/money_ops', amproclefttype => 'money', + amprocrighttype => 'money', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/tid_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '1', amproc => 'bttidcmp' }, +{ amprocfamily => 'btree/tid_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/uuid_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '1', amproc => 'uuid_cmp' }, +{ amprocfamily => 'btree/uuid_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '2', amproc => 'uuid_sortsupport' }, +{ amprocfamily => 'btree/uuid_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/record_ops', amproclefttype => 'record', + amprocrighttype => 'record', amprocnum => '1', amproc => 'btrecordcmp' }, +{ amprocfamily => 'btree/record_image_ops', amproclefttype => 'record', + amprocrighttype => 'record', amprocnum => '1', amproc => 'btrecordimagecmp' }, +{ amprocfamily => 'btree/pg_lsn_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '1', amproc => 'pg_lsn_cmp' }, +{ amprocfamily => 'btree/pg_lsn_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/macaddr8_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '1', amproc => 'macaddr8_cmp' }, +{ amprocfamily => 'btree/macaddr8_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/enum_ops', amproclefttype => 'anyenum', + amprocrighttype => 'anyenum', amprocnum => '1', amproc => 'enum_cmp' }, +{ amprocfamily => 'btree/enum_ops', amproclefttype => 'anyenum', + amprocrighttype => 'anyenum', amprocnum => '4', amproc => 'btequalimage' }, +{ amprocfamily => 'btree/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '1', amproc => 'tsvector_cmp' }, +{ amprocfamily => 'btree/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '1', amproc => 'tsquery_cmp' }, +{ amprocfamily => 'btree/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '1', amproc => 'range_cmp' }, +{ amprocfamily => 'btree/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'multirange_cmp' }, +{ amprocfamily => 'btree/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'jsonb_cmp' }, +{ amprocfamily => 'btree/xid8_ops', amproclefttype => 'xid8', + amprocrighttype => 'xid8', amprocnum => '1', amproc => 'xid8cmp' }, +{ amprocfamily => 'btree/xid8_ops', amproclefttype => 'xid8', + amprocrighttype => 'xid8', amprocnum => '4', amproc => 'btequalimage' }, + +# hash +{ amprocfamily => 'hash/bpchar_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', amproc => 'hashbpchar' }, +{ amprocfamily => 'hash/bpchar_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'hashbpcharextended' }, +{ amprocfamily => 'hash/char_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '1', amproc => 'hashchar' }, +{ amprocfamily => 'hash/char_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '2', amproc => 'hashcharextended' }, +{ amprocfamily => 'hash/date_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '1', amproc => 'hashint4' }, +{ amprocfamily => 'hash/date_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '2', amproc => 'hashint4extended' }, +{ amprocfamily => 'hash/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '1', amproc => 'hash_array' }, +{ amprocfamily => 'hash/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '2', + amproc => 'hash_array_extended' }, +{ amprocfamily => 'hash/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '1', amproc => 'hashfloat4' }, +{ amprocfamily => 'hash/float_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '2', + amproc => 'hashfloat4extended' }, +{ amprocfamily => 'hash/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '1', amproc => 'hashfloat8' }, +{ amprocfamily => 'hash/float_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '2', + amproc => 'hashfloat8extended' }, +{ amprocfamily => 'hash/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', amproc => 'hashinet' }, +{ amprocfamily => 'hash/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', amproc => 'hashinetextended' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '1', amproc => 'hashint2' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '2', amproc => 'hashint2extended' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '1', amproc => 'hashint4' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '2', amproc => 'hashint4extended' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '1', amproc => 'hashint8' }, +{ amprocfamily => 'hash/integer_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '2', amproc => 'hashint8extended' }, +{ amprocfamily => 'hash/interval_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '1', amproc => 'interval_hash' }, +{ amprocfamily => 'hash/interval_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '2', + amproc => 'interval_hash_extended' }, +{ amprocfamily => 'hash/macaddr_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '1', amproc => 'hashmacaddr' }, +{ amprocfamily => 'hash/macaddr_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '2', + amproc => 'hashmacaddrextended' }, +{ amprocfamily => 'hash/oid_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '1', amproc => 'hashoid' }, +{ amprocfamily => 'hash/oid_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '2', amproc => 'hashoidextended' }, +{ amprocfamily => 'hash/oidvector_ops', amproclefttype => 'oidvector', + amprocrighttype => 'oidvector', amprocnum => '1', amproc => 'hashoidvector' }, +{ amprocfamily => 'hash/oidvector_ops', amproclefttype => 'oidvector', + amprocrighttype => 'oidvector', amprocnum => '2', + amproc => 'hashoidvectorextended' }, +{ amprocfamily => 'hash/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'hashtext' }, +{ amprocfamily => 'hash/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', amproc => 'hashtextextended' }, +{ amprocfamily => 'hash/text_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '1', amproc => 'hashname' }, +{ amprocfamily => 'hash/text_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '2', amproc => 'hashnameextended' }, +{ amprocfamily => 'hash/time_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '1', amproc => 'time_hash' }, +{ amprocfamily => 'hash/time_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '2', amproc => 'time_hash_extended' }, +{ amprocfamily => 'hash/numeric_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '1', amproc => 'hash_numeric' }, +{ amprocfamily => 'hash/numeric_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '2', + amproc => 'hash_numeric_extended' }, +{ amprocfamily => 'hash/timestamptz_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'timestamp_hash' }, +{ amprocfamily => 'hash/timestamptz_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '2', + amproc => 'timestamp_hash_extended' }, +{ amprocfamily => 'hash/timetz_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '1', amproc => 'timetz_hash' }, +{ amprocfamily => 'hash/timetz_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '2', + amproc => 'timetz_hash_extended' }, +{ amprocfamily => 'hash/timestamp_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '1', + amproc => 'timestamp_hash' }, +{ amprocfamily => 'hash/timestamp_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '2', + amproc => 'timestamp_hash_extended' }, +{ amprocfamily => 'hash/bool_ops', amproclefttype => 'bool', + amprocrighttype => 'bool', amprocnum => '1', amproc => 'hashchar' }, +{ amprocfamily => 'hash/bool_ops', amproclefttype => 'bool', + amprocrighttype => 'bool', amprocnum => '2', amproc => 'hashcharextended' }, +{ amprocfamily => 'hash/bytea_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '1', amproc => 'hashvarlena' }, +{ amprocfamily => 'hash/bytea_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '2', + amproc => 'hashvarlenaextended' }, +{ amprocfamily => 'hash/xid_ops', amproclefttype => 'xid', + amprocrighttype => 'xid', amprocnum => '1', amproc => 'hashint4' }, +{ amprocfamily => 'hash/xid_ops', amproclefttype => 'xid', + amprocrighttype => 'xid', amprocnum => '2', amproc => 'hashint4extended' }, +{ amprocfamily => 'hash/xid8_ops', amproclefttype => 'xid8', + amprocrighttype => 'xid8', amprocnum => '1', amproc => 'hashint8' }, +{ amprocfamily => 'hash/xid8_ops', amproclefttype => 'xid8', + amprocrighttype => 'xid8', amprocnum => '2', amproc => 'hashint8extended' }, +{ amprocfamily => 'hash/cid_ops', amproclefttype => 'cid', + amprocrighttype => 'cid', amprocnum => '1', amproc => 'hashint4' }, +{ amprocfamily => 'hash/cid_ops', amproclefttype => 'cid', + amprocrighttype => 'cid', amprocnum => '2', amproc => 'hashint4extended' }, +{ amprocfamily => 'hash/tid_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '1', amproc => 'hashtid' }, +{ amprocfamily => 'hash/tid_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '2', amproc => 'hashtidextended' }, +{ amprocfamily => 'hash/text_pattern_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'hashtext' }, +{ amprocfamily => 'hash/text_pattern_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', amproc => 'hashtextextended' }, +{ amprocfamily => 'hash/bpchar_pattern_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', amproc => 'hashbpchar' }, +{ amprocfamily => 'hash/bpchar_pattern_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'hashbpcharextended' }, +{ amprocfamily => 'hash/aclitem_ops', amproclefttype => 'aclitem', + amprocrighttype => 'aclitem', amprocnum => '1', amproc => 'hash_aclitem' }, +{ amprocfamily => 'hash/aclitem_ops', amproclefttype => 'aclitem', + amprocrighttype => 'aclitem', amprocnum => '2', + amproc => 'hash_aclitem_extended' }, +{ amprocfamily => 'hash/uuid_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '1', amproc => 'uuid_hash' }, +{ amprocfamily => 'hash/uuid_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '2', amproc => 'uuid_hash_extended' }, +{ amprocfamily => 'hash/record_ops', amproclefttype => 'record', + amprocrighttype => 'record', amprocnum => '1', amproc => 'hash_record' }, +{ amprocfamily => 'hash/record_ops', amproclefttype => 'record', + amprocrighttype => 'record', amprocnum => '2', + amproc => 'hash_record_extended' }, +{ amprocfamily => 'hash/pg_lsn_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '1', amproc => 'pg_lsn_hash' }, +{ amprocfamily => 'hash/pg_lsn_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '2', + amproc => 'pg_lsn_hash_extended' }, +{ amprocfamily => 'hash/macaddr8_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '1', amproc => 'hashmacaddr8' }, +{ amprocfamily => 'hash/macaddr8_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '2', + amproc => 'hashmacaddr8extended' }, +{ amprocfamily => 'hash/enum_ops', amproclefttype => 'anyenum', + amprocrighttype => 'anyenum', amprocnum => '1', amproc => 'hashenum' }, +{ amprocfamily => 'hash/enum_ops', amproclefttype => 'anyenum', + amprocrighttype => 'anyenum', amprocnum => '2', + amproc => 'hashenumextended' }, +{ amprocfamily => 'hash/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '1', amproc => 'hash_range' }, +{ amprocfamily => 'hash/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '2', + amproc => 'hash_range_extended' }, +{ amprocfamily => 'hash/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'hash_multirange' }, +{ amprocfamily => 'hash/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '2', + amproc => 'hash_multirange_extended' }, +{ amprocfamily => 'hash/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'jsonb_hash' }, +{ amprocfamily => 'hash/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '2', + amproc => 'jsonb_hash_extended' }, + +# gist +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '1', + amproc => 'gist_point_consistent' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '2', amproc => 'gist_box_union' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '3', + amproc => 'gist_point_compress' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '5', amproc => 'gist_box_penalty' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '6', + amproc => 'gist_box_picksplit' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '7', amproc => 'gist_box_same' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '8', + amproc => 'gist_point_distance' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '9', amproc => 'gist_point_fetch' }, +{ amprocfamily => 'gist/point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '11', + amproc => 'gist_point_sortsupport' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '1', amproc => 'gist_box_consistent' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '2', amproc => 'gist_box_union' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '5', amproc => 'gist_box_penalty' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '6', amproc => 'gist_box_picksplit' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '7', amproc => 'gist_box_same' }, +{ amprocfamily => 'gist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '8', amproc => 'gist_box_distance' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '1', + amproc => 'gist_poly_consistent' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '2', amproc => 'gist_box_union' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '3', + amproc => 'gist_poly_compress' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '5', + amproc => 'gist_box_penalty' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '6', + amproc => 'gist_box_picksplit' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '7', amproc => 'gist_box_same' }, +{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '8', + amproc => 'gist_poly_distance' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '1', + amproc => 'gist_circle_consistent' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '2', amproc => 'gist_box_union' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '3', + amproc => 'gist_circle_compress' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '5', amproc => 'gist_box_penalty' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '6', + amproc => 'gist_box_picksplit' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '7', amproc => 'gist_box_same' }, +{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle', + amprocrighttype => 'circle', amprocnum => '8', + amproc => 'gist_circle_distance' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '1', + amproc => 'gtsvector_consistent(internal,tsvector,int2,oid,internal)' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '2', + amproc => 'gtsvector_union' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '3', + amproc => 'gtsvector_compress' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '4', + amproc => 'gtsvector_decompress' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '5', + amproc => 'gtsvector_penalty' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '6', + amproc => 'gtsvector_picksplit' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '7', amproc => 'gtsvector_same' }, +{ amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '10', + amproc => 'gtsvector_options' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '1', + amproc => 'gtsquery_consistent(internal,tsquery,int2,oid,internal)' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '2', amproc => 'gtsquery_union' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '3', + amproc => 'gtsquery_compress' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '5', + amproc => 'gtsquery_penalty' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '6', + amproc => 'gtsquery_picksplit' }, +{ amprocfamily => 'gist/tsquery_ops', amproclefttype => 'tsquery', + amprocrighttype => 'tsquery', amprocnum => '7', amproc => 'gtsquery_same' }, +{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '1', + amproc => 'range_gist_consistent' }, +{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '2', + amproc => 'range_gist_union' }, +{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '5', + amproc => 'range_gist_penalty' }, +{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '6', + amproc => 'range_gist_picksplit' }, +{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '7', + amproc => 'range_gist_same' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', + amproc => 'inet_gist_consistent' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', amproc => 'inet_gist_union' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', amproc => 'inet_gist_compress' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '5', amproc => 'inet_gist_penalty' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '6', + amproc => 'inet_gist_picksplit' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '7', amproc => 'inet_gist_same' }, +{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '9', amproc => 'inet_gist_fetch' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '1', + amproc => 'multirange_gist_consistent' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '2', + amproc => 'range_gist_union' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '3', + amproc => 'multirange_gist_compress' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '5', + amproc => 'range_gist_penalty' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '6', + amproc => 'range_gist_picksplit' }, +{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange', + amprocrighttype => 'anymultirange', amprocnum => '7', + amproc => 'range_gist_same' }, + +# gin +{ amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '2', + amproc => 'ginarrayextract(anyarray,internal,internal)' }, +{ amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '3', + amproc => 'ginqueryarrayextract' }, +{ amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '4', + amproc => 'ginarrayconsistent' }, +{ amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray', + amprocrighttype => 'anyarray', amprocnum => '6', + amproc => 'ginarraytriconsistent' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '1', + amproc => 'gin_cmp_tslexeme' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '2', + amproc => 'gin_extract_tsvector(tsvector,internal,internal)' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '3', + amproc => 'gin_extract_tsquery(tsvector,internal,int2,internal,internal,internal,internal)' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '4', + amproc => 'gin_tsquery_consistent(internal,int2,tsvector,int4,internal,internal,internal,internal)' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '5', amproc => 'gin_cmp_prefix' }, +{ amprocfamily => 'gin/tsvector_ops', amproclefttype => 'tsvector', + amprocrighttype => 'tsvector', amprocnum => '6', + amproc => 'gin_tsquery_triconsistent' }, +{ amprocfamily => 'gin/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'gin_compare_jsonb' }, +{ amprocfamily => 'gin/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '2', amproc => 'gin_extract_jsonb' }, +{ amprocfamily => 'gin/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '3', + amproc => 'gin_extract_jsonb_query' }, +{ amprocfamily => 'gin/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '4', + amproc => 'gin_consistent_jsonb' }, +{ amprocfamily => 'gin/jsonb_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '6', + amproc => 'gin_triconsistent_jsonb' }, +{ amprocfamily => 'gin/jsonb_path_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '1', amproc => 'btint4cmp' }, +{ amprocfamily => 'gin/jsonb_path_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '2', + amproc => 'gin_extract_jsonb_path' }, +{ amprocfamily => 'gin/jsonb_path_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '3', + amproc => 'gin_extract_jsonb_query_path' }, +{ amprocfamily => 'gin/jsonb_path_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '4', + amproc => 'gin_consistent_jsonb_path' }, +{ amprocfamily => 'gin/jsonb_path_ops', amproclefttype => 'jsonb', + amprocrighttype => 'jsonb', amprocnum => '6', + amproc => 'gin_triconsistent_jsonb_path' }, + +# sp-gist +{ amprocfamily => 'spgist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '1', + amproc => 'spg_range_quad_config' }, +{ amprocfamily => 'spgist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '2', + amproc => 'spg_range_quad_choose' }, +{ amprocfamily => 'spgist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '3', + amproc => 'spg_range_quad_picksplit' }, +{ amprocfamily => 'spgist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '4', + amproc => 'spg_range_quad_inner_consistent' }, +{ amprocfamily => 'spgist/range_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '5', + amproc => 'spg_range_quad_leaf_consistent' }, +{ amprocfamily => 'spgist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', amproc => 'inet_spg_config' }, +{ amprocfamily => 'spgist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', amproc => 'inet_spg_choose' }, +{ amprocfamily => 'spgist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', amproc => 'inet_spg_picksplit' }, +{ amprocfamily => 'spgist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', + amproc => 'inet_spg_inner_consistent' }, +{ amprocfamily => 'spgist/network_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '5', + amproc => 'inet_spg_leaf_consistent' }, +{ amprocfamily => 'spgist/quad_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '1', amproc => 'spg_quad_config' }, +{ amprocfamily => 'spgist/quad_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '2', amproc => 'spg_quad_choose' }, +{ amprocfamily => 'spgist/quad_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '3', + amproc => 'spg_quad_picksplit' }, +{ amprocfamily => 'spgist/quad_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '4', + amproc => 'spg_quad_inner_consistent' }, +{ amprocfamily => 'spgist/quad_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '5', + amproc => 'spg_quad_leaf_consistent' }, +{ amprocfamily => 'spgist/kd_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '1', amproc => 'spg_kd_config' }, +{ amprocfamily => 'spgist/kd_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '2', amproc => 'spg_kd_choose' }, +{ amprocfamily => 'spgist/kd_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '3', amproc => 'spg_kd_picksplit' }, +{ amprocfamily => 'spgist/kd_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '4', + amproc => 'spg_kd_inner_consistent' }, +{ amprocfamily => 'spgist/kd_point_ops', amproclefttype => 'point', + amprocrighttype => 'point', amprocnum => '5', + amproc => 'spg_quad_leaf_consistent' }, +{ amprocfamily => 'spgist/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'spg_text_config' }, +{ amprocfamily => 'spgist/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', amproc => 'spg_text_choose' }, +{ amprocfamily => 'spgist/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '3', amproc => 'spg_text_picksplit' }, +{ amprocfamily => 'spgist/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '4', + amproc => 'spg_text_inner_consistent' }, +{ amprocfamily => 'spgist/text_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '5', + amproc => 'spg_text_leaf_consistent' }, +{ amprocfamily => 'spgist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '1', amproc => 'spg_box_quad_config' }, +{ amprocfamily => 'spgist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '2', amproc => 'spg_box_quad_choose' }, +{ amprocfamily => 'spgist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '3', + amproc => 'spg_box_quad_picksplit' }, +{ amprocfamily => 'spgist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '4', + amproc => 'spg_box_quad_inner_consistent' }, +{ amprocfamily => 'spgist/box_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '5', + amproc => 'spg_box_quad_leaf_consistent' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '1', + amproc => 'spg_bbox_quad_config' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '2', + amproc => 'spg_box_quad_choose' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '3', + amproc => 'spg_box_quad_picksplit' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '4', + amproc => 'spg_box_quad_inner_consistent' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '5', + amproc => 'spg_box_quad_leaf_consistent' }, +{ amprocfamily => 'spgist/poly_ops', amproclefttype => 'polygon', + amprocrighttype => 'polygon', amprocnum => '6', + amproc => 'spg_poly_quad_compress' }, + +# BRIN opclasses + +# minmax bytea +{ amprocfamily => 'brin/bytea_minmax_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/bytea_minmax_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/bytea_minmax_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/bytea_minmax_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# bloom bytea +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/bytea_bloom_ops', amproclefttype => 'bytea', + amprocrighttype => 'bytea', amprocnum => '11', amproc => 'hashvarlena' }, + +# minmax "char" +{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/char_minmax_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# bloom "char" +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/char_bloom_ops', amproclefttype => 'char', + amprocrighttype => 'char', amprocnum => '11', amproc => 'hashchar' }, + +# minmax name +{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/name_minmax_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# bloom name +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/name_bloom_ops', amproclefttype => 'name', + amprocrighttype => 'name', amprocnum => '11', amproc => 'hashname' }, + +# minmax integer: int2, int4, int8 +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '4', amproc => 'brin_minmax_union' }, + +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '4', amproc => 'brin_minmax_union' }, + +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/integer_minmax_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi integer: int2, int4, int8 +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_int2' }, + +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_int4' }, + +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/integer_minmax_multi_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_int8' }, + +# bloom integer: int2, int4, int8 +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int8', + amprocrighttype => 'int8', amprocnum => '11', amproc => 'hashint8' }, + +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int2', + amprocrighttype => 'int2', amprocnum => '11', amproc => 'hashint2' }, + +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/integer_bloom_ops', amproclefttype => 'int4', + amprocrighttype => 'int4', amprocnum => '11', amproc => 'hashint4' }, + +# minmax text +{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/text_minmax_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# bloom text +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/text_bloom_ops', amproclefttype => 'text', + amprocrighttype => 'text', amprocnum => '11', amproc => 'hashtext' }, + +# minmax oid +{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '1', amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/oid_minmax_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi oid +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/oid_minmax_multi_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_int4' }, + +# bloom oid +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/oid_bloom_ops', amproclefttype => 'oid', + amprocrighttype => 'oid', amprocnum => '11', amproc => 'hashoid' }, + +# minmax tid +{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '1', amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/tid_minmax_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# bloom tid +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/tid_bloom_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '11', amproc => 'hashtid' }, + +# minmax multi tid +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/tid_minmax_multi_ops', amproclefttype => 'tid', + amprocrighttype => 'tid', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_tid' }, + +# minmax float +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/float_minmax_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi float +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_float4' }, + +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/float_minmax_multi_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_float8' }, + +# bloom float +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float4', + amprocrighttype => 'float4', amprocnum => '11', amproc => 'hashfloat4' }, + +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/float_bloom_ops', amproclefttype => 'float8', + amprocrighttype => 'float8', amprocnum => '11', amproc => 'hashfloat8' }, + +# minmax macaddr +{ amprocfamily => 'brin/macaddr_minmax_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/macaddr_minmax_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/macaddr_minmax_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/macaddr_minmax_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi macaddr +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/macaddr_minmax_multi_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_macaddr' }, + +# bloom macaddr +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/macaddr_bloom_ops', amproclefttype => 'macaddr', + amprocrighttype => 'macaddr', amprocnum => '11', amproc => 'hashmacaddr' }, + +# minmax macaddr8 +{ amprocfamily => 'brin/macaddr8_minmax_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/macaddr8_minmax_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/macaddr8_minmax_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/macaddr8_minmax_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi macaddr8 +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/macaddr8_minmax_multi_ops', + amproclefttype => 'macaddr8', amprocrighttype => 'macaddr8', + amprocnum => '11', amproc => 'brin_minmax_multi_distance_macaddr8' }, + +# bloom macaddr8 +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/macaddr8_bloom_ops', amproclefttype => 'macaddr8', + amprocrighttype => 'macaddr8', amprocnum => '11', amproc => 'hashmacaddr8' }, + +# minmax inet +{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/network_minmax_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi inet +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/network_minmax_multi_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_inet' }, + +# bloom inet +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/network_bloom_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '11', amproc => 'hashinet' }, + +# inclusion inet +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '1', + amproc => 'brin_inclusion_opcinfo' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '2', + amproc => 'brin_inclusion_add_value' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '3', + amproc => 'brin_inclusion_consistent' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '4', + amproc => 'brin_inclusion_union' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '11', amproc => 'inet_merge' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '12', amproc => 'inet_same_family' }, +{ amprocfamily => 'brin/network_inclusion_ops', amproclefttype => 'inet', + amprocrighttype => 'inet', amprocnum => '13', amproc => 'network_supeq' }, + +# minmax character +{ amprocfamily => 'brin/bpchar_minmax_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/bpchar_minmax_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/bpchar_minmax_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/bpchar_minmax_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# bloom character +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/bpchar_bloom_ops', amproclefttype => 'bpchar', + amprocrighttype => 'bpchar', amprocnum => '11', amproc => 'hashbpchar' }, + +# minmax time without time zone +{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/time_minmax_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi time without time zone +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/time_minmax_multi_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_time' }, + +# bloom time without time zone +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/time_bloom_ops', amproclefttype => 'time', + amprocrighttype => 'time', amprocnum => '11', amproc => 'time_hash' }, + +# minmax datetime (date, timestamp, timestamptz) +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi datetime (date, timestamp, timestamptz) +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '1', amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '2', amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '3', amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '4', amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '5', amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamp', amprocrighttype => 'timestamp', + amprocnum => '11', amproc => 'brin_minmax_multi_distance_timestamp' }, + +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '1', amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '2', amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '3', amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '4', amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '5', amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', + amproclefttype => 'timestamptz', amprocrighttype => 'timestamptz', + amprocnum => '11', amproc => 'brin_minmax_multi_distance_timestamp' }, + +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/datetime_minmax_multi_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_date' }, + +# bloom datetime (date, timestamp, timestamptz) +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamp', + amprocrighttype => 'timestamp', amprocnum => '11', + amproc => 'timestamp_hash' }, + +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'timestamptz', + amprocrighttype => 'timestamptz', amprocnum => '11', + amproc => 'timestamp_hash' }, + +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/datetime_bloom_ops', amproclefttype => 'date', + amprocrighttype => 'date', amprocnum => '11', amproc => 'hashint4' }, + +# minmax interval +{ amprocfamily => 'brin/interval_minmax_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/interval_minmax_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/interval_minmax_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/interval_minmax_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi interval +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/interval_minmax_multi_ops', + amproclefttype => 'interval', amprocrighttype => 'interval', + amprocnum => '11', amproc => 'brin_minmax_multi_distance_interval' }, + +# bloom interval +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/interval_bloom_ops', amproclefttype => 'interval', + amprocrighttype => 'interval', amprocnum => '11', amproc => 'interval_hash' }, + +# minmax time with time zone +{ amprocfamily => 'brin/timetz_minmax_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/timetz_minmax_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/timetz_minmax_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/timetz_minmax_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi time with time zone +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/timetz_minmax_multi_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_timetz' }, + +# bloom time with time zone +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/timetz_bloom_ops', amproclefttype => 'timetz', + amprocrighttype => 'timetz', amprocnum => '11', amproc => 'timetz_hash' }, + +# minmax bit +{ amprocfamily => 'brin/bit_minmax_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '1', amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/bit_minmax_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/bit_minmax_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/bit_minmax_ops', amproclefttype => 'bit', + amprocrighttype => 'bit', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax bit varying +{ amprocfamily => 'brin/varbit_minmax_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/varbit_minmax_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/varbit_minmax_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/varbit_minmax_ops', amproclefttype => 'varbit', + amprocrighttype => 'varbit', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax numeric +{ amprocfamily => 'brin/numeric_minmax_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/numeric_minmax_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/numeric_minmax_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/numeric_minmax_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi numeric +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/numeric_minmax_multi_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_numeric' }, + +# bloom numeric +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '4', + amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/numeric_bloom_ops', amproclefttype => 'numeric', + amprocrighttype => 'numeric', amprocnum => '11', amproc => 'hash_numeric' }, + +# minmax uuid +{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/uuid_minmax_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '4', amproc => 'brin_minmax_union' }, + +# minmax multi uuid +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/uuid_minmax_multi_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_uuid' }, + +# bloom uuid +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '1', amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '5', amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/uuid_bloom_ops', amproclefttype => 'uuid', + amprocrighttype => 'uuid', amprocnum => '11', amproc => 'uuid_hash' }, + +# inclusion range types +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '1', + amproc => 'brin_inclusion_opcinfo' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '2', + amproc => 'brin_inclusion_add_value' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '3', + amproc => 'brin_inclusion_consistent' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '4', + amproc => 'brin_inclusion_union' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '11', + amproc => 'range_merge(anyrange,anyrange)' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '13', + amproc => 'range_contains' }, +{ amprocfamily => 'brin/range_inclusion_ops', amproclefttype => 'anyrange', + amprocrighttype => 'anyrange', amprocnum => '14', + amproc => 'isempty(anyrange)' }, + +# minmax pg_lsn +{ amprocfamily => 'brin/pg_lsn_minmax_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '1', + amproc => 'brin_minmax_opcinfo' }, +{ amprocfamily => 'brin/pg_lsn_minmax_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '2', + amproc => 'brin_minmax_add_value' }, +{ amprocfamily => 'brin/pg_lsn_minmax_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '3', + amproc => 'brin_minmax_consistent' }, +{ amprocfamily => 'brin/pg_lsn_minmax_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '4', + amproc => 'brin_minmax_union' }, + +# minmax multi pg_lsn +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '1', + amproc => 'brin_minmax_multi_opcinfo' }, +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '2', + amproc => 'brin_minmax_multi_add_value' }, +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '3', + amproc => 'brin_minmax_multi_consistent' }, +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '4', + amproc => 'brin_minmax_multi_union' }, +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '5', + amproc => 'brin_minmax_multi_options' }, +{ amprocfamily => 'brin/pg_lsn_minmax_multi_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '11', + amproc => 'brin_minmax_multi_distance_pg_lsn' }, + +# bloom pg_lsn +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '1', + amproc => 'brin_bloom_opcinfo' }, +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '2', + amproc => 'brin_bloom_add_value' }, +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '3', + amproc => 'brin_bloom_consistent' }, +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '4', amproc => 'brin_bloom_union' }, +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '5', + amproc => 'brin_bloom_options' }, +{ amprocfamily => 'brin/pg_lsn_bloom_ops', amproclefttype => 'pg_lsn', + amprocrighttype => 'pg_lsn', amprocnum => '11', amproc => 'pg_lsn_hash' }, + +# inclusion box +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '1', + amproc => 'brin_inclusion_opcinfo' }, +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '2', + amproc => 'brin_inclusion_add_value' }, +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '3', + amproc => 'brin_inclusion_consistent' }, +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '4', + amproc => 'brin_inclusion_union' }, +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '11', amproc => 'bound_box' }, +{ amprocfamily => 'brin/box_inclusion_ops', amproclefttype => 'box', + amprocrighttype => 'box', amprocnum => '13', amproc => 'box_contain' }, + +] diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h new file mode 100644 index 0000000..f529fc6 --- /dev/null +++ b/src/include/catalog/pg_amproc.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * pg_amproc.h + * definition of the "access method procedure" system catalog (pg_amproc) + * + * The amproc table identifies support procedures associated with index + * operator families and classes. These procedures can't be listed in pg_amop + * since they are not the implementation of any indexable operator. + * + * The primary key for this table is <amprocfamily, amproclefttype, + * amprocrighttype, amprocnum>. The "default" support functions for a + * particular opclass within the family are those with amproclefttype = + * amprocrighttype = opclass's opcintype. These are the ones loaded into the + * relcache for an index and typically used for internal index operations. + * Other support functions are typically used to handle cross-type indexable + * operators with oprleft/oprright matching the entry's amproclefttype and + * amprocrighttype. The exact behavior depends on the index AM, however, and + * some don't pay attention to non-default functions at all. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_amproc.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AMPROC_H +#define PG_AMPROC_H + +#include "catalog/genbki.h" +#include "catalog/pg_amproc_d.h" + +/* ---------------- + * pg_amproc definition. cpp turns this into + * typedef struct FormData_pg_amproc + * ---------------- + */ +CATALOG(pg_amproc,2603,AccessMethodProcedureRelationId) +{ + Oid oid; /* oid */ + + /* the index opfamily this entry is for */ + Oid amprocfamily BKI_LOOKUP(pg_opfamily); + + /* procedure's left input data type */ + Oid amproclefttype BKI_LOOKUP(pg_type); + + /* procedure's right input data type */ + Oid amprocrighttype BKI_LOOKUP(pg_type); + + /* support procedure index */ + int16 amprocnum; + + /* OID of the proc */ + regproc amproc BKI_LOOKUP(pg_proc); +} FormData_pg_amproc; + +/* ---------------- + * Form_pg_amproc corresponds to a pointer to a tuple with + * the format of pg_amproc relation. + * ---------------- + */ +typedef FormData_pg_amproc *Form_pg_amproc; + +DECLARE_UNIQUE_INDEX(pg_amproc_fam_proc_index, 2655, AccessMethodProcedureIndexId, on pg_amproc using btree(amprocfamily oid_ops, amproclefttype oid_ops, amprocrighttype oid_ops, amprocnum int2_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_amproc_oid_index, 2757, AccessMethodProcedureOidIndexId, on pg_amproc using btree(oid oid_ops)); + +#endif /* PG_AMPROC_H */ diff --git a/src/include/catalog/pg_attrdef.h b/src/include/catalog/pg_attrdef.h new file mode 100644 index 0000000..a21dd38 --- /dev/null +++ b/src/include/catalog/pg_attrdef.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- + * + * pg_attrdef.h + * definition of the "attribute defaults" system catalog (pg_attrdef) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_attrdef.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ATTRDEF_H +#define PG_ATTRDEF_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_attrdef_d.h" + +/* ---------------- + * pg_attrdef definition. cpp turns this into + * typedef struct FormData_pg_attrdef + * ---------------- + */ +CATALOG(pg_attrdef,2604,AttrDefaultRelationId) +{ + Oid oid; /* oid */ + + Oid adrelid BKI_LOOKUP(pg_class); /* OID of table containing + * attribute */ + int16 adnum; /* attnum of attribute */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + pg_node_tree adbin BKI_FORCE_NOT_NULL; /* nodeToString representation of + * default */ +#endif +} FormData_pg_attrdef; + +/* ---------------- + * Form_pg_attrdef corresponds to a pointer to a tuple with + * the format of pg_attrdef relation. + * ---------------- + */ +typedef FormData_pg_attrdef *Form_pg_attrdef; + +DECLARE_TOAST(pg_attrdef, 2830, 2831); + +DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index, 2656, AttrDefaultIndexId, on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_attrdef_oid_index, 2657, AttrDefaultOidIndexId, on pg_attrdef using btree(oid oid_ops)); + +DECLARE_FOREIGN_KEY((adrelid, adnum), pg_attribute, (attrelid, attnum)); + + +extern Oid StoreAttrDefault(Relation rel, AttrNumber attnum, + Node *expr, bool is_internal, + bool add_column_mode); +extern void RemoveAttrDefault(Oid relid, AttrNumber attnum, + DropBehavior behavior, + bool complain, bool internal); +extern void RemoveAttrDefaultById(Oid attrdefId); + +extern Oid GetAttrDefaultOid(Oid relid, AttrNumber attnum); +extern ObjectAddress GetAttrDefaultColumnAddress(Oid attrdefoid); + +#endif /* PG_ATTRDEF_H */ diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h new file mode 100644 index 0000000..053294c --- /dev/null +++ b/src/include/catalog/pg_attribute.h @@ -0,0 +1,221 @@ +/*------------------------------------------------------------------------- + * + * pg_attribute.h + * definition of the "attribute" system catalog (pg_attribute) + * + * The initial contents of pg_attribute are generated at compile time by + * genbki.pl, so there is no pg_attribute.dat file. Only "bootstrapped" + * relations need be included. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_attribute.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ATTRIBUTE_H +#define PG_ATTRIBUTE_H + +#include "catalog/genbki.h" +#include "catalog/pg_attribute_d.h" + +/* ---------------- + * pg_attribute definition. cpp turns this into + * typedef struct FormData_pg_attribute + * + * If you change the following, make sure you change the structs for + * system attributes in catalog/heap.c also. + * You may need to change catalog/genbki.pl as well. + * ---------------- + */ +CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,AttributeRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid attrelid BKI_LOOKUP(pg_class); /* OID of relation containing + * this attribute */ + NameData attname; /* name of attribute */ + + /* + * atttypid is the OID of the instance in Catalog Class pg_type that + * defines the data type of this attribute (e.g. int4). Information in + * that instance is redundant with the attlen, attbyval, and attalign + * attributes of this instance, so they had better match or Postgres will + * fail. In an entry for a dropped column, this field is set to zero + * since the pg_type entry may no longer exist; but we rely on attlen, + * attbyval, and attalign to still tell us how large the values in the + * table are. + */ + Oid atttypid BKI_LOOKUP_OPT(pg_type); + + /* + * attstattarget is the target number of statistics datapoints to collect + * during VACUUM ANALYZE of this column. A zero here indicates that we do + * not wish to collect any stats about this column. A "-1" here indicates + * that no value has been explicitly set for this column, so ANALYZE + * should use the default setting. + */ + int32 attstattarget BKI_DEFAULT(-1); + + /* + * attlen is a copy of the typlen field from pg_type for this attribute. + * See atttypid comments above. + */ + int16 attlen; + + /* + * attnum is the "attribute number" for the attribute: A value that + * uniquely identifies this attribute within its class. For user + * attributes, Attribute numbers are greater than 0 and not greater than + * the number of attributes in the class. I.e. if the Class pg_class says + * that Class XYZ has 10 attributes, then the user attribute numbers in + * Class pg_attribute must be 1-10. + * + * System attributes have attribute numbers less than 0 that are unique + * within the class, but not constrained to any particular range. + * + * Note that (attnum - 1) is often used as the index to an array. + */ + int16 attnum; + + /* + * attndims is the declared number of dimensions, if an array type, + * otherwise zero. + */ + int32 attndims; + + /* + * fastgetattr() uses attcacheoff to cache byte offsets of attributes in + * heap tuples. The value actually stored in pg_attribute (-1) indicates + * no cached value. But when we copy these tuples into a tuple + * descriptor, we may then update attcacheoff in the copies. This speeds + * up the attribute walking process. + */ + int32 attcacheoff BKI_DEFAULT(-1); + + /* + * atttypmod records type-specific data supplied at table creation time + * (for example, the max length of a varchar field). It is passed to + * type-specific input and output functions as the third argument. The + * value will generally be -1 for types that do not need typmod. + */ + int32 atttypmod BKI_DEFAULT(-1); + + /* + * attbyval is a copy of the typbyval field from pg_type for this + * attribute. See atttypid comments above. + */ + bool attbyval; + + /* + * attalign is a copy of the typalign field from pg_type for this + * attribute. See atttypid comments above. + */ + char attalign; + + /*---------- + * attstorage tells for VARLENA attributes, what the heap access + * methods can do to it if a given tuple doesn't fit into a page. + * Possible values are as for pg_type.typstorage (see TYPSTORAGE macros). + *---------- + */ + char attstorage; + + /* + * attcompression sets the current compression method of the attribute. + * Typically this is InvalidCompressionMethod ('\0') to specify use of the + * current default setting (see default_toast_compression). Otherwise, + * 'p' selects pglz compression, while 'l' selects LZ4 compression. + * However, this field is ignored whenever attstorage does not allow + * compression. + */ + char attcompression BKI_DEFAULT('\0'); + + /* This flag represents the "NOT NULL" constraint */ + bool attnotnull; + + /* Has DEFAULT value or not */ + bool atthasdef BKI_DEFAULT(f); + + /* Has a missing value or not */ + bool atthasmissing BKI_DEFAULT(f); + + /* One of the ATTRIBUTE_IDENTITY_* constants below, or '\0' */ + char attidentity BKI_DEFAULT('\0'); + + /* One of the ATTRIBUTE_GENERATED_* constants below, or '\0' */ + char attgenerated BKI_DEFAULT('\0'); + + /* Is dropped (ie, logically invisible) or not */ + bool attisdropped BKI_DEFAULT(f); + + /* + * This flag specifies whether this column has ever had a local + * definition. It is set for normal non-inherited columns, but also for + * columns that are inherited from parents if also explicitly listed in + * CREATE TABLE INHERITS. It is also set when inheritance is removed from + * a table with ALTER TABLE NO INHERIT. If the flag is set, the column is + * not dropped by a parent's DROP COLUMN even if this causes the column's + * attinhcount to become zero. + */ + bool attislocal BKI_DEFAULT(t); + + /* Number of times inherited from direct parent relation(s) */ + int32 attinhcount BKI_DEFAULT(0); + + /* attribute's collation, if any */ + Oid attcollation BKI_LOOKUP_OPT(pg_collation); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* NOTE: The following fields are not present in tuple descriptors. */ + + /* Column-level access permissions */ + aclitem attacl[1] BKI_DEFAULT(_null_); + + /* Column-level options */ + text attoptions[1] BKI_DEFAULT(_null_); + + /* Column-level FDW options */ + text attfdwoptions[1] BKI_DEFAULT(_null_); + + /* + * Missing value for added columns. This is a one element array which lets + * us store a value of the attribute type here. + */ + anyarray attmissingval BKI_DEFAULT(_null_); +#endif +} FormData_pg_attribute; + +/* + * ATTRIBUTE_FIXED_PART_SIZE is the size of the fixed-layout, + * guaranteed-not-null part of a pg_attribute row. This is in fact as much + * of the row as gets copied into tuple descriptors, so don't expect you + * can access the variable-length fields except in a real tuple! + */ +#define ATTRIBUTE_FIXED_PART_SIZE \ + (offsetof(FormData_pg_attribute,attcollation) + sizeof(Oid)) + +/* ---------------- + * Form_pg_attribute corresponds to a pointer to a tuple with + * the format of pg_attribute relation. + * ---------------- + */ +typedef FormData_pg_attribute *Form_pg_attribute; + +DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index, 2658, AttributeRelidNameIndexId, on pg_attribute using btree(attrelid oid_ops, attname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_attribute_relid_attnum_index, 2659, AttributeRelidNumIndexId, on pg_attribute using btree(attrelid oid_ops, attnum int2_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +#define ATTRIBUTE_IDENTITY_ALWAYS 'a' +#define ATTRIBUTE_IDENTITY_BY_DEFAULT 'd' + +#define ATTRIBUTE_GENERATED_STORED 's' + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_ATTRIBUTE_H */ diff --git a/src/include/catalog/pg_auth_members.h b/src/include/catalog/pg_auth_members.h new file mode 100644 index 0000000..1bc027f --- /dev/null +++ b/src/include/catalog/pg_auth_members.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * pg_auth_members.h + * definition of the "authorization identifier members" system catalog + * (pg_auth_members). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_auth_members.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AUTH_MEMBERS_H +#define PG_AUTH_MEMBERS_H + +#include "catalog/genbki.h" +#include "catalog/pg_auth_members_d.h" + +/* ---------------- + * pg_auth_members definition. cpp turns this into + * typedef struct FormData_pg_auth_members + * ---------------- + */ +CATALOG(pg_auth_members,1261,AuthMemRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2843,AuthMemRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid roleid BKI_LOOKUP(pg_authid); /* ID of a role */ + Oid member BKI_LOOKUP(pg_authid); /* ID of a member of that role */ + Oid grantor BKI_LOOKUP(pg_authid); /* who granted the membership */ + bool admin_option; /* granted with admin option? */ +} FormData_pg_auth_members; + +/* ---------------- + * Form_pg_auth_members corresponds to a pointer to a tuple with + * the format of pg_auth_members relation. + * ---------------- + */ +typedef FormData_pg_auth_members *Form_pg_auth_members; + +DECLARE_UNIQUE_INDEX_PKEY(pg_auth_members_role_member_index, 2694, AuthMemRoleMemIndexId, on pg_auth_members using btree(roleid oid_ops, member oid_ops)); +DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index, 2695, AuthMemMemRoleIndexId, on pg_auth_members using btree(member oid_ops, roleid oid_ops)); + +#endif /* PG_AUTH_MEMBERS_H */ diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat new file mode 100644 index 0000000..3343a69 --- /dev/null +++ b/src/include/catalog/pg_authid.dat @@ -0,0 +1,88 @@ +#---------------------------------------------------------------------- +# +# pg_authid.dat +# Initial contents of the pg_authid system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_authid.dat +# +#---------------------------------------------------------------------- + +[ + +# The C code typically refers to these roles using the #define symbols, +# so make sure every entry has an oid_symbol value. + +# The bootstrap superuser is named POSTGRES according to this data and +# according to BKI_DEFAULT entries in other catalogs. However, initdb +# will replace that at database initialization time. + +{ oid => '10', oid_symbol => 'BOOTSTRAP_SUPERUSERID', + rolname => 'POSTGRES', rolsuper => 't', rolinherit => 't', + rolcreaterole => 't', rolcreatedb => 't', rolcanlogin => 't', + rolreplication => 't', rolbypassrls => 't', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '6171', oid_symbol => 'ROLE_PG_DATABASE_OWNER', + rolname => 'pg_database_owner', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '6181', oid_symbol => 'ROLE_PG_READ_ALL_DATA', + rolname => 'pg_read_all_data', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '6182', oid_symbol => 'ROLE_PG_WRITE_ALL_DATA', + rolname => 'pg_write_all_data', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '3373', oid_symbol => 'ROLE_PG_MONITOR', + rolname => 'pg_monitor', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '3374', oid_symbol => 'ROLE_PG_READ_ALL_SETTINGS', + rolname => 'pg_read_all_settings', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '3375', oid_symbol => 'ROLE_PG_READ_ALL_STATS', + rolname => 'pg_read_all_stats', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '3377', oid_symbol => 'ROLE_PG_STAT_SCAN_TABLES', + rolname => 'pg_stat_scan_tables', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '4569', oid_symbol => 'ROLE_PG_READ_SERVER_FILES', + rolname => 'pg_read_server_files', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '4570', oid_symbol => 'ROLE_PG_WRITE_SERVER_FILES', + rolname => 'pg_write_server_files', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '4571', oid_symbol => 'ROLE_PG_EXECUTE_SERVER_PROGRAM', + rolname => 'pg_execute_server_program', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '4200', oid_symbol => 'ROLE_PG_SIGNAL_BACKEND', + rolname => 'pg_signal_backend', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, +{ oid => '4544', oid_symbol => 'ROLE_PG_CHECKPOINT', + rolname => 'pg_checkpoint', rolsuper => 'f', rolinherit => 't', + rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f', + rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1', + rolpassword => '_null_', rolvaliduntil => '_null_' }, + +] diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h new file mode 100644 index 0000000..3512601 --- /dev/null +++ b/src/include/catalog/pg_authid.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * pg_authid.h + * definition of the "authorization identifier" system catalog (pg_authid) + * + * pg_shadow and pg_group are now publicly accessible views on pg_authid. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_authid.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_AUTHID_H +#define PG_AUTHID_H + +#include "catalog/genbki.h" +#include "catalog/pg_authid_d.h" + +/* ---------------- + * pg_authid definition. cpp turns this into + * typedef struct FormData_pg_authid + * ---------------- + */ +CATALOG(pg_authid,1260,AuthIdRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842,AuthIdRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid; /* oid */ + NameData rolname; /* name of role */ + bool rolsuper; /* read this field via superuser() only! */ + bool rolinherit; /* inherit privileges from other roles? */ + bool rolcreaterole; /* allowed to create more roles? */ + bool rolcreatedb; /* allowed to create databases? */ + bool rolcanlogin; /* allowed to log in as session user? */ + bool rolreplication; /* role used for streaming replication */ + bool rolbypassrls; /* bypasses row-level security? */ + int32 rolconnlimit; /* max connections allowed (-1=no limit) */ + + /* remaining fields may be null; use heap_getattr to read them! */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text rolpassword; /* password, if any */ + timestamptz rolvaliduntil; /* password expiration time, if any */ +#endif +} FormData_pg_authid; + +/* ---------------- + * Form_pg_authid corresponds to a pointer to a tuple with + * the format of pg_authid relation. + * ---------------- + */ +typedef FormData_pg_authid *Form_pg_authid; + +DECLARE_TOAST_WITH_MACRO(pg_authid, 4175, 4176, PgAuthidToastTable, PgAuthidToastIndex); + +DECLARE_UNIQUE_INDEX(pg_authid_rolname_index, 2676, AuthIdRolnameIndexId, on pg_authid using btree(rolname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_authid_oid_index, 2677, AuthIdOidIndexId, on pg_authid using btree(oid oid_ops)); + +#endif /* PG_AUTHID_H */ diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat new file mode 100644 index 0000000..4471eb6 --- /dev/null +++ b/src/include/catalog/pg_cast.dat @@ -0,0 +1,549 @@ +#---------------------------------------------------------------------- +# +# pg_cast.dat +# Initial contents of the pg_cast system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_cast.dat +# +#---------------------------------------------------------------------- + +[ + +# Note: this table has OIDs, but we don't bother to assign them manually, +# since nothing needs to know the specific OID of any built-in cast. + +# Numeric category: implicit casts are allowed in the direction +# int2->int4->int8->numeric->float4->float8, while casts in the +# reverse direction are assignment-only. +{ castsource => 'int8', casttarget => 'int2', castfunc => 'int2(int8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'int8', casttarget => 'int4', castfunc => 'int4(int8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'int8', casttarget => 'float4', castfunc => 'float4(int8)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int8', casttarget => 'float8', castfunc => 'float8(int8)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int8', casttarget => 'numeric', castfunc => 'numeric(int8)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'int8', castfunc => 'int8(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'int4', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'float4', castfunc => 'float4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'float8', castfunc => 'float8(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'numeric', castfunc => 'numeric(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'int8', castfunc => 'int8(int4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'int2', castfunc => 'int2(int4)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'float4', castfunc => 'float4(int4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'float8', castfunc => 'float8(int4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'numeric', castfunc => 'numeric(int4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'float4', casttarget => 'int8', castfunc => 'int8(float4)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float4', casttarget => 'int2', castfunc => 'int2(float4)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float4', casttarget => 'int4', castfunc => 'int4(float4)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float4', casttarget => 'float8', castfunc => 'float8(float4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'float4', casttarget => 'numeric', + castfunc => 'numeric(float4)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float8', casttarget => 'int8', castfunc => 'int8(float8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float8', casttarget => 'int2', castfunc => 'int2(float8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float8', casttarget => 'int4', castfunc => 'int4(float8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float8', casttarget => 'float4', castfunc => 'float4(float8)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'float8', casttarget => 'numeric', + castfunc => 'numeric(float8)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'int8', castfunc => 'int8(numeric)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'int2', castfunc => 'int2(numeric)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'int4', castfunc => 'int4(numeric)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'float4', + castfunc => 'float4(numeric)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'float8', + castfunc => 'float8(numeric)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'money', casttarget => 'numeric', castfunc => 'numeric(money)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'money', castfunc => 'money(numeric)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'money', castfunc => 'money(int4)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'int8', casttarget => 'money', castfunc => 'money(int8)', + castcontext => 'a', castmethod => 'f' }, + +# Allow explicit coercions between int4 and bool +{ castsource => 'int4', casttarget => 'bool', castfunc => 'bool(int4)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'bool', casttarget => 'int4', castfunc => 'int4(bool)', + castcontext => 'e', castmethod => 'f' }, + +# Allow explicit coercions between xid8 and xid +{ castsource => 'xid8', casttarget => 'xid', castfunc => 'xid(xid8)', + castcontext => 'e', castmethod => 'f' }, + +# OID category: allow implicit conversion from any integral type (including +# int8, to support OID literals > 2G) to OID, as well as assignment coercion +# from OID to int4 or int8. Similarly for each OID-alias type. Also allow +# implicit coercions between OID and each OID-alias type, as well as +# regproc<->regprocedure and regoper<->regoperator. (Other coercions +# between alias types must pass through OID.) Lastly, there are implicit +# casts from text and varchar to regclass, which exist mainly to support +# legacy forms of nextval() and related functions. +{ castsource => 'int8', casttarget => 'oid', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'oid', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'oid', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regproc', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regproc', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regproc', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regproc', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regproc', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regproc', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regproc', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'regproc', casttarget => 'regprocedure', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regprocedure', casttarget => 'regproc', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regprocedure', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regprocedure', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regprocedure', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regprocedure', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regprocedure', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regprocedure', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regprocedure', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regoper', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regoper', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regoper', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regoper', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regoper', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regoper', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regoper', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'regoper', casttarget => 'regoperator', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regoperator', casttarget => 'regoper', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regoperator', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regoperator', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regoperator', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regoperator', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regoperator', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regoperator', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regoperator', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regclass', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regclass', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regclass', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regclass', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regclass', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regclass', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regclass', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regcollation', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regcollation', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regcollation', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regcollation', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regcollation', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regcollation', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regcollation', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regtype', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regtype', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regtype', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regtype', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regtype', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regtype', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regtype', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regconfig', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regconfig', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regconfig', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regconfig', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regconfig', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regconfig', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regconfig', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regdictionary', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regdictionary', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regdictionary', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regdictionary', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regdictionary', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regdictionary', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regdictionary', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'text', casttarget => 'regclass', castfunc => 'regclass', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'varchar', casttarget => 'regclass', castfunc => 'regclass', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'oid', casttarget => 'regrole', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regrole', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regrole', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regrole', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regrole', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regrole', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regrole', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regnamespace', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regnamespace', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regnamespace', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regnamespace', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regnamespace', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regnamespace', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regnamespace', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, + +# String category +{ castsource => 'text', casttarget => 'bpchar', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'text', casttarget => 'varchar', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'bpchar', casttarget => 'text', castfunc => 'text(bpchar)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'bpchar', casttarget => 'varchar', castfunc => 'text(bpchar)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'varchar', casttarget => 'text', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'varchar', casttarget => 'bpchar', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'char', casttarget => 'text', castfunc => 'text(char)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'char', casttarget => 'bpchar', castfunc => 'bpchar(char)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'char', casttarget => 'varchar', castfunc => 'text(char)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'name', casttarget => 'text', castfunc => 'text(name)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'name', casttarget => 'bpchar', castfunc => 'bpchar(name)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'name', casttarget => 'varchar', castfunc => 'varchar(name)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'text', casttarget => 'char', castfunc => 'char(text)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'bpchar', casttarget => 'char', castfunc => 'char(text)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'varchar', casttarget => 'char', castfunc => 'char(text)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'text', casttarget => 'name', castfunc => 'name(text)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'bpchar', casttarget => 'name', castfunc => 'name(bpchar)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'varchar', casttarget => 'name', castfunc => 'name(varchar)', + castcontext => 'i', castmethod => 'f' }, + +# Allow explicit coercions between int4 and "char" +{ castsource => 'char', casttarget => 'int4', castfunc => 'int4(char)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'char', castfunc => 'char(int4)', + castcontext => 'e', castmethod => 'f' }, + +# pg_node_tree can be coerced to, but not from, text +{ castsource => 'pg_node_tree', casttarget => 'text', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, + +# pg_ndistinct can be coerced to, but not from, bytea and text +{ castsource => 'pg_ndistinct', casttarget => 'bytea', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'pg_ndistinct', casttarget => 'text', castfunc => '0', + castcontext => 'i', castmethod => 'i' }, + +# pg_dependencies can be coerced to, but not from, bytea and text +{ castsource => 'pg_dependencies', casttarget => 'bytea', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'pg_dependencies', casttarget => 'text', castfunc => '0', + castcontext => 'i', castmethod => 'i' }, + +# pg_mcv_list can be coerced to, but not from, bytea and text +{ castsource => 'pg_mcv_list', casttarget => 'bytea', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'pg_mcv_list', casttarget => 'text', castfunc => '0', + castcontext => 'i', castmethod => 'i' }, + +# Datetime category +{ castsource => 'date', casttarget => 'timestamp', + castfunc => 'timestamp(date)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'date', casttarget => 'timestamptz', + castfunc => 'timestamptz(date)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'time', casttarget => 'interval', castfunc => 'interval(time)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'time', casttarget => 'timetz', castfunc => 'timetz(time)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'timestamp', casttarget => 'date', + castfunc => 'date(timestamp)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timestamp', casttarget => 'time', + castfunc => 'time(timestamp)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timestamp', casttarget => 'timestamptz', + castfunc => 'timestamptz(timestamp)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'timestamptz', casttarget => 'date', + castfunc => 'date(timestamptz)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timestamptz', casttarget => 'time', + castfunc => 'time(timestamptz)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timestamptz', casttarget => 'timestamp', + castfunc => 'timestamp(timestamptz)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timestamptz', casttarget => 'timetz', + castfunc => 'timetz(timestamptz)', castcontext => 'a', castmethod => 'f' }, +{ castsource => 'interval', casttarget => 'time', castfunc => 'time(interval)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'timetz', casttarget => 'time', castfunc => 'time(timetz)', + castcontext => 'a', castmethod => 'f' }, + +# Geometric category +{ castsource => 'point', casttarget => 'box', castfunc => 'box(point)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'lseg', casttarget => 'point', castfunc => 'point(lseg)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'path', casttarget => 'polygon', castfunc => 'polygon(path)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'box', casttarget => 'point', castfunc => 'point(box)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'box', casttarget => 'lseg', castfunc => 'lseg(box)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'box', casttarget => 'polygon', castfunc => 'polygon(box)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'box', casttarget => 'circle', castfunc => 'circle(box)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'polygon', casttarget => 'point', castfunc => 'point(polygon)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'polygon', casttarget => 'path', castfunc => 'path', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'polygon', casttarget => 'box', castfunc => 'box(polygon)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'polygon', casttarget => 'circle', + castfunc => 'circle(polygon)', castcontext => 'e', castmethod => 'f' }, +{ castsource => 'circle', casttarget => 'point', castfunc => 'point(circle)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'circle', casttarget => 'box', castfunc => 'box(circle)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'circle', casttarget => 'polygon', + castfunc => 'polygon(circle)', castcontext => 'e', castmethod => 'f' }, + +# MAC address category +{ castsource => 'macaddr', casttarget => 'macaddr8', castfunc => 'macaddr8', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'macaddr8', casttarget => 'macaddr', castfunc => 'macaddr', + castcontext => 'i', castmethod => 'f' }, + +# INET category +{ castsource => 'cidr', casttarget => 'inet', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'inet', casttarget => 'cidr', castfunc => 'cidr', + castcontext => 'a', castmethod => 'f' }, + +# BitString category +{ castsource => 'bit', casttarget => 'varbit', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'varbit', casttarget => 'bit', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, + +# Cross-category casts between bit and int4, int8 +{ castsource => 'int8', casttarget => 'bit', castfunc => 'bit(int8,int4)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'bit', castfunc => 'bit(int4,int4)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'bit', casttarget => 'int8', castfunc => 'int8(bit)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'bit', casttarget => 'int4', castfunc => 'int4(bit)', + castcontext => 'e', castmethod => 'f' }, + +# Cross-category casts to and from TEXT +# We need entries here only for a few specialized cases where the behavior +# of the cast function differs from the datatype's I/O functions. Otherwise, +# parse_coerce.c will generate CoerceViaIO operations without any prompting. +# Note that the castcontext values specified here should be no stronger than +# parse_coerce.c's automatic casts ('a' to text, 'e' from text) else odd +# behavior will ensue when the automatic cast is applied instead of the +# pg_cast entry! +{ castsource => 'cidr', casttarget => 'text', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'inet', casttarget => 'text', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'bool', casttarget => 'text', castfunc => 'text(bool)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'xml', casttarget => 'text', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'text', casttarget => 'xml', castfunc => 'xml', + castcontext => 'e', castmethod => 'f' }, + +# Cross-category casts to and from VARCHAR +# We support all the same casts as for TEXT. +{ castsource => 'cidr', casttarget => 'varchar', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'inet', casttarget => 'varchar', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'bool', casttarget => 'varchar', castfunc => 'text(bool)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'xml', casttarget => 'varchar', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'varchar', casttarget => 'xml', castfunc => 'xml', + castcontext => 'e', castmethod => 'f' }, + +# Cross-category casts to and from BPCHAR +# We support all the same casts as for TEXT. +{ castsource => 'cidr', casttarget => 'bpchar', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'inet', casttarget => 'bpchar', castfunc => 'text(inet)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'bool', casttarget => 'bpchar', castfunc => 'text(bool)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'xml', casttarget => 'bpchar', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, +{ castsource => 'bpchar', casttarget => 'xml', castfunc => 'xml', + castcontext => 'e', castmethod => 'f' }, + +# Length-coercion functions +{ castsource => 'bpchar', casttarget => 'bpchar', + castfunc => 'bpchar(bpchar,int4,bool)', castcontext => 'i', + castmethod => 'f' }, +{ castsource => 'varchar', casttarget => 'varchar', + castfunc => 'varchar(varchar,int4,bool)', castcontext => 'i', + castmethod => 'f' }, +{ castsource => 'time', casttarget => 'time', castfunc => 'time(time,int4)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'timestamp', casttarget => 'timestamp', + castfunc => 'timestamp(timestamp,int4)', castcontext => 'i', + castmethod => 'f' }, +{ castsource => 'timestamptz', casttarget => 'timestamptz', + castfunc => 'timestamptz(timestamptz,int4)', castcontext => 'i', + castmethod => 'f' }, +{ castsource => 'interval', casttarget => 'interval', + castfunc => 'interval(interval,int4)', castcontext => 'i', + castmethod => 'f' }, +{ castsource => 'timetz', casttarget => 'timetz', + castfunc => 'timetz(timetz,int4)', castcontext => 'i', castmethod => 'f' }, +{ castsource => 'bit', casttarget => 'bit', castfunc => 'bit(bit,int4,bool)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'varbit', casttarget => 'varbit', castfunc => 'varbit', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'numeric', casttarget => 'numeric', + castfunc => 'numeric(numeric,int4)', castcontext => 'i', castmethod => 'f' }, + +# json to/from jsonb +{ castsource => 'json', casttarget => 'jsonb', castfunc => '0', + castcontext => 'a', castmethod => 'i' }, +{ castsource => 'jsonb', casttarget => 'json', castfunc => '0', + castcontext => 'a', castmethod => 'i' }, + +# jsonb to numeric and bool types +{ castsource => 'jsonb', casttarget => 'bool', castfunc => 'bool(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'numeric', castfunc => 'numeric(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'int2', castfunc => 'int2(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'int4', castfunc => 'int4(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'int8', castfunc => 'int8(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'float4', castfunc => 'float4(jsonb)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'jsonb', casttarget => 'float8', castfunc => 'float8(jsonb)', + castcontext => 'e', castmethod => 'f' }, + +# range to multirange +{ castsource => 'int4range', casttarget => 'int4multirange', + castfunc => 'int4multirange(int4range)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'int8range', casttarget => 'int8multirange', + castfunc => 'int8multirange(int8range)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'numrange', casttarget => 'nummultirange', + castfunc => 'nummultirange(numrange)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'daterange', casttarget => 'datemultirange', + castfunc => 'datemultirange(daterange)', castcontext => 'e', + castmethod => 'f' }, +{ castsource => 'tsrange', casttarget => 'tsmultirange', + castfunc => 'tsmultirange(tsrange)', castcontext => 'e', castmethod => 'f' }, +{ castsource => 'tstzrange', casttarget => 'tstzmultirange', + castfunc => 'tstzmultirange(tstzrange)', castcontext => 'e', + castmethod => 'f' }, +] diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h new file mode 100644 index 0000000..3c15df0 --- /dev/null +++ b/src/include/catalog/pg_cast.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------- + * + * pg_cast.h + * definition of the "type casts" system catalog (pg_cast) + * + * As of Postgres 8.0, pg_cast describes not only type coercion functions + * but also length coercion functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_cast.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CAST_H +#define PG_CAST_H + +#include "catalog/dependency.h" +#include "catalog/genbki.h" +#include "catalog/pg_cast_d.h" + +/* ---------------- + * pg_cast definition. cpp turns this into + * typedef struct FormData_pg_cast + * ---------------- + */ +CATALOG(pg_cast,2605,CastRelationId) +{ + Oid oid; /* oid */ + + /* source datatype for cast */ + Oid castsource BKI_LOOKUP(pg_type); + + /* destination datatype for cast */ + Oid casttarget BKI_LOOKUP(pg_type); + + /* cast function; 0 = binary coercible */ + Oid castfunc BKI_LOOKUP_OPT(pg_proc); + + /* contexts in which cast can be used */ + char castcontext; + + /* cast method */ + char castmethod; +} FormData_pg_cast; + +/* ---------------- + * Form_pg_cast corresponds to a pointer to a tuple with + * the format of pg_cast relation. + * ---------------- + */ +typedef FormData_pg_cast *Form_pg_cast; + +DECLARE_UNIQUE_INDEX_PKEY(pg_cast_oid_index, 2660, CastOidIndexId, on pg_cast using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, CastSourceTargetIndexId, on pg_cast using btree(castsource oid_ops, casttarget oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * The allowable values for pg_cast.castcontext are specified by this enum. + * Since castcontext is stored as a "char", we use ASCII codes for human + * convenience in reading the table. Note that internally to the backend, + * these values are converted to the CoercionContext enum (see primnodes.h), + * which is defined to sort in a convenient order; the ASCII codes don't + * have to sort in any special order. + */ + +typedef enum CoercionCodes +{ + COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */ + COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */ + COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */ +} CoercionCodes; + +/* + * The allowable values for pg_cast.castmethod are specified by this enum. + * Since castmethod is stored as a "char", we use ASCII codes for human + * convenience in reading the table. + */ +typedef enum CoercionMethod +{ + COERCION_METHOD_FUNCTION = 'f', /* use a function */ + COERCION_METHOD_BINARY = 'b', /* types are binary-compatible */ + COERCION_METHOD_INOUT = 'i' /* use input/output functions */ +} CoercionMethod; + +#endif /* EXPOSE_TO_CLIENT_CODE */ + + +extern ObjectAddress CastCreate(Oid sourcetypeid, + Oid targettypeid, + Oid funcid, + char castcontext, + char castmethod, + DependencyType behavior); + +#endif /* PG_CAST_H */ diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat new file mode 100644 index 0000000..c2cd40d --- /dev/null +++ b/src/include/catalog/pg_class.dat @@ -0,0 +1,28 @@ +#---------------------------------------------------------------------- +# +# pg_class.dat +# Initial contents of the pg_class system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_class.dat +# +#---------------------------------------------------------------------- + +[ + +# Note: only bootstrap catalogs, ie those marked BKI_BOOTSTRAP, need to +# have entries here. Be sure that the OIDs listed here match those given in +# their CATALOG and BKI_ROWTYPE_OID macros. + +{ oid => '1247', + relname => 'pg_type', reltype => 'pg_type' }, +{ oid => '1249', + relname => 'pg_attribute', reltype => 'pg_attribute' }, +{ oid => '1255', + relname => 'pg_proc', reltype => 'pg_proc' }, +{ oid => '1259', + relname => 'pg_class', reltype => 'pg_class' }, + +] diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h new file mode 100644 index 0000000..e1f4eef --- /dev/null +++ b/src/include/catalog/pg_class.h @@ -0,0 +1,230 @@ +/*------------------------------------------------------------------------- + * + * pg_class.h + * definition of the "relation" system catalog (pg_class) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_class.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CLASS_H +#define PG_CLASS_H + +#include "catalog/genbki.h" +#include "catalog/pg_class_d.h" + +/* ---------------- + * pg_class definition. cpp turns this into + * typedef struct FormData_pg_class + * + * Note that the BKI_DEFAULT values below are only used for rows describing + * BKI_BOOTSTRAP catalogs, since only those rows appear in pg_class.dat. + * ---------------- + */ +CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + /* oid */ + Oid oid; + + /* class name */ + NameData relname; + + /* OID of namespace containing this class */ + Oid relnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* OID of entry in pg_type for relation's implicit row type, if any */ + Oid reltype BKI_LOOKUP_OPT(pg_type); + + /* OID of entry in pg_type for underlying composite type, if any */ + Oid reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* class owner */ + Oid relowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* access method; 0 if not a table / index */ + Oid relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am); + + /* identifier of physical storage file */ + /* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */ + Oid relfilenode BKI_DEFAULT(0); + + /* identifier of table space for relation (0 means default for database) */ + Oid reltablespace BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_tablespace); + + /* # of blocks (not always up-to-date) */ + int32 relpages BKI_DEFAULT(0); + + /* # of tuples (not always up-to-date; -1 means "unknown") */ + float4 reltuples BKI_DEFAULT(-1); + + /* # of all-visible blocks (not always up-to-date) */ + int32 relallvisible BKI_DEFAULT(0); + + /* OID of toast table; 0 if none */ + Oid reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); + + /* T if has (or has had) any indexes */ + bool relhasindex BKI_DEFAULT(f); + + /* T if shared across databases */ + bool relisshared BKI_DEFAULT(f); + + /* see RELPERSISTENCE_xxx constants below */ + char relpersistence BKI_DEFAULT(p); + + /* see RELKIND_xxx constants below */ + char relkind BKI_DEFAULT(r); + + /* number of user attributes */ + int16 relnatts BKI_DEFAULT(0); /* genbki.pl will fill this in */ + + /* + * Class pg_attribute must contain exactly "relnatts" user attributes + * (with attnums ranging from 1 to relnatts) for this class. It may also + * contain entries with negative attnums for system attributes. + */ + + /* # of CHECK constraints for class */ + int16 relchecks BKI_DEFAULT(0); + + /* has (or has had) any rules */ + bool relhasrules BKI_DEFAULT(f); + + /* has (or has had) any TRIGGERs */ + bool relhastriggers BKI_DEFAULT(f); + + /* has (or has had) child tables or indexes */ + bool relhassubclass BKI_DEFAULT(f); + + /* row security is enabled or not */ + bool relrowsecurity BKI_DEFAULT(f); + + /* row security forced for owners or not */ + bool relforcerowsecurity BKI_DEFAULT(f); + + /* matview currently holds query results */ + bool relispopulated BKI_DEFAULT(t); + + /* see REPLICA_IDENTITY_xxx constants */ + char relreplident BKI_DEFAULT(n); + + /* is relation a partition? */ + bool relispartition BKI_DEFAULT(f); + + /* link to original rel during table rewrite; otherwise 0 */ + Oid relrewrite BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); + + /* all Xids < this are frozen in this rel */ + TransactionId relfrozenxid BKI_DEFAULT(3); /* FirstNormalTransactionId */ + + /* all multixacts in this rel are >= this; it is really a MultiXactId */ + TransactionId relminmxid BKI_DEFAULT(1); /* FirstMultiXactId */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* NOTE: These fields are not present in a relcache entry's rd_rel field. */ + /* access permissions */ + aclitem relacl[1] BKI_DEFAULT(_null_); + + /* access-method-specific options */ + text reloptions[1] BKI_DEFAULT(_null_); + + /* partition bound node tree */ + pg_node_tree relpartbound BKI_DEFAULT(_null_); +#endif +} FormData_pg_class; + +/* Size of fixed part of pg_class tuples, not counting var-length fields */ +#define CLASS_TUPLE_SIZE \ + (offsetof(FormData_pg_class,relminmxid) + sizeof(TransactionId)) + +/* ---------------- + * Form_pg_class corresponds to a pointer to a tuple with + * the format of pg_class relation. + * ---------------- + */ +typedef FormData_pg_class *Form_pg_class; + +DECLARE_UNIQUE_INDEX_PKEY(pg_class_oid_index, 2662, ClassOidIndexId, on pg_class using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, ClassNameNspIndexId, on pg_class using btree(relname name_ops, relnamespace oid_ops)); +DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeIndexId, on pg_class using btree(reltablespace oid_ops, relfilenode oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +#define RELKIND_RELATION 'r' /* ordinary table */ +#define RELKIND_INDEX 'i' /* secondary index */ +#define RELKIND_SEQUENCE 'S' /* sequence object */ +#define RELKIND_TOASTVALUE 't' /* for out-of-line values */ +#define RELKIND_VIEW 'v' /* view */ +#define RELKIND_MATVIEW 'm' /* materialized view */ +#define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ +#define RELKIND_FOREIGN_TABLE 'f' /* foreign table */ +#define RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */ +#define RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */ + +#define RELPERSISTENCE_PERMANENT 'p' /* regular table */ +#define RELPERSISTENCE_UNLOGGED 'u' /* unlogged permanent table */ +#define RELPERSISTENCE_TEMP 't' /* temporary table */ + +/* default selection for replica identity (primary key or nothing) */ +#define REPLICA_IDENTITY_DEFAULT 'd' +/* no replica identity is logged for this relation */ +#define REPLICA_IDENTITY_NOTHING 'n' +/* all columns are logged as replica identity */ +#define REPLICA_IDENTITY_FULL 'f' +/* + * an explicitly chosen candidate key's columns are used as replica identity. + * Note this will still be set if the index has been dropped; in that case it + * has the same meaning as 'n'. + */ +#define REPLICA_IDENTITY_INDEX 'i' + +/* + * Relation kinds that have physical storage. These relations normally have + * relfilenode set to non-zero, but it can also be zero if the relation is + * mapped. + */ +#define RELKIND_HAS_STORAGE(relkind) \ + ((relkind) == RELKIND_RELATION || \ + (relkind) == RELKIND_INDEX || \ + (relkind) == RELKIND_SEQUENCE || \ + (relkind) == RELKIND_TOASTVALUE || \ + (relkind) == RELKIND_MATVIEW) + +#define RELKIND_HAS_PARTITIONS(relkind) \ + ((relkind) == RELKIND_PARTITIONED_TABLE || \ + (relkind) == RELKIND_PARTITIONED_INDEX) + +/* + * Relation kinds that support tablespaces: All relation kinds with storage + * support tablespaces, except that we don't support moving sequences around + * into different tablespaces. Partitioned tables and indexes don't have + * physical storage, but they have a tablespace settings so that their + * children can inherit it. + */ +#define RELKIND_HAS_TABLESPACE(relkind) \ + ((RELKIND_HAS_STORAGE(relkind) || RELKIND_HAS_PARTITIONS(relkind)) \ + && (relkind) != RELKIND_SEQUENCE) + +/* + * Relation kinds with a table access method (rd_tableam). Although sequences + * use the heap table AM, they are enough of a special case in most uses that + * they are not included here. + */ +#define RELKIND_HAS_TABLE_AM(relkind) \ + ((relkind) == RELKIND_RELATION || \ + (relkind) == RELKIND_TOASTVALUE || \ + (relkind) == RELKIND_MATVIEW) + +extern int errdetail_relkind_not_supported(char relkind); + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_CLASS_H */ diff --git a/src/include/catalog/pg_collation.dat b/src/include/catalog/pg_collation.dat new file mode 100644 index 0000000..f7470ea --- /dev/null +++ b/src/include/catalog/pg_collation.dat @@ -0,0 +1,27 @@ +#---------------------------------------------------------------------- +# +# pg_collation.dat +# Initial contents of the pg_collation system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_collation.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '100', oid_symbol => 'DEFAULT_COLLATION_OID', + descr => 'database\'s default collation', + collname => 'default', collprovider => 'd', collencoding => '-1' }, +{ oid => '950', oid_symbol => 'C_COLLATION_OID', + descr => 'standard C collation', + collname => 'C', collprovider => 'c', collencoding => '-1', + collcollate => 'C', collctype => 'C' }, +{ oid => '951', oid_symbol => 'POSIX_COLLATION_OID', + descr => 'standard POSIX collation', + collname => 'POSIX', collprovider => 'c', collencoding => '-1', + collcollate => 'POSIX', collctype => 'POSIX' }, + +] diff --git a/src/include/catalog/pg_collation.h b/src/include/catalog/pg_collation.h new file mode 100644 index 0000000..2190ccb --- /dev/null +++ b/src/include/catalog/pg_collation.h @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + * + * pg_collation.h + * definition of the "collation" system catalog (pg_collation) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_collation.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_COLLATION_H +#define PG_COLLATION_H + +#include "catalog/genbki.h" +#include "catalog/pg_collation_d.h" + +/* ---------------- + * pg_collation definition. cpp turns this into + * typedef struct FormData_pg_collation + * ---------------- + */ +CATALOG(pg_collation,3456,CollationRelationId) +{ + Oid oid; /* oid */ + NameData collname; /* collation name */ + + /* OID of namespace containing this collation */ + Oid collnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner of collation */ + Oid collowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + char collprovider; /* see constants below */ + bool collisdeterministic BKI_DEFAULT(t); + int32 collencoding; /* encoding for this collation; -1 = "all" */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text collcollate BKI_DEFAULT(_null_); /* LC_COLLATE setting */ + text collctype BKI_DEFAULT(_null_); /* LC_CTYPE setting */ + text colliculocale BKI_DEFAULT(_null_); /* ICU locale ID */ + text collversion BKI_DEFAULT(_null_); /* provider-dependent + * version of collation + * data */ +#endif +} FormData_pg_collation; + +/* ---------------- + * Form_pg_collation corresponds to a pointer to a row with + * the format of pg_collation relation. + * ---------------- + */ +typedef FormData_pg_collation *Form_pg_collation; + +DECLARE_TOAST(pg_collation, 6175, 6176); + +DECLARE_UNIQUE_INDEX(pg_collation_name_enc_nsp_index, 3164, CollationNameEncNspIndexId, on pg_collation using btree(collname name_ops, collencoding int4_ops, collnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_collation_oid_index, 3085, CollationOidIndexId, on pg_collation using btree(oid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +#define COLLPROVIDER_DEFAULT 'd' +#define COLLPROVIDER_ICU 'i' +#define COLLPROVIDER_LIBC 'c' + +static inline const char * +collprovider_name(char c) +{ + switch (c) + { + case COLLPROVIDER_ICU: + return "icu"; + case COLLPROVIDER_LIBC: + return "libc"; + default: + return "???"; + } +} + +#endif /* EXPOSE_TO_CLIENT_CODE */ + + +extern Oid CollationCreate(const char *collname, Oid collnamespace, + Oid collowner, + char collprovider, + bool collisdeterministic, + int32 collencoding, + const char *collcollate, const char *collctype, + const char *colliculocale, + const char *collversion, + bool if_not_exists, + bool quiet); + +#endif /* PG_COLLATION_H */ diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h new file mode 100644 index 0000000..e7d967f --- /dev/null +++ b/src/include/catalog/pg_constraint.h @@ -0,0 +1,273 @@ +/*------------------------------------------------------------------------- + * + * pg_constraint.h + * definition of the "constraint" system catalog (pg_constraint) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_constraint.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONSTRAINT_H +#define PG_CONSTRAINT_H + +#include "catalog/dependency.h" +#include "catalog/genbki.h" +#include "catalog/pg_constraint_d.h" +#include "nodes/pg_list.h" + +/* ---------------- + * pg_constraint definition. cpp turns this into + * typedef struct FormData_pg_constraint + * ---------------- + */ +CATALOG(pg_constraint,2606,ConstraintRelationId) +{ + Oid oid; /* oid */ + + /* + * conname + connamespace is deliberately not unique; we allow, for + * example, the same name to be used for constraints of different + * relations. This is partly for backwards compatibility with past + * Postgres practice, and partly because we don't want to have to obtain a + * global lock to generate a globally unique name for a nameless + * constraint. We associate a namespace with constraint names only for + * SQL-spec compatibility. + * + * However, we do require conname to be unique among the constraints of a + * single relation or domain. This is enforced by a unique index on + * conrelid + contypid + conname. + */ + NameData conname; /* name of this constraint */ + Oid connamespace BKI_LOOKUP(pg_namespace); /* OID of namespace + * containing constraint */ + char contype; /* constraint type; see codes below */ + bool condeferrable; /* deferrable constraint? */ + bool condeferred; /* deferred by default? */ + bool convalidated; /* constraint has been validated? */ + + /* + * conrelid and conkey are only meaningful if the constraint applies to a + * specific relation (this excludes domain constraints and assertions). + * Otherwise conrelid is 0 and conkey is NULL. + */ + Oid conrelid BKI_LOOKUP_OPT(pg_class); /* relation this + * constraint constrains */ + + /* + * contypid links to the pg_type row for a domain if this is a domain + * constraint. Otherwise it's 0. + * + * For SQL-style global ASSERTIONs, both conrelid and contypid would be + * zero. This is not presently supported, however. + */ + Oid contypid BKI_LOOKUP_OPT(pg_type); /* domain this constraint + * constrains */ + + /* + * conindid links to the index supporting the constraint, if any; + * otherwise it's 0. This is used for unique, primary-key, and exclusion + * constraints, and less obviously for foreign-key constraints (where the + * index is a unique index on the referenced relation's referenced + * columns). Notice that the index is on conrelid in the first case but + * confrelid in the second. + */ + Oid conindid BKI_LOOKUP_OPT(pg_class); /* index supporting this + * constraint */ + + /* + * If this constraint is on a partition inherited from a partitioned + * table, this is the OID of the corresponding constraint in the parent. + */ + Oid conparentid BKI_LOOKUP_OPT(pg_constraint); + + /* + * These fields, plus confkey, are only meaningful for a foreign-key + * constraint. Otherwise confrelid is 0 and the char fields are spaces. + */ + Oid confrelid BKI_LOOKUP_OPT(pg_class); /* relation referenced by + * foreign key */ + char confupdtype; /* foreign key's ON UPDATE action */ + char confdeltype; /* foreign key's ON DELETE action */ + char confmatchtype; /* foreign key's match type */ + + /* Has a local definition (hence, do not drop when coninhcount is 0) */ + bool conislocal; + + /* Number of times inherited from direct parent relation(s) */ + int32 coninhcount; + + /* Has a local definition and cannot be inherited */ + bool connoinherit; + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + /* + * Columns of conrelid that the constraint applies to, if known (this is + * NULL for trigger constraints) + */ + int16 conkey[1]; + + /* + * If a foreign key, the referenced columns of confrelid + */ + int16 confkey[1]; + + /* + * If a foreign key, the OIDs of the PK = FK equality operators for each + * column of the constraint + */ + Oid conpfeqop[1] BKI_LOOKUP(pg_operator); + + /* + * If a foreign key, the OIDs of the PK = PK equality operators for each + * column of the constraint (i.e., equality for the referenced columns) + */ + Oid conppeqop[1] BKI_LOOKUP(pg_operator); + + /* + * If a foreign key, the OIDs of the FK = FK equality operators for each + * column of the constraint (i.e., equality for the referencing columns) + */ + Oid conffeqop[1] BKI_LOOKUP(pg_operator); + + /* + * If a foreign key with an ON DELETE SET NULL/DEFAULT action, the subset + * of conkey to updated. If null, all columns are updated. + */ + int16 confdelsetcols[1]; + + /* + * If an exclusion constraint, the OIDs of the exclusion operators for + * each column of the constraint + */ + Oid conexclop[1] BKI_LOOKUP(pg_operator); + + /* + * If a check constraint, nodeToString representation of expression + */ + pg_node_tree conbin; +#endif +} FormData_pg_constraint; + +/* ---------------- + * Form_pg_constraint corresponds to a pointer to a tuple with + * the format of pg_constraint relation. + * ---------------- + */ +typedef FormData_pg_constraint *Form_pg_constraint; + +DECLARE_TOAST(pg_constraint, 2832, 2833); + +DECLARE_INDEX(pg_constraint_conname_nsp_index, 2664, ConstraintNameNspIndexId, on pg_constraint using btree(conname name_ops, connamespace oid_ops)); +DECLARE_UNIQUE_INDEX(pg_constraint_conrelid_contypid_conname_index, 2665, ConstraintRelidTypidNameIndexId, on pg_constraint using btree(conrelid oid_ops, contypid oid_ops, conname name_ops)); +DECLARE_INDEX(pg_constraint_contypid_index, 2666, ConstraintTypidIndexId, on pg_constraint using btree(contypid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, ConstraintOidIndexId, on pg_constraint using btree(oid oid_ops)); +DECLARE_INDEX(pg_constraint_conparentid_index, 2579, ConstraintParentIndexId, on pg_constraint using btree(conparentid oid_ops)); + +/* conkey can contain zero (InvalidAttrNumber) if a whole-row Var is used */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((conrelid, conkey), pg_attribute, (attrelid, attnum)); +DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* Valid values for contype */ +#define CONSTRAINT_CHECK 'c' +#define CONSTRAINT_FOREIGN 'f' +#define CONSTRAINT_PRIMARY 'p' +#define CONSTRAINT_UNIQUE 'u' +#define CONSTRAINT_TRIGGER 't' +#define CONSTRAINT_EXCLUSION 'x' + +/* + * Valid values for confupdtype and confdeltype are the FKCONSTR_ACTION_xxx + * constants defined in parsenodes.h. Valid values for confmatchtype are + * the FKCONSTR_MATCH_xxx constants defined in parsenodes.h. + */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +/* + * Identify constraint type for lookup purposes + */ +typedef enum ConstraintCategory +{ + CONSTRAINT_RELATION, + CONSTRAINT_DOMAIN, + CONSTRAINT_ASSERTION /* for future expansion */ +} ConstraintCategory; + + +extern Oid CreateConstraintEntry(const char *constraintName, + Oid constraintNamespace, + char constraintType, + bool isDeferrable, + bool isDeferred, + bool isValidated, + Oid parentConstrId, + Oid relId, + const int16 *constraintKey, + int constraintNKeys, + int constraintNTotalKeys, + Oid domainId, + Oid indexRelId, + Oid foreignRelId, + const int16 *foreignKey, + const Oid *pfEqOp, + const Oid *ppEqOp, + const Oid *ffEqOp, + int foreignNKeys, + char foreignUpdateType, + char foreignDeleteType, + const int16 *fkDeleteSetCols, + int numFkDeleteSetCols, + char foreignMatchType, + const Oid *exclOp, + Node *conExpr, + const char *conBin, + bool conIsLocal, + int conInhCount, + bool conNoInherit, + bool is_internal); + +extern void RemoveConstraintById(Oid conId); +extern void RenameConstraintById(Oid conId, const char *newname); + +extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, + const char *conname); +extern bool ConstraintNameExists(const char *conname, Oid namespaceid); +extern char *ChooseConstraintName(const char *name1, const char *name2, + const char *label, Oid namespaceid, + List *others); + +extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, + Oid newNspId, bool isType, ObjectAddresses *objsMoved); +extern void ConstraintSetParentConstraint(Oid childConstrId, + Oid parentConstrId, + Oid childTableId); +extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok); +extern Bitmapset *get_relation_constraint_attnos(Oid relid, const char *conname, + bool missing_ok, Oid *constraintOid); +extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok); +extern Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId); + +extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk, + Oid *constraintOid); +extern void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, + AttrNumber *conkey, AttrNumber *confkey, + Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, + int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols); + +extern bool check_functional_grouping(Oid relid, + Index varno, Index varlevelsup, + List *grouping_columns, + List **constraintDeps); + +#endif /* PG_CONSTRAINT_H */ diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h new file mode 100644 index 0000000..06368e2 --- /dev/null +++ b/src/include/catalog/pg_control.h @@ -0,0 +1,250 @@ +/*------------------------------------------------------------------------- + * + * pg_control.h + * The system control file "pg_control" is not a heap relation. + * However, we define it here so that the format is documented. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_control.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONTROL_H +#define PG_CONTROL_H + +#include "access/transam.h" +#include "access/xlogdefs.h" +#include "pgtime.h" /* for pg_time_t */ +#include "port/pg_crc32c.h" + + +/* Version identifier for this pg_control format */ +#define PG_CONTROL_VERSION 1300 + +/* Nonce key length, see below */ +#define MOCK_AUTH_NONCE_LEN 32 + +/* + * Body of CheckPoint XLOG records. This is declared here because we keep + * a copy of the latest one in pg_control for possible disaster recovery. + * Changing this struct requires a PG_CONTROL_VERSION bump. + */ +typedef struct CheckPoint +{ + XLogRecPtr redo; /* next RecPtr available when we began to + * create CheckPoint (i.e. REDO start point) */ + TimeLineID ThisTimeLineID; /* current TLI */ + TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new + * timeline (equals ThisTimeLineID otherwise) */ + bool fullPageWrites; /* current full_page_writes */ + FullTransactionId nextXid; /* next free transaction ID */ + Oid nextOid; /* next free OID */ + MultiXactId nextMulti; /* next free MultiXactId */ + MultiXactOffset nextMultiOffset; /* next free MultiXact offset */ + TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */ + Oid oldestXidDB; /* database with minimum datfrozenxid */ + MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */ + Oid oldestMultiDB; /* database with minimum datminmxid */ + pg_time_t time; /* time stamp of checkpoint */ + TransactionId oldestCommitTsXid; /* oldest Xid with valid commit + * timestamp */ + TransactionId newestCommitTsXid; /* newest Xid with valid commit + * timestamp */ + + /* + * Oldest XID still running. This is only needed to initialize hot standby + * mode from an online checkpoint, so we only bother calculating this for + * online checkpoints and only when wal_level is replica. Otherwise it's + * set to InvalidTransactionId. + */ + TransactionId oldestActiveXid; +} CheckPoint; + +/* XLOG info values for XLOG rmgr */ +#define XLOG_CHECKPOINT_SHUTDOWN 0x00 +#define XLOG_CHECKPOINT_ONLINE 0x10 +#define XLOG_NOOP 0x20 +#define XLOG_NEXTOID 0x30 +#define XLOG_SWITCH 0x40 +#define XLOG_BACKUP_END 0x50 +#define XLOG_PARAMETER_CHANGE 0x60 +#define XLOG_RESTORE_POINT 0x70 +#define XLOG_FPW_CHANGE 0x80 +#define XLOG_END_OF_RECOVERY 0x90 +#define XLOG_FPI_FOR_HINT 0xA0 +#define XLOG_FPI 0xB0 +/* 0xC0 is used in Postgres 9.5-11 */ +#define XLOG_OVERWRITE_CONTRECORD 0xD0 + + +/* + * System status indicator. Note this is stored in pg_control; if you change + * it, you must bump PG_CONTROL_VERSION + */ +typedef enum DBState +{ + DB_STARTUP = 0, + DB_SHUTDOWNED, + DB_SHUTDOWNED_IN_RECOVERY, + DB_SHUTDOWNING, + DB_IN_CRASH_RECOVERY, + DB_IN_ARCHIVE_RECOVERY, + DB_IN_PRODUCTION +} DBState; + +/* + * Contents of pg_control. + */ + +typedef struct ControlFileData +{ + /* + * Unique system identifier --- to ensure we match up xlog files with the + * installation that produced them. + */ + uint64 system_identifier; + + /* + * Version identifier information. Keep these fields at the same offset, + * especially pg_control_version; they won't be real useful if they move + * around. (For historical reasons they must be 8 bytes into the file + * rather than immediately at the front.) + * + * pg_control_version identifies the format of pg_control itself. + * catalog_version_no identifies the format of the system catalogs. + * + * There are additional version identifiers in individual files; for + * example, WAL logs contain per-page magic numbers that can serve as + * version cues for the WAL log. + */ + uint32 pg_control_version; /* PG_CONTROL_VERSION */ + uint32 catalog_version_no; /* see catversion.h */ + + /* + * System status data + */ + DBState state; /* see enum above */ + pg_time_t time; /* time stamp of last pg_control update */ + XLogRecPtr checkPoint; /* last check point record ptr */ + + CheckPoint checkPointCopy; /* copy of last check point record */ + + XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */ + + /* + * These two values determine the minimum point we must recover up to + * before starting up: + * + * minRecoveryPoint is updated to the latest replayed LSN whenever we + * flush a data change during archive recovery. That guards against + * starting archive recovery, aborting it, and restarting with an earlier + * stop location. If we've already flushed data changes from WAL record X + * to disk, we mustn't start up until we reach X again. Zero when not + * doing archive recovery. + * + * backupStartPoint is the redo pointer of the backup start checkpoint, if + * we are recovering from an online backup and haven't reached the end of + * backup yet. It is reset to zero when the end of backup is reached, and + * we mustn't start up before that. A boolean would suffice otherwise, but + * we use the redo pointer as a cross-check when we see an end-of-backup + * record, to make sure the end-of-backup record corresponds the base + * backup we're recovering from. + * + * backupEndPoint is the backup end location, if we are recovering from an + * online backup which was taken from the standby and haven't reached the + * end of backup yet. It is initialized to the minimum recovery point in + * pg_control which was backed up last. It is reset to zero when the end + * of backup is reached, and we mustn't start up before that. + * + * If backupEndRequired is true, we know for sure that we're restoring + * from a backup, and must see a backup-end record before we can safely + * start up. + */ + XLogRecPtr minRecoveryPoint; + TimeLineID minRecoveryPointTLI; + XLogRecPtr backupStartPoint; + XLogRecPtr backupEndPoint; + bool backupEndRequired; + + /* + * Parameter settings that determine if the WAL can be used for archival + * or hot standby. + */ + int wal_level; + bool wal_log_hints; + int MaxConnections; + int max_worker_processes; + int max_wal_senders; + int max_prepared_xacts; + int max_locks_per_xact; + bool track_commit_timestamp; + + /* + * This data is used to check for hardware-architecture compatibility of + * the database and the backend executable. We need not check endianness + * explicitly, since the pg_control version will surely look wrong to a + * machine of different endianness, but we do need to worry about MAXALIGN + * and floating-point format. (Note: storage layout nominally also + * depends on SHORTALIGN and INTALIGN, but in practice these are the same + * on all architectures of interest.) + * + * Testing just one double value is not a very bulletproof test for + * floating-point compatibility, but it will catch most cases. + */ + uint32 maxAlign; /* alignment requirement for tuples */ + double floatFormat; /* constant 1234567.0 */ +#define FLOATFORMAT_VALUE 1234567.0 + + /* + * This data is used to make sure that configuration of this database is + * compatible with the backend executable. + */ + uint32 blcksz; /* data block size for this DB */ + uint32 relseg_size; /* blocks per segment of large relation */ + + uint32 xlog_blcksz; /* block size within WAL files */ + uint32 xlog_seg_size; /* size of each WAL segment */ + + uint32 nameDataLen; /* catalog name field width */ + uint32 indexMaxKeys; /* max number of columns in an index */ + + uint32 toast_max_chunk_size; /* chunk size in TOAST tables */ + uint32 loblksize; /* chunk size in pg_largeobject */ + + bool float8ByVal; /* float8, int8, etc pass-by-value? */ + + /* Are data pages protected by checksums? Zero if no checksum version */ + uint32 data_checksum_version; + + /* + * Random nonce, used in authentication requests that need to proceed + * based on values that are cluster-unique, like a SASL exchange that + * failed at an early stage. + */ + char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN]; + + /* CRC of all above ... MUST BE LAST! */ + pg_crc32c crc; +} ControlFileData; + +/* + * Maximum safe value of sizeof(ControlFileData). For reliability's sake, + * it's critical that pg_control updates be atomic writes. That generally + * means the active data can't be more than one disk sector, which is 512 + * bytes on common hardware. Be very careful about raising this limit. + */ +#define PG_CONTROL_MAX_SAFE_SIZE 512 + +/* + * Physical size of the pg_control file. Note that this is considerably + * bigger than the actually used size (ie, sizeof(ControlFileData)). + * The idea is to keep the physical size constant independent of format + * changes, so that ReadControlFile will deliver a suitable wrong-version + * message instead of a read error if it's looking at an incompatible file. + */ +#define PG_CONTROL_FILE_SIZE 8192 + +#endif /* PG_CONTROL_H */ diff --git a/src/include/catalog/pg_conversion.dat b/src/include/catalog/pg_conversion.dat new file mode 100644 index 0000000..17f3f16 --- /dev/null +++ b/src/include/catalog/pg_conversion.dat @@ -0,0 +1,405 @@ +#---------------------------------------------------------------------- +# +# pg_conversion.dat +# Initial contents of the pg_conversion system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_conversion.dat +# +#---------------------------------------------------------------------- + +# Note: conforencoding and contoencoding must match the spelling of +# the labels used in the enum pg_enc in mb/pg_wchar.h. + +[ + +{ oid => '4402', descr => 'conversion for KOI8R to MULE_INTERNAL', + conname => 'koi8_r_to_mic', conforencoding => 'PG_KOI8R', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'koi8r_to_mic' }, +{ oid => '4403', descr => 'conversion for MULE_INTERNAL to KOI8R', + conname => 'mic_to_koi8_r', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_KOI8R', conproc => 'mic_to_koi8r' }, +{ oid => '4404', descr => 'conversion for ISO-8859-5 to MULE_INTERNAL', + conname => 'iso_8859_5_to_mic', conforencoding => 'PG_ISO_8859_5', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'iso_to_mic' }, +{ oid => '4405', descr => 'conversion for MULE_INTERNAL to ISO-8859-5', + conname => 'mic_to_iso_8859_5', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_ISO_8859_5', conproc => 'mic_to_iso' }, +{ oid => '4406', descr => 'conversion for WIN1251 to MULE_INTERNAL', + conname => 'windows_1251_to_mic', conforencoding => 'PG_WIN1251', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'win1251_to_mic' }, +{ oid => '4407', descr => 'conversion for MULE_INTERNAL to WIN1251', + conname => 'mic_to_windows_1251', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_WIN1251', conproc => 'mic_to_win1251' }, +{ oid => '4408', descr => 'conversion for WIN866 to MULE_INTERNAL', + conname => 'windows_866_to_mic', conforencoding => 'PG_WIN866', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'win866_to_mic' }, +{ oid => '4409', descr => 'conversion for MULE_INTERNAL to WIN866', + conname => 'mic_to_windows_866', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_WIN866', conproc => 'mic_to_win866' }, +{ oid => '4410', descr => 'conversion for KOI8R to WIN1251', + conname => 'koi8_r_to_windows_1251', conforencoding => 'PG_KOI8R', + contoencoding => 'PG_WIN1251', conproc => 'koi8r_to_win1251' }, +{ oid => '4411', descr => 'conversion for WIN1251 to KOI8R', + conname => 'windows_1251_to_koi8_r', conforencoding => 'PG_WIN1251', + contoencoding => 'PG_KOI8R', conproc => 'win1251_to_koi8r' }, +{ oid => '4412', descr => 'conversion for KOI8R to WIN866', + conname => 'koi8_r_to_windows_866', conforencoding => 'PG_KOI8R', + contoencoding => 'PG_WIN866', conproc => 'koi8r_to_win866' }, +{ oid => '4413', descr => 'conversion for WIN866 to KOI8R', + conname => 'windows_866_to_koi8_r', conforencoding => 'PG_WIN866', + contoencoding => 'PG_KOI8R', conproc => 'win866_to_koi8r' }, +{ oid => '4414', descr => 'conversion for WIN866 to WIN1251', + conname => 'windows_866_to_windows_1251', conforencoding => 'PG_WIN866', + contoencoding => 'PG_WIN1251', conproc => 'win866_to_win1251' }, +{ oid => '4415', descr => 'conversion for WIN1251 to WIN866', + conname => 'windows_1251_to_windows_866', conforencoding => 'PG_WIN1251', + contoencoding => 'PG_WIN866', conproc => 'win1251_to_win866' }, +{ oid => '4416', descr => 'conversion for ISO-8859-5 to KOI8R', + conname => 'iso_8859_5_to_koi8_r', conforencoding => 'PG_ISO_8859_5', + contoencoding => 'PG_KOI8R', conproc => 'iso_to_koi8r' }, +{ oid => '4417', descr => 'conversion for KOI8R to ISO-8859-5', + conname => 'koi8_r_to_iso_8859_5', conforencoding => 'PG_KOI8R', + contoencoding => 'PG_ISO_8859_5', conproc => 'koi8r_to_iso' }, +{ oid => '4418', descr => 'conversion for ISO-8859-5 to WIN1251', + conname => 'iso_8859_5_to_windows_1251', conforencoding => 'PG_ISO_8859_5', + contoencoding => 'PG_WIN1251', conproc => 'iso_to_win1251' }, +{ oid => '4419', descr => 'conversion for WIN1251 to ISO-8859-5', + conname => 'windows_1251_to_iso_8859_5', conforencoding => 'PG_WIN1251', + contoencoding => 'PG_ISO_8859_5', conproc => 'win1251_to_iso' }, +{ oid => '4420', descr => 'conversion for ISO-8859-5 to WIN866', + conname => 'iso_8859_5_to_windows_866', conforencoding => 'PG_ISO_8859_5', + contoencoding => 'PG_WIN866', conproc => 'iso_to_win866' }, +{ oid => '4421', descr => 'conversion for WIN866 to ISO-8859-5', + conname => 'windows_866_to_iso_8859_5', conforencoding => 'PG_WIN866', + contoencoding => 'PG_ISO_8859_5', conproc => 'win866_to_iso' }, +{ oid => '4422', descr => 'conversion for EUC_CN to MULE_INTERNAL', + conname => 'euc_cn_to_mic', conforencoding => 'PG_EUC_CN', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'euc_cn_to_mic' }, +{ oid => '4423', descr => 'conversion for MULE_INTERNAL to EUC_CN', + conname => 'mic_to_euc_cn', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_EUC_CN', conproc => 'mic_to_euc_cn' }, +{ oid => '4424', descr => 'conversion for EUC_JP to SJIS', + conname => 'euc_jp_to_sjis', conforencoding => 'PG_EUC_JP', + contoencoding => 'PG_SJIS', conproc => 'euc_jp_to_sjis' }, +{ oid => '4425', descr => 'conversion for SJIS to EUC_JP', + conname => 'sjis_to_euc_jp', conforencoding => 'PG_SJIS', + contoencoding => 'PG_EUC_JP', conproc => 'sjis_to_euc_jp' }, +{ oid => '4426', descr => 'conversion for EUC_JP to MULE_INTERNAL', + conname => 'euc_jp_to_mic', conforencoding => 'PG_EUC_JP', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'euc_jp_to_mic' }, +{ oid => '4427', descr => 'conversion for SJIS to MULE_INTERNAL', + conname => 'sjis_to_mic', conforencoding => 'PG_SJIS', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'sjis_to_mic' }, +{ oid => '4428', descr => 'conversion for MULE_INTERNAL to EUC_JP', + conname => 'mic_to_euc_jp', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_EUC_JP', conproc => 'mic_to_euc_jp' }, +{ oid => '4429', descr => 'conversion for MULE_INTERNAL to SJIS', + conname => 'mic_to_sjis', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_SJIS', conproc => 'mic_to_sjis' }, +{ oid => '4430', descr => 'conversion for EUC_KR to MULE_INTERNAL', + conname => 'euc_kr_to_mic', conforencoding => 'PG_EUC_KR', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'euc_kr_to_mic' }, +{ oid => '4431', descr => 'conversion for MULE_INTERNAL to EUC_KR', + conname => 'mic_to_euc_kr', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_EUC_KR', conproc => 'mic_to_euc_kr' }, +{ oid => '4432', descr => 'conversion for EUC_TW to BIG5', + conname => 'euc_tw_to_big5', conforencoding => 'PG_EUC_TW', + contoencoding => 'PG_BIG5', conproc => 'euc_tw_to_big5' }, +{ oid => '4433', descr => 'conversion for BIG5 to EUC_TW', + conname => 'big5_to_euc_tw', conforencoding => 'PG_BIG5', + contoencoding => 'PG_EUC_TW', conproc => 'big5_to_euc_tw' }, +{ oid => '4434', descr => 'conversion for EUC_TW to MULE_INTERNAL', + conname => 'euc_tw_to_mic', conforencoding => 'PG_EUC_TW', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'euc_tw_to_mic' }, +{ oid => '4435', descr => 'conversion for BIG5 to MULE_INTERNAL', + conname => 'big5_to_mic', conforencoding => 'PG_BIG5', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'big5_to_mic' }, +{ oid => '4436', descr => 'conversion for MULE_INTERNAL to EUC_TW', + conname => 'mic_to_euc_tw', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_EUC_TW', conproc => 'mic_to_euc_tw' }, +{ oid => '4437', descr => 'conversion for MULE_INTERNAL to BIG5', + conname => 'mic_to_big5', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_BIG5', conproc => 'mic_to_big5' }, +{ oid => '4438', descr => 'conversion for LATIN2 to MULE_INTERNAL', + conname => 'iso_8859_2_to_mic', conforencoding => 'PG_LATIN2', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'latin2_to_mic' }, +{ oid => '4439', descr => 'conversion for MULE_INTERNAL to LATIN2', + conname => 'mic_to_iso_8859_2', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_LATIN2', conproc => 'mic_to_latin2' }, +{ oid => '4440', descr => 'conversion for WIN1250 to MULE_INTERNAL', + conname => 'windows_1250_to_mic', conforencoding => 'PG_WIN1250', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'win1250_to_mic' }, +{ oid => '4441', descr => 'conversion for MULE_INTERNAL to WIN1250', + conname => 'mic_to_windows_1250', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_WIN1250', conproc => 'mic_to_win1250' }, +{ oid => '4442', descr => 'conversion for LATIN2 to WIN1250', + conname => 'iso_8859_2_to_windows_1250', conforencoding => 'PG_LATIN2', + contoencoding => 'PG_WIN1250', conproc => 'latin2_to_win1250' }, +{ oid => '4443', descr => 'conversion for WIN1250 to LATIN2', + conname => 'windows_1250_to_iso_8859_2', conforencoding => 'PG_WIN1250', + contoencoding => 'PG_LATIN2', conproc => 'win1250_to_latin2' }, +{ oid => '4444', descr => 'conversion for LATIN1 to MULE_INTERNAL', + conname => 'iso_8859_1_to_mic', conforencoding => 'PG_LATIN1', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'latin1_to_mic' }, +{ oid => '4445', descr => 'conversion for MULE_INTERNAL to LATIN1', + conname => 'mic_to_iso_8859_1', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_LATIN1', conproc => 'mic_to_latin1' }, +{ oid => '4446', descr => 'conversion for LATIN3 to MULE_INTERNAL', + conname => 'iso_8859_3_to_mic', conforencoding => 'PG_LATIN3', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'latin3_to_mic' }, +{ oid => '4447', descr => 'conversion for MULE_INTERNAL to LATIN3', + conname => 'mic_to_iso_8859_3', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_LATIN3', conproc => 'mic_to_latin3' }, +{ oid => '4448', descr => 'conversion for LATIN4 to MULE_INTERNAL', + conname => 'iso_8859_4_to_mic', conforencoding => 'PG_LATIN4', + contoencoding => 'PG_MULE_INTERNAL', conproc => 'latin4_to_mic' }, +{ oid => '4449', descr => 'conversion for MULE_INTERNAL to LATIN4', + conname => 'mic_to_iso_8859_4', conforencoding => 'PG_MULE_INTERNAL', + contoencoding => 'PG_LATIN4', conproc => 'mic_to_latin4' }, +{ oid => '4452', descr => 'conversion for BIG5 to UTF8', + conname => 'big5_to_utf8', conforencoding => 'PG_BIG5', + contoencoding => 'PG_UTF8', conproc => 'big5_to_utf8' }, +{ oid => '4453', descr => 'conversion for UTF8 to BIG5', + conname => 'utf8_to_big5', conforencoding => 'PG_UTF8', + contoencoding => 'PG_BIG5', conproc => 'utf8_to_big5' }, +{ oid => '4454', descr => 'conversion for UTF8 to KOI8R', + conname => 'utf8_to_koi8_r', conforencoding => 'PG_UTF8', + contoencoding => 'PG_KOI8R', conproc => 'utf8_to_koi8r' }, +{ oid => '4455', descr => 'conversion for KOI8R to UTF8', + conname => 'koi8_r_to_utf8', conforencoding => 'PG_KOI8R', + contoencoding => 'PG_UTF8', conproc => 'koi8r_to_utf8' }, +{ oid => '4456', descr => 'conversion for UTF8 to KOI8U', + conname => 'utf8_to_koi8_u', conforencoding => 'PG_UTF8', + contoencoding => 'PG_KOI8U', conproc => 'utf8_to_koi8u' }, +{ oid => '4457', descr => 'conversion for KOI8U to UTF8', + conname => 'koi8_u_to_utf8', conforencoding => 'PG_KOI8U', + contoencoding => 'PG_UTF8', conproc => 'koi8u_to_utf8' }, +{ oid => '4458', descr => 'conversion for UTF8 to WIN866', + conname => 'utf8_to_windows_866', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN866', conproc => 'utf8_to_win' }, +{ oid => '4459', descr => 'conversion for WIN866 to UTF8', + conname => 'windows_866_to_utf8', conforencoding => 'PG_WIN866', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4460', descr => 'conversion for UTF8 to WIN874', + conname => 'utf8_to_windows_874', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN874', conproc => 'utf8_to_win' }, +{ oid => '4461', descr => 'conversion for WIN874 to UTF8', + conname => 'windows_874_to_utf8', conforencoding => 'PG_WIN874', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4462', descr => 'conversion for UTF8 to WIN1250', + conname => 'utf8_to_windows_1250', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1250', conproc => 'utf8_to_win' }, +{ oid => '4463', descr => 'conversion for WIN1250 to UTF8', + conname => 'windows_1250_to_utf8', conforencoding => 'PG_WIN1250', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4464', descr => 'conversion for UTF8 to WIN1251', + conname => 'utf8_to_windows_1251', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1251', conproc => 'utf8_to_win' }, +{ oid => '4465', descr => 'conversion for WIN1251 to UTF8', + conname => 'windows_1251_to_utf8', conforencoding => 'PG_WIN1251', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4466', descr => 'conversion for UTF8 to WIN1252', + conname => 'utf8_to_windows_1252', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1252', conproc => 'utf8_to_win' }, +{ oid => '4467', descr => 'conversion for WIN1252 to UTF8', + conname => 'windows_1252_to_utf8', conforencoding => 'PG_WIN1252', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4468', descr => 'conversion for UTF8 to WIN1253', + conname => 'utf8_to_windows_1253', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1253', conproc => 'utf8_to_win' }, +{ oid => '4469', descr => 'conversion for WIN1253 to UTF8', + conname => 'windows_1253_to_utf8', conforencoding => 'PG_WIN1253', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4470', descr => 'conversion for UTF8 to WIN1254', + conname => 'utf8_to_windows_1254', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1254', conproc => 'utf8_to_win' }, +{ oid => '4471', descr => 'conversion for WIN1254 to UTF8', + conname => 'windows_1254_to_utf8', conforencoding => 'PG_WIN1254', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4472', descr => 'conversion for UTF8 to WIN1255', + conname => 'utf8_to_windows_1255', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1255', conproc => 'utf8_to_win' }, +{ oid => '4473', descr => 'conversion for WIN1255 to UTF8', + conname => 'windows_1255_to_utf8', conforencoding => 'PG_WIN1255', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4474', descr => 'conversion for UTF8 to WIN1256', + conname => 'utf8_to_windows_1256', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1256', conproc => 'utf8_to_win' }, +{ oid => '4475', descr => 'conversion for WIN1256 to UTF8', + conname => 'windows_1256_to_utf8', conforencoding => 'PG_WIN1256', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4476', descr => 'conversion for UTF8 to WIN1257', + conname => 'utf8_to_windows_1257', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1257', conproc => 'utf8_to_win' }, +{ oid => '4477', descr => 'conversion for WIN1257 to UTF8', + conname => 'windows_1257_to_utf8', conforencoding => 'PG_WIN1257', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4478', descr => 'conversion for UTF8 to WIN1258', + conname => 'utf8_to_windows_1258', conforencoding => 'PG_UTF8', + contoencoding => 'PG_WIN1258', conproc => 'utf8_to_win' }, +{ oid => '4479', descr => 'conversion for WIN1258 to UTF8', + conname => 'windows_1258_to_utf8', conforencoding => 'PG_WIN1258', + contoencoding => 'PG_UTF8', conproc => 'win_to_utf8' }, +{ oid => '4480', descr => 'conversion for EUC_CN to UTF8', + conname => 'euc_cn_to_utf8', conforencoding => 'PG_EUC_CN', + contoencoding => 'PG_UTF8', conproc => 'euc_cn_to_utf8' }, +{ oid => '4481', descr => 'conversion for UTF8 to EUC_CN', + conname => 'utf8_to_euc_cn', conforencoding => 'PG_UTF8', + contoencoding => 'PG_EUC_CN', conproc => 'utf8_to_euc_cn' }, +{ oid => '4482', descr => 'conversion for EUC_JP to UTF8', + conname => 'euc_jp_to_utf8', conforencoding => 'PG_EUC_JP', + contoencoding => 'PG_UTF8', conproc => 'euc_jp_to_utf8' }, +{ oid => '4483', descr => 'conversion for UTF8 to EUC_JP', + conname => 'utf8_to_euc_jp', conforencoding => 'PG_UTF8', + contoencoding => 'PG_EUC_JP', conproc => 'utf8_to_euc_jp' }, +{ oid => '4484', descr => 'conversion for EUC_KR to UTF8', + conname => 'euc_kr_to_utf8', conforencoding => 'PG_EUC_KR', + contoencoding => 'PG_UTF8', conproc => 'euc_kr_to_utf8' }, +{ oid => '4485', descr => 'conversion for UTF8 to EUC_KR', + conname => 'utf8_to_euc_kr', conforencoding => 'PG_UTF8', + contoencoding => 'PG_EUC_KR', conproc => 'utf8_to_euc_kr' }, +{ oid => '4486', descr => 'conversion for EUC_TW to UTF8', + conname => 'euc_tw_to_utf8', conforencoding => 'PG_EUC_TW', + contoencoding => 'PG_UTF8', conproc => 'euc_tw_to_utf8' }, +{ oid => '4487', descr => 'conversion for UTF8 to EUC_TW', + conname => 'utf8_to_euc_tw', conforencoding => 'PG_UTF8', + contoencoding => 'PG_EUC_TW', conproc => 'utf8_to_euc_tw' }, +{ oid => '4488', descr => 'conversion for GB18030 to UTF8', + conname => 'gb18030_to_utf8', conforencoding => 'PG_GB18030', + contoencoding => 'PG_UTF8', conproc => 'gb18030_to_utf8' }, +{ oid => '4489', descr => 'conversion for UTF8 to GB18030', + conname => 'utf8_to_gb18030', conforencoding => 'PG_UTF8', + contoencoding => 'PG_GB18030', conproc => 'utf8_to_gb18030' }, +{ oid => '4490', descr => 'conversion for GBK to UTF8', + conname => 'gbk_to_utf8', conforencoding => 'PG_GBK', + contoencoding => 'PG_UTF8', conproc => 'gbk_to_utf8' }, +{ oid => '4491', descr => 'conversion for UTF8 to GBK', + conname => 'utf8_to_gbk', conforencoding => 'PG_UTF8', + contoencoding => 'PG_GBK', conproc => 'utf8_to_gbk' }, +{ oid => '4492', descr => 'conversion for UTF8 to LATIN2', + conname => 'utf8_to_iso_8859_2', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN2', conproc => 'utf8_to_iso8859' }, +{ oid => '4493', descr => 'conversion for LATIN2 to UTF8', + conname => 'iso_8859_2_to_utf8', conforencoding => 'PG_LATIN2', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4494', descr => 'conversion for UTF8 to LATIN3', + conname => 'utf8_to_iso_8859_3', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN3', conproc => 'utf8_to_iso8859' }, +{ oid => '4495', descr => 'conversion for LATIN3 to UTF8', + conname => 'iso_8859_3_to_utf8', conforencoding => 'PG_LATIN3', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4496', descr => 'conversion for UTF8 to LATIN4', + conname => 'utf8_to_iso_8859_4', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN4', conproc => 'utf8_to_iso8859' }, +{ oid => '4497', descr => 'conversion for LATIN4 to UTF8', + conname => 'iso_8859_4_to_utf8', conforencoding => 'PG_LATIN4', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4498', descr => 'conversion for UTF8 to LATIN5', + conname => 'utf8_to_iso_8859_9', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN5', conproc => 'utf8_to_iso8859' }, +{ oid => '4499', descr => 'conversion for LATIN5 to UTF8', + conname => 'iso_8859_9_to_utf8', conforencoding => 'PG_LATIN5', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4500', descr => 'conversion for UTF8 to LATIN6', + conname => 'utf8_to_iso_8859_10', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN6', conproc => 'utf8_to_iso8859' }, +{ oid => '4501', descr => 'conversion for LATIN6 to UTF8', + conname => 'iso_8859_10_to_utf8', conforencoding => 'PG_LATIN6', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4502', descr => 'conversion for UTF8 to LATIN7', + conname => 'utf8_to_iso_8859_13', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN7', conproc => 'utf8_to_iso8859' }, +{ oid => '4503', descr => 'conversion for LATIN7 to UTF8', + conname => 'iso_8859_13_to_utf8', conforencoding => 'PG_LATIN7', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4504', descr => 'conversion for UTF8 to LATIN8', + conname => 'utf8_to_iso_8859_14', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN8', conproc => 'utf8_to_iso8859' }, +{ oid => '4505', descr => 'conversion for LATIN8 to UTF8', + conname => 'iso_8859_14_to_utf8', conforencoding => 'PG_LATIN8', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4506', descr => 'conversion for UTF8 to LATIN9', + conname => 'utf8_to_iso_8859_15', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN9', conproc => 'utf8_to_iso8859' }, +{ oid => '4507', descr => 'conversion for LATIN9 to UTF8', + conname => 'iso_8859_15_to_utf8', conforencoding => 'PG_LATIN9', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4508', descr => 'conversion for UTF8 to LATIN10', + conname => 'utf8_to_iso_8859_16', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN10', conproc => 'utf8_to_iso8859' }, +{ oid => '4509', descr => 'conversion for LATIN10 to UTF8', + conname => 'iso_8859_16_to_utf8', conforencoding => 'PG_LATIN10', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4510', descr => 'conversion for UTF8 to ISO-8859-5', + conname => 'utf8_to_iso_8859_5', conforencoding => 'PG_UTF8', + contoencoding => 'PG_ISO_8859_5', conproc => 'utf8_to_iso8859' }, +{ oid => '4511', descr => 'conversion for ISO-8859-5 to UTF8', + conname => 'iso_8859_5_to_utf8', conforencoding => 'PG_ISO_8859_5', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4512', descr => 'conversion for UTF8 to ISO-8859-6', + conname => 'utf8_to_iso_8859_6', conforencoding => 'PG_UTF8', + contoencoding => 'PG_ISO_8859_6', conproc => 'utf8_to_iso8859' }, +{ oid => '4513', descr => 'conversion for ISO-8859-6 to UTF8', + conname => 'iso_8859_6_to_utf8', conforencoding => 'PG_ISO_8859_6', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4514', descr => 'conversion for UTF8 to ISO-8859-7', + conname => 'utf8_to_iso_8859_7', conforencoding => 'PG_UTF8', + contoencoding => 'PG_ISO_8859_7', conproc => 'utf8_to_iso8859' }, +{ oid => '4515', descr => 'conversion for ISO-8859-7 to UTF8', + conname => 'iso_8859_7_to_utf8', conforencoding => 'PG_ISO_8859_7', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4516', descr => 'conversion for UTF8 to ISO-8859-8', + conname => 'utf8_to_iso_8859_8', conforencoding => 'PG_UTF8', + contoencoding => 'PG_ISO_8859_8', conproc => 'utf8_to_iso8859' }, +{ oid => '4517', descr => 'conversion for ISO-8859-8 to UTF8', + conname => 'iso_8859_8_to_utf8', conforencoding => 'PG_ISO_8859_8', + contoencoding => 'PG_UTF8', conproc => 'iso8859_to_utf8' }, +{ oid => '4518', descr => 'conversion for LATIN1 to UTF8', + conname => 'iso_8859_1_to_utf8', conforencoding => 'PG_LATIN1', + contoencoding => 'PG_UTF8', conproc => 'iso8859_1_to_utf8' }, +{ oid => '4519', descr => 'conversion for UTF8 to LATIN1', + conname => 'utf8_to_iso_8859_1', conforencoding => 'PG_UTF8', + contoencoding => 'PG_LATIN1', conproc => 'utf8_to_iso8859_1' }, +{ oid => '4520', descr => 'conversion for JOHAB to UTF8', + conname => 'johab_to_utf8', conforencoding => 'PG_JOHAB', + contoencoding => 'PG_UTF8', conproc => 'johab_to_utf8' }, +{ oid => '4521', descr => 'conversion for UTF8 to JOHAB', + conname => 'utf8_to_johab', conforencoding => 'PG_UTF8', + contoencoding => 'PG_JOHAB', conproc => 'utf8_to_johab' }, +{ oid => '4522', descr => 'conversion for SJIS to UTF8', + conname => 'sjis_to_utf8', conforencoding => 'PG_SJIS', + contoencoding => 'PG_UTF8', conproc => 'sjis_to_utf8' }, +{ oid => '4523', descr => 'conversion for UTF8 to SJIS', + conname => 'utf8_to_sjis', conforencoding => 'PG_UTF8', + contoencoding => 'PG_SJIS', conproc => 'utf8_to_sjis' }, +{ oid => '4524', descr => 'conversion for UHC to UTF8', + conname => 'uhc_to_utf8', conforencoding => 'PG_UHC', + contoencoding => 'PG_UTF8', conproc => 'uhc_to_utf8' }, +{ oid => '4525', descr => 'conversion for UTF8 to UHC', + conname => 'utf8_to_uhc', conforencoding => 'PG_UTF8', + contoencoding => 'PG_UHC', conproc => 'utf8_to_uhc' }, +{ oid => '4526', descr => 'conversion for EUC_JIS_2004 to UTF8', + conname => 'euc_jis_2004_to_utf8', conforencoding => 'PG_EUC_JIS_2004', + contoencoding => 'PG_UTF8', conproc => 'euc_jis_2004_to_utf8' }, +{ oid => '4527', descr => 'conversion for UTF8 to EUC_JIS_2004', + conname => 'utf8_to_euc_jis_2004', conforencoding => 'PG_UTF8', + contoencoding => 'PG_EUC_JIS_2004', conproc => 'utf8_to_euc_jis_2004' }, +{ oid => '4528', descr => 'conversion for SHIFT_JIS_2004 to UTF8', + conname => 'shift_jis_2004_to_utf8', conforencoding => 'PG_SHIFT_JIS_2004', + contoencoding => 'PG_UTF8', conproc => 'shift_jis_2004_to_utf8' }, +{ oid => '4529', descr => 'conversion for UTF8 to SHIFT_JIS_2004', + conname => 'utf8_to_shift_jis_2004', conforencoding => 'PG_UTF8', + contoencoding => 'PG_SHIFT_JIS_2004', conproc => 'utf8_to_shift_jis_2004' }, +{ oid => '4530', descr => 'conversion for EUC_JIS_2004 to SHIFT_JIS_2004', + conname => 'euc_jis_2004_to_shift_jis_2004', + conforencoding => 'PG_EUC_JIS_2004', contoencoding => 'PG_SHIFT_JIS_2004', + conproc => 'euc_jis_2004_to_shift_jis_2004' }, +{ oid => '4531', descr => 'conversion for SHIFT_JIS_2004 to EUC_JIS_2004', + conname => 'shift_jis_2004_to_euc_jis_2004', + conforencoding => 'PG_SHIFT_JIS_2004', contoencoding => 'PG_EUC_JIS_2004', + conproc => 'shift_jis_2004_to_euc_jis_2004' }, + +] diff --git a/src/include/catalog/pg_conversion.h b/src/include/catalog/pg_conversion.h new file mode 100644 index 0000000..fb26123 --- /dev/null +++ b/src/include/catalog/pg_conversion.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * pg_conversion.h + * definition of the "conversion" system catalog (pg_conversion) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_conversion.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CONVERSION_H +#define PG_CONVERSION_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_conversion_d.h" + +/* ---------------- + * pg_conversion definition. cpp turns this into + * typedef struct FormData_pg_conversion + * ---------------- + */ +CATALOG(pg_conversion,2607,ConversionRelationId) +{ + /* oid */ + Oid oid; + + /* name of the conversion */ + NameData conname; + + /* namespace that the conversion belongs to */ + Oid connamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner of the conversion */ + Oid conowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* FOR encoding id */ + int32 conforencoding BKI_LOOKUP(encoding); + + /* TO encoding id */ + int32 contoencoding BKI_LOOKUP(encoding); + + /* OID of the conversion proc */ + regproc conproc BKI_LOOKUP(pg_proc); + + /* true if this is a default conversion */ + bool condefault BKI_DEFAULT(t); +} FormData_pg_conversion; + +/* ---------------- + * Form_pg_conversion corresponds to a pointer to a tuple with + * the format of pg_conversion relation. + * ---------------- + */ +typedef FormData_pg_conversion *Form_pg_conversion; + +DECLARE_UNIQUE_INDEX(pg_conversion_default_index, 2668, ConversionDefaultIndexId, on pg_conversion using btree(connamespace oid_ops, conforencoding int4_ops, contoencoding int4_ops, oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_conversion_name_nsp_index, 2669, ConversionNameNspIndexId, on pg_conversion using btree(conname name_ops, connamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_conversion_oid_index, 2670, ConversionOidIndexId, on pg_conversion using btree(oid oid_ops)); + + +extern ObjectAddress ConversionCreate(const char *conname, Oid connamespace, + Oid conowner, + int32 conforencoding, int32 contoencoding, + Oid conproc, bool def); +extern Oid FindDefaultConversion(Oid connamespace, int32 for_encoding, + int32 to_encoding); + +#endif /* PG_CONVERSION_H */ diff --git a/src/include/catalog/pg_database.dat b/src/include/catalog/pg_database.dat new file mode 100644 index 0000000..47dcbfb --- /dev/null +++ b/src/include/catalog/pg_database.dat @@ -0,0 +1,23 @@ +#---------------------------------------------------------------------- +# +# pg_database.dat +# Initial contents of the pg_database system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_database.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '1', oid_symbol => 'Template1DbOid', + descr => 'default template for new databases', + datname => 'template1', encoding => 'ENCODING', + datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't', + datallowconn => 't', datconnlimit => '-1', datfrozenxid => '0', + datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE', + datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datacl => '_null_' }, + +] diff --git a/src/include/catalog/pg_database.h b/src/include/catalog/pg_database.h new file mode 100644 index 0000000..48dec14 --- /dev/null +++ b/src/include/catalog/pg_database.h @@ -0,0 +1,121 @@ +/*------------------------------------------------------------------------- + * + * pg_database.h + * definition of the "database" system catalog (pg_database) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_database.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DATABASE_H +#define PG_DATABASE_H + +#include "catalog/genbki.h" +#include "catalog/pg_database_d.h" + +/* ---------------- + * pg_database definition. cpp turns this into + * typedef struct FormData_pg_database + * ---------------- + */ +CATALOG(pg_database,1262,DatabaseRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(1248,DatabaseRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + /* oid */ + Oid oid; + + /* database name */ + NameData datname; + + /* owner of database */ + Oid datdba BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* character encoding */ + int32 encoding; + + /* locale provider, see pg_collation.collprovider */ + char datlocprovider; + + /* allowed as CREATE DATABASE template? */ + bool datistemplate; + + /* new connections allowed? */ + bool datallowconn; + + /* + * Max connections allowed. Negative values have special meaning, see + * DATCONNLIMIT_* defines below. + */ + int32 datconnlimit; + + /* all Xids < this are frozen in this DB */ + TransactionId datfrozenxid; + + /* all multixacts in the DB are >= this */ + TransactionId datminmxid; + + /* default table space for this DB */ + Oid dattablespace BKI_LOOKUP(pg_tablespace); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* LC_COLLATE setting */ + text datcollate BKI_FORCE_NOT_NULL; + + /* LC_CTYPE setting */ + text datctype BKI_FORCE_NOT_NULL; + + /* ICU locale ID */ + text daticulocale; + + /* provider-dependent version of collation data */ + text datcollversion BKI_DEFAULT(_null_); + + /* access permissions */ + aclitem datacl[1]; +#endif +} FormData_pg_database; + +/* ---------------- + * Form_pg_database corresponds to a pointer to a tuple with + * the format of pg_database relation. + * ---------------- + */ +typedef FormData_pg_database *Form_pg_database; + +DECLARE_TOAST_WITH_MACRO(pg_database, 4177, 4178, PgDatabaseToastTable, PgDatabaseToastIndex); + +DECLARE_UNIQUE_INDEX(pg_database_datname_index, 2671, DatabaseNameIndexId, on pg_database using btree(datname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_database_oid_index, 2672, DatabaseOidIndexId, on pg_database using btree(oid oid_ops)); + +/* + * pg_database.dat contains an entry for template1, but not for the template0 + * or postgres databases, because those are created later in initdb. + * However, we still want to manually assign the OIDs for template0 and + * postgres, so declare those here. + */ +DECLARE_OID_DEFINING_MACRO(Template0DbOid, 4); +DECLARE_OID_DEFINING_MACRO(PostgresDbOid, 5); + +/* + * Special values for pg_database.datconnlimit. Normal values are >= 0. + */ +#define DATCONNLIMIT_UNLIMITED -1 /* no limit */ + +/* + * A database is set to invalid partway through being dropped. Using + * datconnlimit=-2 for this purpose isn't particularly clean, but is + * backpatchable. + */ +#define DATCONNLIMIT_INVALID_DB -2 + +extern bool database_is_invalid_form(Form_pg_database datform); +extern bool database_is_invalid_oid(Oid dboid); + +#endif /* PG_DATABASE_H */ diff --git a/src/include/catalog/pg_db_role_setting.h b/src/include/catalog/pg_db_role_setting.h new file mode 100644 index 0000000..45d478e --- /dev/null +++ b/src/include/catalog/pg_db_role_setting.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * pg_db_role_setting.h + * definition of the system catalog for per-database/per-user + * configuration settings (pg_db_role_setting) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_db_role_setting.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DB_ROLE_SETTING_H +#define PG_DB_ROLE_SETTING_H + +#include "catalog/genbki.h" +#include "catalog/pg_db_role_setting_d.h" + +#include "utils/guc.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + +/* ---------------- + * pg_db_role_setting definition. cpp turns this into + * typedef struct FormData_pg_db_role_setting + * ---------------- + */ +CATALOG(pg_db_role_setting,2964,DbRoleSettingRelationId) BKI_SHARED_RELATION +{ + /* database, or 0 for a role-specific setting */ + Oid setdatabase BKI_LOOKUP_OPT(pg_database); + + /* role, or 0 for a database-specific setting */ + Oid setrole BKI_LOOKUP_OPT(pg_authid); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text setconfig[1]; /* GUC settings to apply at login */ +#endif +} FormData_pg_db_role_setting; + +typedef FormData_pg_db_role_setting * Form_pg_db_role_setting; + +DECLARE_TOAST_WITH_MACRO(pg_db_role_setting, 2966, 2967, PgDbRoleSettingToastTable, PgDbRoleSettingToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_db_role_setting_databaseid_rol_index, 2965, DbRoleSettingDatidRolidIndexId, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops)); + +/* + * prototypes for functions in pg_db_role_setting.h + */ +extern void AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt); +extern void DropSetting(Oid databaseid, Oid roleid); +extern void ApplySetting(Snapshot snapshot, Oid databaseid, Oid roleid, + Relation relsetting, GucSource source); + +#endif /* PG_DB_ROLE_SETTING_H */ diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h new file mode 100644 index 0000000..2a79155 --- /dev/null +++ b/src/include/catalog/pg_default_acl.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * pg_default_acl.h + * definition of the system catalog for default ACLs of new objects + * (pg_default_acl) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_default_acl.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DEFAULT_ACL_H +#define PG_DEFAULT_ACL_H + +#include "catalog/genbki.h" +#include "catalog/pg_default_acl_d.h" + +/* ---------------- + * pg_default_acl definition. cpp turns this into + * typedef struct FormData_pg_default_acl + * ---------------- + */ +CATALOG(pg_default_acl,826,DefaultAclRelationId) +{ + Oid oid; /* oid */ + Oid defaclrole BKI_LOOKUP(pg_authid); /* OID of role owning this + * ACL */ + Oid defaclnamespace BKI_LOOKUP_OPT(pg_namespace); /* OID of namespace, or + * 0 for all */ + char defaclobjtype; /* see DEFACLOBJ_xxx constants below */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem defaclacl[1] BKI_FORCE_NOT_NULL; /* permissions to add at + * CREATE time */ +#endif +} FormData_pg_default_acl; + +/* ---------------- + * Form_pg_default_acl corresponds to a pointer to a tuple with + * the format of pg_default_acl relation. + * ---------------- + */ +typedef FormData_pg_default_acl *Form_pg_default_acl; + +DECLARE_TOAST(pg_default_acl, 4143, 4144); + +DECLARE_UNIQUE_INDEX(pg_default_acl_role_nsp_obj_index, 827, DefaultAclRoleNspObjIndexId, on pg_default_acl using btree(defaclrole oid_ops, defaclnamespace oid_ops, defaclobjtype char_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_default_acl_oid_index, 828, DefaultAclOidIndexId, on pg_default_acl using btree(oid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Types of objects for which the user is allowed to specify default + * permissions through pg_default_acl. These codes are used in the + * defaclobjtype column. + */ +#define DEFACLOBJ_RELATION 'r' /* table, view */ +#define DEFACLOBJ_SEQUENCE 'S' /* sequence */ +#define DEFACLOBJ_FUNCTION 'f' /* function */ +#define DEFACLOBJ_TYPE 'T' /* type */ +#define DEFACLOBJ_NAMESPACE 'n' /* namespace */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_DEFAULT_ACL_H */ diff --git a/src/include/catalog/pg_depend.h b/src/include/catalog/pg_depend.h new file mode 100644 index 0000000..2f736ec --- /dev/null +++ b/src/include/catalog/pg_depend.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * pg_depend.h + * definition of the "dependency" system catalog (pg_depend) + * + * pg_depend has no preloaded contents, so there is no pg_depend.dat + * file; dependencies for system-defined objects are loaded into it + * on-the-fly during initdb. Most built-in objects are pinned anyway, + * and hence need no explicit entries in pg_depend. + * + * NOTE: we do not represent all possible dependency pairs in pg_depend; + * for example, there's not much value in creating an explicit dependency + * from an attribute to its relation. Usually we make a dependency for + * cases where the relationship is conditional rather than essential + * (for example, not all triggers are dependent on constraints, but all + * attributes are dependent on relations) or where the dependency is not + * convenient to find from the contents of other catalogs. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_depend.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DEPEND_H +#define PG_DEPEND_H + +#include "catalog/genbki.h" +#include "catalog/pg_depend_d.h" + +/* ---------------- + * pg_depend definition. cpp turns this into + * typedef struct FormData_pg_depend + * ---------------- + */ +CATALOG(pg_depend,2608,DependRelationId) +{ + /* + * Identification of the dependent (referencing) object. + */ + Oid classid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ + Oid objid; /* OID of object itself */ + int32 objsubid; /* column number, or 0 if not used */ + + /* + * Identification of the independent (referenced) object. + */ + Oid refclassid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ + Oid refobjid; /* OID of object itself */ + int32 refobjsubid; /* column number, or 0 if not used */ + + /* + * Precise semantics of the relationship are specified by the deptype + * field. See DependencyType in catalog/dependency.h. + */ + char deptype; /* see codes in dependency.h */ +} FormData_pg_depend; + +/* ---------------- + * Form_pg_depend corresponds to a pointer to a row with + * the format of pg_depend relation. + * ---------------- + */ +typedef FormData_pg_depend *Form_pg_depend; + +DECLARE_INDEX(pg_depend_depender_index, 2673, DependDependerIndexId, on pg_depend using btree(classid oid_ops, objid oid_ops, objsubid int4_ops)); +DECLARE_INDEX(pg_depend_reference_index, 2674, DependReferenceIndexId, on pg_depend using btree(refclassid oid_ops, refobjid oid_ops, refobjsubid int4_ops)); + +#endif /* PG_DEPEND_H */ diff --git a/src/include/catalog/pg_description.h b/src/include/catalog/pg_description.h new file mode 100644 index 0000000..67636ba --- /dev/null +++ b/src/include/catalog/pg_description.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * pg_description.h + * definition of the "description" system catalog (pg_description) + * + * Because the contents of this table are taken from the *.dat files + * of other catalogs, there is no pg_description.dat file. The initial + * contents are assembled by genbki.pl and loaded during initdb. + * + * NOTE: an object is identified by the OID of the row that primarily + * defines the object, plus the OID of the table that that row appears in. + * For example, a function is identified by the OID of its pg_proc row + * plus the pg_class OID of table pg_proc. This allows unique identification + * of objects without assuming that OIDs are unique across tables. + * + * Since attributes don't have OIDs of their own, we identify an attribute + * comment by the objoid+classoid of its parent table, plus an "objsubid" + * giving the attribute column number. "objsubid" must be zero in a comment + * for a table itself, so that it is distinct from any column comment. + * Currently, objsubid is unused and zero for all other kinds of objects, + * but perhaps it might be useful someday to associate comments with + * constituent elements of other kinds of objects (arguments of a function, + * for example). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_description.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_DESCRIPTION_H +#define PG_DESCRIPTION_H + +#include "catalog/genbki.h" +#include "catalog/pg_description_d.h" + +/* ---------------- + * pg_description definition. cpp turns this into + * typedef struct FormData_pg_description + * ---------------- + */ +CATALOG(pg_description,2609,DescriptionRelationId) +{ + Oid objoid; /* OID of object itself */ + Oid classoid; /* OID of table containing object */ + int32 objsubid; /* column number, or 0 if not used */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text description BKI_FORCE_NOT_NULL; /* description of object */ +#endif +} FormData_pg_description; + +/* ---------------- + * Form_pg_description corresponds to a pointer to a tuple with + * the format of pg_description relation. + * ---------------- + */ +typedef FormData_pg_description * Form_pg_description; + +DECLARE_TOAST(pg_description, 2834, 2835); + +DECLARE_UNIQUE_INDEX_PKEY(pg_description_o_c_o_index, 2675, DescriptionObjIndexId, on pg_description using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); + +/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */ +DECLARE_FOREIGN_KEY((classoid), pg_class, (oid)); + +#endif /* PG_DESCRIPTION_H */ diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h new file mode 100644 index 0000000..9c6dedd --- /dev/null +++ b/src/include/catalog/pg_enum.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * pg_enum.h + * definition of the "enum" system catalog (pg_enum) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_enum.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_ENUM_H +#define PG_ENUM_H + +#include "catalog/genbki.h" +#include "catalog/pg_enum_d.h" + +#include "nodes/pg_list.h" + +/* ---------------- + * pg_enum definition. cpp turns this into + * typedef struct FormData_pg_enum + * ---------------- + */ +CATALOG(pg_enum,3501,EnumRelationId) +{ + Oid oid; /* oid */ + Oid enumtypid BKI_LOOKUP(pg_type); /* OID of owning enum type */ + float4 enumsortorder; /* sort position of this enum value */ + NameData enumlabel; /* text representation of enum value */ +} FormData_pg_enum; + +/* ---------------- + * Form_pg_enum corresponds to a pointer to a tuple with + * the format of pg_enum relation. + * ---------------- + */ +typedef FormData_pg_enum *Form_pg_enum; + +DECLARE_UNIQUE_INDEX_PKEY(pg_enum_oid_index, 3502, EnumOidIndexId, on pg_enum using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_enum_typid_label_index, 3503, EnumTypIdLabelIndexId, on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops)); +DECLARE_UNIQUE_INDEX(pg_enum_typid_sortorder_index, 3534, EnumTypIdSortOrderIndexId, on pg_enum using btree(enumtypid oid_ops, enumsortorder float4_ops)); + +/* + * prototypes for functions in pg_enum.c + */ +extern void EnumValuesCreate(Oid enumTypeOid, List *vals); +extern void EnumValuesDelete(Oid enumTypeOid); +extern void AddEnumLabel(Oid enumTypeOid, const char *newVal, + const char *neighbor, bool newValIsAfter, + bool skipIfExists); +extern void RenameEnumLabel(Oid enumTypeOid, + const char *oldVal, const char *newVal); +extern bool EnumUncommitted(Oid enum_id); +extern Size EstimateUncommittedEnumsSpace(void); +extern void SerializeUncommittedEnums(void *space, Size size); +extern void RestoreUncommittedEnums(void *space); +extern void AtEOXact_Enum(void); + +#endif /* PG_ENUM_H */ diff --git a/src/include/catalog/pg_event_trigger.h b/src/include/catalog/pg_event_trigger.h new file mode 100644 index 0000000..3fe0e8d --- /dev/null +++ b/src/include/catalog/pg_event_trigger.h @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * pg_event_trigger.h + * definition of the "event trigger" system catalog (pg_event_trigger) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_event_trigger.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_EVENT_TRIGGER_H +#define PG_EVENT_TRIGGER_H + +#include "catalog/genbki.h" +#include "catalog/pg_event_trigger_d.h" + +/* ---------------- + * pg_event_trigger definition. cpp turns this into + * typedef struct FormData_pg_event_trigger + * ---------------- + */ +CATALOG(pg_event_trigger,3466,EventTriggerRelationId) +{ + Oid oid; /* oid */ + NameData evtname; /* trigger's name */ + NameData evtevent; /* trigger's event */ + Oid evtowner BKI_LOOKUP(pg_authid); /* trigger's owner */ + Oid evtfoid BKI_LOOKUP(pg_proc); /* OID of function to be + * called */ + char evtenabled; /* trigger's firing configuration WRT + * session_replication_role */ + +#ifdef CATALOG_VARLEN + text evttags[1]; /* command TAGs this event trigger targets */ +#endif +} FormData_pg_event_trigger; + +/* ---------------- + * Form_pg_event_trigger corresponds to a pointer to a tuple with + * the format of pg_event_trigger relation. + * ---------------- + */ +typedef FormData_pg_event_trigger *Form_pg_event_trigger; + +DECLARE_TOAST(pg_event_trigger, 4145, 4146); + +DECLARE_UNIQUE_INDEX(pg_event_trigger_evtname_index, 3467, EventTriggerNameIndexId, on pg_event_trigger using btree(evtname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_event_trigger_oid_index, 3468, EventTriggerOidIndexId, on pg_event_trigger using btree(oid oid_ops)); + +#endif /* PG_EVENT_TRIGGER_H */ diff --git a/src/include/catalog/pg_extension.h b/src/include/catalog/pg_extension.h new file mode 100644 index 0000000..43d16d4 --- /dev/null +++ b/src/include/catalog/pg_extension.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * pg_extension.h + * definition of the "extension" system catalog (pg_extension) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_extension.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_EXTENSION_H +#define PG_EXTENSION_H + +#include "catalog/genbki.h" +#include "catalog/pg_extension_d.h" + +/* ---------------- + * pg_extension definition. cpp turns this into + * typedef struct FormData_pg_extension + * ---------------- + */ +CATALOG(pg_extension,3079,ExtensionRelationId) +{ + Oid oid; /* oid */ + NameData extname; /* extension name */ + Oid extowner BKI_LOOKUP(pg_authid); /* extension owner */ + Oid extnamespace BKI_LOOKUP(pg_namespace); /* namespace of + * contained objects */ + bool extrelocatable; /* if true, allow ALTER EXTENSION SET SCHEMA */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* extversion may never be null, but the others can be. */ + text extversion BKI_FORCE_NOT_NULL; /* extension version name */ + Oid extconfig[1] BKI_LOOKUP(pg_class); /* dumpable configuration + * tables */ + text extcondition[1]; /* WHERE clauses for config tables */ +#endif +} FormData_pg_extension; + +/* ---------------- + * Form_pg_extension corresponds to a pointer to a tuple with + * the format of pg_extension relation. + * ---------------- + */ +typedef FormData_pg_extension *Form_pg_extension; + +DECLARE_TOAST(pg_extension, 4147, 4148); + +DECLARE_UNIQUE_INDEX_PKEY(pg_extension_oid_index, 3080, ExtensionOidIndexId, on pg_extension using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, ExtensionNameIndexId, on pg_extension using btree(extname name_ops)); + +#endif /* PG_EXTENSION_H */ diff --git a/src/include/catalog/pg_foreign_data_wrapper.h b/src/include/catalog/pg_foreign_data_wrapper.h new file mode 100644 index 0000000..86db654 --- /dev/null +++ b/src/include/catalog/pg_foreign_data_wrapper.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_data_wrapper.h + * definition of the "foreign-data wrapper" system catalog (pg_foreign_data_wrapper) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_foreign_data_wrapper.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_DATA_WRAPPER_H +#define PG_FOREIGN_DATA_WRAPPER_H + +#include "catalog/genbki.h" +#include "catalog/pg_foreign_data_wrapper_d.h" + +/* ---------------- + * pg_foreign_data_wrapper definition. cpp turns this into + * typedef struct FormData_pg_foreign_data_wrapper + * ---------------- + */ +CATALOG(pg_foreign_data_wrapper,2328,ForeignDataWrapperRelationId) +{ + Oid oid; /* oid */ + NameData fdwname; /* foreign-data wrapper name */ + Oid fdwowner BKI_LOOKUP(pg_authid); /* FDW owner */ + Oid fdwhandler BKI_LOOKUP_OPT(pg_proc); /* handler function, or 0 + * if none */ + Oid fdwvalidator BKI_LOOKUP_OPT(pg_proc); /* option validation + * function, or 0 if + * none */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem fdwacl[1]; /* access permissions */ + text fdwoptions[1]; /* FDW options */ +#endif +} FormData_pg_foreign_data_wrapper; + +/* ---------------- + * Form_pg_foreign_data_wrapper corresponds to a pointer to a tuple with + * the format of pg_foreign_data_wrapper relation. + * ---------------- + */ +typedef FormData_pg_foreign_data_wrapper *Form_pg_foreign_data_wrapper; + +DECLARE_TOAST(pg_foreign_data_wrapper, 4149, 4150); + +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_data_wrapper_oid_index, 112, ForeignDataWrapperOidIndexId, on pg_foreign_data_wrapper using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_name_index, 548, ForeignDataWrapperNameIndexId, on pg_foreign_data_wrapper using btree(fdwname name_ops)); + +#endif /* PG_FOREIGN_DATA_WRAPPER_H */ diff --git a/src/include/catalog/pg_foreign_server.h b/src/include/catalog/pg_foreign_server.h new file mode 100644 index 0000000..dcef33d --- /dev/null +++ b/src/include/catalog/pg_foreign_server.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_server.h + * definition of the "foreign server" system catalog (pg_foreign_server) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_foreign_server.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_SERVER_H +#define PG_FOREIGN_SERVER_H + +#include "catalog/genbki.h" +#include "catalog/pg_foreign_server_d.h" + +/* ---------------- + * pg_foreign_server definition. cpp turns this into + * typedef struct FormData_pg_foreign_server + * ---------------- + */ +CATALOG(pg_foreign_server,1417,ForeignServerRelationId) +{ + Oid oid; /* oid */ + NameData srvname; /* foreign server name */ + Oid srvowner BKI_LOOKUP(pg_authid); /* server owner */ + Oid srvfdw BKI_LOOKUP(pg_foreign_data_wrapper); /* server FDW */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text srvtype; + text srvversion; + aclitem srvacl[1]; /* access permissions */ + text srvoptions[1]; /* FDW-specific options */ +#endif +} FormData_pg_foreign_server; + +/* ---------------- + * Form_pg_foreign_server corresponds to a pointer to a tuple with + * the format of pg_foreign_server relation. + * ---------------- + */ +typedef FormData_pg_foreign_server *Form_pg_foreign_server; + +DECLARE_TOAST(pg_foreign_server, 4151, 4152); + +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_server_oid_index, 113, ForeignServerOidIndexId, on pg_foreign_server using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_foreign_server_name_index, 549, ForeignServerNameIndexId, on pg_foreign_server using btree(srvname name_ops)); + +#endif /* PG_FOREIGN_SERVER_H */ diff --git a/src/include/catalog/pg_foreign_table.h b/src/include/catalog/pg_foreign_table.h new file mode 100644 index 0000000..88753cd --- /dev/null +++ b/src/include/catalog/pg_foreign_table.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * pg_foreign_table.h + * definition of the "foreign table" system catalog (pg_foreign_table) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_foreign_table.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_FOREIGN_TABLE_H +#define PG_FOREIGN_TABLE_H + +#include "catalog/genbki.h" +#include "catalog/pg_foreign_table_d.h" + +/* ---------------- + * pg_foreign_table definition. cpp turns this into + * typedef struct FormData_pg_foreign_table + * ---------------- + */ +CATALOG(pg_foreign_table,3118,ForeignTableRelationId) +{ + Oid ftrelid BKI_LOOKUP(pg_class); /* OID of foreign table */ + Oid ftserver BKI_LOOKUP(pg_foreign_server); /* OID of foreign server */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text ftoptions[1]; /* FDW-specific options */ +#endif +} FormData_pg_foreign_table; + +/* ---------------- + * Form_pg_foreign_table corresponds to a pointer to a tuple with + * the format of pg_foreign_table relation. + * ---------------- + */ +typedef FormData_pg_foreign_table *Form_pg_foreign_table; + +DECLARE_TOAST(pg_foreign_table, 4153, 4154); + +DECLARE_UNIQUE_INDEX_PKEY(pg_foreign_table_relid_index, 3119, ForeignTableRelidIndexId, on pg_foreign_table using btree(ftrelid oid_ops)); + +#endif /* PG_FOREIGN_TABLE_H */ diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h new file mode 100644 index 0000000..f853846 --- /dev/null +++ b/src/include/catalog/pg_index.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * pg_index.h + * definition of the "index" system catalog (pg_index) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_index.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INDEX_H +#define PG_INDEX_H + +#include "catalog/genbki.h" +#include "catalog/pg_index_d.h" + +/* ---------------- + * pg_index definition. cpp turns this into + * typedef struct FormData_pg_index. + * ---------------- + */ +CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO +{ + Oid indexrelid BKI_LOOKUP(pg_class); /* OID of the index */ + Oid indrelid BKI_LOOKUP(pg_class); /* OID of the relation it + * indexes */ + int16 indnatts; /* total number of columns in index */ + int16 indnkeyatts; /* number of key columns in index */ + bool indisunique; /* is this a unique index? */ + bool indnullsnotdistinct; /* null treatment in unique index */ + bool indisprimary; /* is this index for primary key? */ + bool indisexclusion; /* is this index for exclusion constraint? */ + bool indimmediate; /* is uniqueness enforced immediately? */ + bool indisclustered; /* is this the index last clustered by? */ + bool indisvalid; /* is this index valid for use by queries? */ + bool indcheckxmin; /* must we wait for xmin to be old? */ + bool indisready; /* is this index ready for inserts? */ + bool indislive; /* is this index alive at all? */ + bool indisreplident; /* is this index the identity for replication? */ + + /* variable-length fields start here, but we allow direct access to indkey */ + int2vector indkey BKI_FORCE_NOT_NULL; /* column numbers of indexed cols, + * or 0 */ + +#ifdef CATALOG_VARLEN + oidvector indcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL; /* collation identifiers */ + oidvector indclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* opclass identifiers */ + int2vector indoption BKI_FORCE_NOT_NULL; /* per-column flags + * (AM-specific meanings) */ + pg_node_tree indexprs; /* expression trees for index attributes that + * are not simple column references; one for + * each zero entry in indkey[] */ + pg_node_tree indpred; /* expression tree for predicate, if a partial + * index; else NULL */ +#endif +} FormData_pg_index; + +/* ---------------- + * Form_pg_index corresponds to a pointer to a tuple with + * the format of pg_index relation. + * ---------------- + */ +typedef FormData_pg_index *Form_pg_index; + +DECLARE_INDEX(pg_index_indrelid_index, 2678, IndexIndrelidIndexId, on pg_index using btree(indrelid oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_index_indexrelid_index, 2679, IndexRelidIndexId, on pg_index using btree(indexrelid oid_ops)); + +/* indkey can contain zero (InvalidAttrNumber) to represent expressions */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((indrelid, indkey), pg_attribute, (attrelid, attnum)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Index AMs that support ordered scans must support these two indoption + * bits. Otherwise, the content of the per-column indoption fields is + * open for future definition. + */ +#define INDOPTION_DESC 0x0001 /* values are in reverse order */ +#define INDOPTION_NULLS_FIRST 0x0002 /* NULLs are first instead of last */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_INDEX_H */ diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h new file mode 100644 index 0000000..b5a3275 --- /dev/null +++ b/src/include/catalog/pg_inherits.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * pg_inherits.h + * definition of the "inherits" system catalog (pg_inherits) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_inherits.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INHERITS_H +#define PG_INHERITS_H + +#include "catalog/genbki.h" +#include "catalog/pg_inherits_d.h" + +#include "nodes/pg_list.h" +#include "storage/lock.h" + +/* ---------------- + * pg_inherits definition. cpp turns this into + * typedef struct FormData_pg_inherits + * ---------------- + */ +CATALOG(pg_inherits,2611,InheritsRelationId) +{ + Oid inhrelid BKI_LOOKUP(pg_class); + Oid inhparent BKI_LOOKUP(pg_class); + int32 inhseqno; + bool inhdetachpending; +} FormData_pg_inherits; + +/* ---------------- + * Form_pg_inherits corresponds to a pointer to a tuple with + * the format of pg_inherits relation. + * ---------------- + */ +typedef FormData_pg_inherits *Form_pg_inherits; + +DECLARE_UNIQUE_INDEX_PKEY(pg_inherits_relid_seqno_index, 2680, InheritsRelidSeqnoIndexId, on pg_inherits using btree(inhrelid oid_ops, inhseqno int4_ops)); +DECLARE_INDEX(pg_inherits_parent_index, 2187, InheritsParentIndexId, on pg_inherits using btree(inhparent oid_ops)); + + +extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode); +extern List *find_inheritance_children_extended(Oid parentrelId, bool omit_detached, + LOCKMODE lockmode, bool *detached_exist, TransactionId *detached_xmin); + +extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, + List **parents); +extern bool has_subclass(Oid relationId); +extern bool has_superclass(Oid relationId); +extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId); +extern void StoreSingleInheritance(Oid relationId, Oid parentOid, + int32 seqNumber); +extern bool DeleteInheritsTuple(Oid inhrelid, Oid inhparent, bool allow_detached, + const char *childname); +extern bool PartitionHasPendingDetach(Oid partoid); + +#endif /* PG_INHERITS_H */ diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h new file mode 100644 index 0000000..c226edc --- /dev/null +++ b/src/include/catalog/pg_init_privs.h @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------- + * + * pg_init_privs.h + * definition of the "initial privileges" system catalog (pg_init_privs) + * + * NOTE: an object is identified by the OID of the row that primarily + * defines the object, plus the OID of the table that that row appears in. + * For example, a function is identified by the OID of its pg_proc row + * plus the pg_class OID of table pg_proc. This allows unique identification + * of objects without assuming that OIDs are unique across tables. + * + * Since attributes don't have OIDs of their own, we identify an attribute + * privilege by the objoid+classoid of its parent table, plus an "objsubid" + * giving the attribute column number. "objsubid" must be zero in a privilege + * for a table itself, so that it is distinct from any column privilege. + * Currently, objsubid is unused and zero for all other kinds of objects. + * + * Because the contents of this table depend on what is done with the other + * objects in the system (and, in particular, may change due to changes in + * system_views.sql), there is no pg_init_privs.dat file. The initial contents + * are loaded near the end of initdb. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_init_privs.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INIT_PRIVS_H +#define PG_INIT_PRIVS_H + +#include "catalog/genbki.h" +#include "catalog/pg_init_privs_d.h" + +/* ---------------- + * pg_init_privs definition. cpp turns this into + * typedef struct FormData_pg_init_privs + * ---------------- + */ +CATALOG(pg_init_privs,3394,InitPrivsRelationId) +{ + Oid objoid; /* OID of object itself */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ + int32 objsubid; /* column number, or 0 if not used */ + char privtype; /* from initdb or extension? */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem initprivs[1] BKI_FORCE_NOT_NULL; /* initial privs on object */ +#endif +} FormData_pg_init_privs; + +/* ---------------- + * Form_pg_init_privs corresponds to a pointer to a tuple with + * the format of pg_init_privs relation. + * ---------------- + */ +typedef FormData_pg_init_privs * Form_pg_init_privs; + +DECLARE_TOAST(pg_init_privs, 4155, 4156); + +DECLARE_UNIQUE_INDEX_PKEY(pg_init_privs_o_c_o_index, 3395, InitPrivsObjIndexId, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); + +/* + * It is important to know if the initial privileges are from initdb or from an + * extension. This enum is used to provide that differentiation and the two + * places which populate this table (initdb and during CREATE EXTENSION, see + * recordExtensionInitPriv()) know to use the correct values. + */ + +typedef enum InitPrivsType +{ + INITPRIVS_INITDB = 'i', + INITPRIVS_EXTENSION = 'e' +} InitPrivsType; + +#endif /* PG_INIT_PRIVS_H */ diff --git a/src/include/catalog/pg_language.dat b/src/include/catalog/pg_language.dat new file mode 100644 index 0000000..1663c96 --- /dev/null +++ b/src/include/catalog/pg_language.dat @@ -0,0 +1,25 @@ +#---------------------------------------------------------------------- +# +# pg_language.dat +# Initial contents of the pg_language system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_language.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '12', oid_symbol => 'INTERNALlanguageId', + descr => 'built-in functions', + lanname => 'internal', lanvalidator => 'fmgr_internal_validator' }, +{ oid => '13', oid_symbol => 'ClanguageId', + descr => 'dynamically-loaded C functions', + lanname => 'c', lanvalidator => 'fmgr_c_validator' }, +{ oid => '14', oid_symbol => 'SQLlanguageId', + descr => 'SQL-language functions', + lanname => 'sql', lanpltrusted => 't', lanvalidator => 'fmgr_sql_validator' }, + +] diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h new file mode 100644 index 0000000..4b9c259 --- /dev/null +++ b/src/include/catalog/pg_language.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * pg_language.h + * definition of the "language" system catalog (pg_language) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_language.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LANGUAGE_H +#define PG_LANGUAGE_H + +#include "catalog/genbki.h" +#include "catalog/pg_language_d.h" + +/* ---------------- + * pg_language definition. cpp turns this into + * typedef struct FormData_pg_language + * ---------------- + */ +CATALOG(pg_language,2612,LanguageRelationId) +{ + Oid oid; /* oid */ + + /* Language name */ + NameData lanname; + + /* Language's owner */ + Oid lanowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* Is a procedural language */ + bool lanispl BKI_DEFAULT(f); + + /* PL is trusted */ + bool lanpltrusted BKI_DEFAULT(f); + + /* Call handler, if it's a PL */ + Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); + + /* Optional anonymous-block handler function */ + Oid laninline BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); + + /* Optional validation function */ + Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* Access privileges */ + aclitem lanacl[1] BKI_DEFAULT(_null_); +#endif +} FormData_pg_language; + +/* ---------------- + * Form_pg_language corresponds to a pointer to a tuple with + * the format of pg_language relation. + * ---------------- + */ +typedef FormData_pg_language *Form_pg_language; + +DECLARE_TOAST(pg_language, 4157, 4158); + +DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, LanguageNameIndexId, on pg_language using btree(lanname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_language_oid_index, 2682, LanguageOidIndexId, on pg_language using btree(oid oid_ops)); + +#endif /* PG_LANGUAGE_H */ diff --git a/src/include/catalog/pg_largeobject.h b/src/include/catalog/pg_largeobject.h new file mode 100644 index 0000000..1fd076d --- /dev/null +++ b/src/include/catalog/pg_largeobject.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * pg_largeobject.h + * definition of the "large object" system catalog (pg_largeobject) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_largeobject.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LARGEOBJECT_H +#define PG_LARGEOBJECT_H + +#include "catalog/genbki.h" +#include "catalog/pg_largeobject_d.h" + +/* ---------------- + * pg_largeobject definition. cpp turns this into + * typedef struct FormData_pg_largeobject + * ---------------- + */ +CATALOG(pg_largeobject,2613,LargeObjectRelationId) +{ + Oid loid BKI_LOOKUP(pg_largeobject_metadata); /* Identifier of large + * object */ + int32 pageno; /* Page number (starting from 0) */ + + /* data has variable length, but we allow direct access; see inv_api.c */ + bytea data BKI_FORCE_NOT_NULL; /* Data for page (may be + * zero-length) */ +} FormData_pg_largeobject; + +/* ---------------- + * Form_pg_largeobject corresponds to a pointer to a tuple with + * the format of pg_largeobject relation. + * ---------------- + */ +typedef FormData_pg_largeobject *Form_pg_largeobject; + +DECLARE_UNIQUE_INDEX_PKEY(pg_largeobject_loid_pn_index, 2683, LargeObjectLOidPNIndexId, on pg_largeobject using btree(loid oid_ops, pageno int4_ops)); + +extern Oid LargeObjectCreate(Oid loid); +extern void LargeObjectDrop(Oid loid); +extern bool LargeObjectExists(Oid loid); + +#endif /* PG_LARGEOBJECT_H */ diff --git a/src/include/catalog/pg_largeobject_metadata.h b/src/include/catalog/pg_largeobject_metadata.h new file mode 100644 index 0000000..ec1c3bf --- /dev/null +++ b/src/include/catalog/pg_largeobject_metadata.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * pg_largeobject_metadata.h + * definition of the "large object metadata" system catalog + * (pg_largeobject_metadata) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_largeobject_metadata.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LARGEOBJECT_METADATA_H +#define PG_LARGEOBJECT_METADATA_H + +#include "catalog/genbki.h" +#include "catalog/pg_largeobject_metadata_d.h" + +/* ---------------- + * pg_largeobject_metadata definition. cpp turns this into + * typedef struct FormData_pg_largeobject_metadata + * ---------------- + */ +CATALOG(pg_largeobject_metadata,2995,LargeObjectMetadataRelationId) +{ + Oid oid; /* oid */ + + Oid lomowner BKI_LOOKUP(pg_authid); /* OID of the largeobject + * owner */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem lomacl[1]; /* access permissions */ +#endif +} FormData_pg_largeobject_metadata; + +/* ---------------- + * Form_pg_largeobject_metadata corresponds to a pointer to a tuple + * with the format of pg_largeobject_metadata relation. + * ---------------- + */ +typedef FormData_pg_largeobject_metadata *Form_pg_largeobject_metadata; + +DECLARE_UNIQUE_INDEX_PKEY(pg_largeobject_metadata_oid_index, 2996, LargeObjectMetadataOidIndexId, on pg_largeobject_metadata using btree(oid oid_ops)); + +#endif /* PG_LARGEOBJECT_METADATA_H */ diff --git a/src/include/catalog/pg_namespace.dat b/src/include/catalog/pg_namespace.dat new file mode 100644 index 0000000..9f1d27c --- /dev/null +++ b/src/include/catalog/pg_namespace.dat @@ -0,0 +1,26 @@ +#---------------------------------------------------------------------- +# +# pg_namespace.dat +# Initial contents of the pg_namespace system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_namespace.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '11', oid_symbol => 'PG_CATALOG_NAMESPACE', + descr => 'system catalog schema', + nspname => 'pg_catalog', nspacl => '_null_' }, +{ oid => '99', oid_symbol => 'PG_TOAST_NAMESPACE', + descr => 'reserved schema for TOAST tables', + nspname => 'pg_toast', nspacl => '_null_' }, +# update dumpNamespace() if changing this descr +{ oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE', + descr => 'standard public schema', + nspname => 'public', nspowner => 'pg_database_owner', nspacl => '_null_' }, + +] diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h new file mode 100644 index 0000000..ba56e44 --- /dev/null +++ b/src/include/catalog/pg_namespace.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * pg_namespace.h + * definition of the "namespace" system catalog (pg_namespace) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_namespace.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_NAMESPACE_H +#define PG_NAMESPACE_H + +#include "catalog/genbki.h" +#include "catalog/pg_namespace_d.h" +#include "utils/acl.h" + +/* ---------------------------------------------------------------- + * pg_namespace definition. + * + * cpp turns this into typedef struct FormData_pg_namespace + * + * nspname name of the namespace + * nspowner owner (creator) of the namespace + * nspacl access privilege list + * ---------------------------------------------------------------- + */ +CATALOG(pg_namespace,2615,NamespaceRelationId) +{ + Oid oid; /* oid */ + + NameData nspname; + Oid nspowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem nspacl[1]; +#endif +} FormData_pg_namespace; + +/* ---------------- + * Form_pg_namespace corresponds to a pointer to a tuple with + * the format of pg_namespace relation. + * ---------------- + */ +typedef FormData_pg_namespace *Form_pg_namespace; + +DECLARE_TOAST(pg_namespace, 4163, 4164); + +DECLARE_UNIQUE_INDEX(pg_namespace_nspname_index, 2684, NamespaceNameIndexId, on pg_namespace using btree(nspname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_namespace_oid_index, 2685, NamespaceOidIndexId, on pg_namespace using btree(oid oid_ops)); + +/* + * prototypes for functions in pg_namespace.c + */ +extern Oid NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp); + +#endif /* PG_NAMESPACE_H */ diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat new file mode 100644 index 0000000..dbcae7f --- /dev/null +++ b/src/include/catalog/pg_opclass.dat @@ -0,0 +1,488 @@ +#---------------------------------------------------------------------- +# +# pg_opclass.dat +# Initial contents of the pg_opclass system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_opclass.dat +# +#---------------------------------------------------------------------- + +[ + +# Note: we hard-wire an OID only for a few entries that have to be explicitly +# referenced in the C code or in built-in catalog entries. The rest get OIDs +# assigned on-the-fly during initdb. + +{ opcmethod => 'btree', opcname => 'array_ops', opcfamily => 'btree/array_ops', + opcintype => 'anyarray' }, +{ opcmethod => 'hash', opcname => 'array_ops', opcfamily => 'hash/array_ops', + opcintype => 'anyarray' }, +{ opcmethod => 'btree', opcname => 'bit_ops', opcfamily => 'btree/bit_ops', + opcintype => 'bit' }, +{ opcmethod => 'btree', opcname => 'bool_ops', opcfamily => 'btree/bool_ops', + opcintype => 'bool' }, +{ opcmethod => 'btree', opcname => 'bpchar_ops', + opcfamily => 'btree/bpchar_ops', opcintype => 'bpchar' }, +{ opcmethod => 'hash', opcname => 'bpchar_ops', opcfamily => 'hash/bpchar_ops', + opcintype => 'bpchar' }, +{ opcmethod => 'btree', opcname => 'bytea_ops', opcfamily => 'btree/bytea_ops', + opcintype => 'bytea' }, +{ opcmethod => 'btree', opcname => 'char_ops', opcfamily => 'btree/char_ops', + opcintype => 'char' }, +{ opcmethod => 'hash', opcname => 'char_ops', opcfamily => 'hash/char_ops', + opcintype => 'char' }, +{ opcmethod => 'btree', opcname => 'cidr_ops', opcfamily => 'btree/network_ops', + opcintype => 'inet', opcdefault => 'f' }, +{ opcmethod => 'hash', opcname => 'cidr_ops', opcfamily => 'hash/network_ops', + opcintype => 'inet', opcdefault => 'f' }, +{ oid => '3122', oid_symbol => 'DATE_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'date_ops', + opcfamily => 'btree/datetime_ops', opcintype => 'date' }, +{ opcmethod => 'hash', opcname => 'date_ops', opcfamily => 'hash/date_ops', + opcintype => 'date' }, +{ opcmethod => 'btree', opcname => 'float4_ops', opcfamily => 'btree/float_ops', + opcintype => 'float4' }, +{ opcmethod => 'hash', opcname => 'float4_ops', opcfamily => 'hash/float_ops', + opcintype => 'float4' }, +{ oid => '3123', oid_symbol => 'FLOAT8_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'float8_ops', opcfamily => 'btree/float_ops', + opcintype => 'float8' }, +{ opcmethod => 'hash', opcname => 'float8_ops', opcfamily => 'hash/float_ops', + opcintype => 'float8' }, +{ opcmethod => 'btree', opcname => 'inet_ops', opcfamily => 'btree/network_ops', + opcintype => 'inet' }, +{ opcmethod => 'hash', opcname => 'inet_ops', opcfamily => 'hash/network_ops', + opcintype => 'inet' }, +{ opcmethod => 'gist', opcname => 'inet_ops', opcfamily => 'gist/network_ops', + opcintype => 'inet', opcdefault => 'f' }, +{ opcmethod => 'spgist', opcname => 'inet_ops', + opcfamily => 'spgist/network_ops', opcintype => 'inet' }, +{ oid => '1979', oid_symbol => 'INT2_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'int2_ops', opcfamily => 'btree/integer_ops', + opcintype => 'int2' }, +{ opcmethod => 'hash', opcname => 'int2_ops', opcfamily => 'hash/integer_ops', + opcintype => 'int2' }, +{ oid => '1978', oid_symbol => 'INT4_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'int4_ops', opcfamily => 'btree/integer_ops', + opcintype => 'int4' }, +{ opcmethod => 'hash', opcname => 'int4_ops', opcfamily => 'hash/integer_ops', + opcintype => 'int4' }, +{ oid => '3124', oid_symbol => 'INT8_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'int8_ops', opcfamily => 'btree/integer_ops', + opcintype => 'int8' }, +{ opcmethod => 'hash', opcname => 'int8_ops', opcfamily => 'hash/integer_ops', + opcintype => 'int8' }, +{ opcmethod => 'btree', opcname => 'interval_ops', + opcfamily => 'btree/interval_ops', opcintype => 'interval' }, +{ opcmethod => 'hash', opcname => 'interval_ops', + opcfamily => 'hash/interval_ops', opcintype => 'interval' }, +{ opcmethod => 'btree', opcname => 'macaddr_ops', + opcfamily => 'btree/macaddr_ops', opcintype => 'macaddr' }, +{ opcmethod => 'hash', opcname => 'macaddr_ops', + opcfamily => 'hash/macaddr_ops', opcintype => 'macaddr' }, +{ opcmethod => 'btree', opcname => 'macaddr8_ops', + opcfamily => 'btree/macaddr8_ops', opcintype => 'macaddr8' }, +{ opcmethod => 'hash', opcname => 'macaddr8_ops', + opcfamily => 'hash/macaddr8_ops', opcintype => 'macaddr8' }, + +# Here's an ugly little hack to save space in the system catalog indexes. +# btree doesn't ordinarily allow a storage type different from input type; +# but cstring and name are the same thing except for trailing padding, +# and we can safely omit that within an index entry. So we declare the +# btree opclass for name as using cstring storage type. +{ opcmethod => 'btree', opcname => 'name_ops', opcfamily => 'btree/text_ops', + opcintype => 'name', opckeytype => 'cstring' }, + +{ opcmethod => 'hash', opcname => 'name_ops', opcfamily => 'hash/text_ops', + opcintype => 'name' }, +{ oid => '3125', oid_symbol => 'NUMERIC_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'numeric_ops', + opcfamily => 'btree/numeric_ops', opcintype => 'numeric' }, +{ opcmethod => 'hash', opcname => 'numeric_ops', + opcfamily => 'hash/numeric_ops', opcintype => 'numeric' }, +{ oid => '1981', oid_symbol => 'OID_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'oid_ops', opcfamily => 'btree/oid_ops', + opcintype => 'oid' }, +{ opcmethod => 'hash', opcname => 'oid_ops', opcfamily => 'hash/oid_ops', + opcintype => 'oid' }, +{ opcmethod => 'btree', opcname => 'oidvector_ops', + opcfamily => 'btree/oidvector_ops', opcintype => 'oidvector' }, +{ opcmethod => 'hash', opcname => 'oidvector_ops', + opcfamily => 'hash/oidvector_ops', opcintype => 'oidvector' }, +{ opcmethod => 'btree', opcname => 'record_ops', + opcfamily => 'btree/record_ops', opcintype => 'record' }, +{ opcmethod => 'hash', opcname => 'record_ops', opcfamily => 'hash/record_ops', + opcintype => 'record' }, +{ opcmethod => 'btree', opcname => 'record_image_ops', + opcfamily => 'btree/record_image_ops', opcintype => 'record', + opcdefault => 'f' }, +{ oid => '3126', oid_symbol => 'TEXT_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'text_ops', opcfamily => 'btree/text_ops', + opcintype => 'text' }, +{ opcmethod => 'hash', opcname => 'text_ops', opcfamily => 'hash/text_ops', + opcintype => 'text' }, +{ opcmethod => 'btree', opcname => 'time_ops', opcfamily => 'btree/time_ops', + opcintype => 'time' }, +{ opcmethod => 'hash', opcname => 'time_ops', opcfamily => 'hash/time_ops', + opcintype => 'time' }, +{ oid => '3127', oid_symbol => 'TIMESTAMPTZ_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'timestamptz_ops', + opcfamily => 'btree/datetime_ops', opcintype => 'timestamptz' }, +{ opcmethod => 'hash', opcname => 'timestamptz_ops', + opcfamily => 'hash/timestamptz_ops', opcintype => 'timestamptz' }, +{ opcmethod => 'btree', opcname => 'timetz_ops', + opcfamily => 'btree/timetz_ops', opcintype => 'timetz' }, +{ opcmethod => 'hash', opcname => 'timetz_ops', opcfamily => 'hash/timetz_ops', + opcintype => 'timetz' }, +{ opcmethod => 'btree', opcname => 'varbit_ops', + opcfamily => 'btree/varbit_ops', opcintype => 'varbit' }, +{ opcmethod => 'btree', opcname => 'varchar_ops', opcfamily => 'btree/text_ops', + opcintype => 'text', opcdefault => 'f' }, +{ opcmethod => 'hash', opcname => 'varchar_ops', opcfamily => 'hash/text_ops', + opcintype => 'text', opcdefault => 'f' }, +{ oid => '3128', oid_symbol => 'TIMESTAMP_BTREE_OPS_OID', + opcmethod => 'btree', opcname => 'timestamp_ops', + opcfamily => 'btree/datetime_ops', opcintype => 'timestamp' }, +{ opcmethod => 'hash', opcname => 'timestamp_ops', + opcfamily => 'hash/timestamp_ops', opcintype => 'timestamp' }, +{ oid => '4217', oid_symbol => 'TEXT_BTREE_PATTERN_OPS_OID', + opcmethod => 'btree', opcname => 'text_pattern_ops', + opcfamily => 'btree/text_pattern_ops', opcintype => 'text', + opcdefault => 'f' }, +{ oid => '4218', oid_symbol => 'VARCHAR_BTREE_PATTERN_OPS_OID', + opcmethod => 'btree', opcname => 'varchar_pattern_ops', + opcfamily => 'btree/text_pattern_ops', opcintype => 'text', + opcdefault => 'f' }, +{ oid => '4219', oid_symbol => 'BPCHAR_BTREE_PATTERN_OPS_OID', + opcmethod => 'btree', opcname => 'bpchar_pattern_ops', + opcfamily => 'btree/bpchar_pattern_ops', opcintype => 'bpchar', + opcdefault => 'f' }, +{ opcmethod => 'btree', opcname => 'money_ops', opcfamily => 'btree/money_ops', + opcintype => 'money' }, +{ opcmethod => 'hash', opcname => 'bool_ops', opcfamily => 'hash/bool_ops', + opcintype => 'bool' }, +{ opcmethod => 'hash', opcname => 'bytea_ops', opcfamily => 'hash/bytea_ops', + opcintype => 'bytea' }, +{ opcmethod => 'btree', opcname => 'tid_ops', opcfamily => 'btree/tid_ops', + opcintype => 'tid' }, +{ opcmethod => 'hash', opcname => 'xid_ops', opcfamily => 'hash/xid_ops', + opcintype => 'xid' }, +{ opcmethod => 'hash', opcname => 'xid8_ops', opcfamily => 'hash/xid8_ops', + opcintype => 'xid8' }, +{ opcmethod => 'btree', opcname => 'xid8_ops', opcfamily => 'btree/xid8_ops', + opcintype => 'xid8' }, +{ opcmethod => 'hash', opcname => 'cid_ops', opcfamily => 'hash/cid_ops', + opcintype => 'cid' }, +{ opcmethod => 'hash', opcname => 'tid_ops', opcfamily => 'hash/tid_ops', + opcintype => 'tid' }, +{ opcmethod => 'hash', opcname => 'text_pattern_ops', + opcfamily => 'hash/text_pattern_ops', opcintype => 'text', + opcdefault => 'f' }, +{ opcmethod => 'hash', opcname => 'varchar_pattern_ops', + opcfamily => 'hash/text_pattern_ops', opcintype => 'text', + opcdefault => 'f' }, +{ opcmethod => 'hash', opcname => 'bpchar_pattern_ops', + opcfamily => 'hash/bpchar_pattern_ops', opcintype => 'bpchar', + opcdefault => 'f' }, +{ opcmethod => 'hash', opcname => 'aclitem_ops', + opcfamily => 'hash/aclitem_ops', opcintype => 'aclitem' }, +{ opcmethod => 'gist', opcname => 'box_ops', opcfamily => 'gist/box_ops', + opcintype => 'box' }, +{ opcmethod => 'gist', opcname => 'point_ops', opcfamily => 'gist/point_ops', + opcintype => 'point', opckeytype => 'box' }, +{ opcmethod => 'gist', opcname => 'poly_ops', opcfamily => 'gist/poly_ops', + opcintype => 'polygon', opckeytype => 'box' }, +{ opcmethod => 'gist', opcname => 'circle_ops', opcfamily => 'gist/circle_ops', + opcintype => 'circle', opckeytype => 'box' }, +{ opcmethod => 'gin', opcname => 'array_ops', opcfamily => 'gin/array_ops', + opcintype => 'anyarray', opckeytype => 'anyelement' }, +{ opcmethod => 'btree', opcname => 'uuid_ops', opcfamily => 'btree/uuid_ops', + opcintype => 'uuid' }, +{ opcmethod => 'hash', opcname => 'uuid_ops', opcfamily => 'hash/uuid_ops', + opcintype => 'uuid' }, +{ opcmethod => 'btree', opcname => 'pg_lsn_ops', + opcfamily => 'btree/pg_lsn_ops', opcintype => 'pg_lsn' }, +{ opcmethod => 'hash', opcname => 'pg_lsn_ops', opcfamily => 'hash/pg_lsn_ops', + opcintype => 'pg_lsn' }, +{ opcmethod => 'btree', opcname => 'enum_ops', opcfamily => 'btree/enum_ops', + opcintype => 'anyenum' }, +{ opcmethod => 'hash', opcname => 'enum_ops', opcfamily => 'hash/enum_ops', + opcintype => 'anyenum' }, +{ opcmethod => 'btree', opcname => 'tsvector_ops', + opcfamily => 'btree/tsvector_ops', opcintype => 'tsvector' }, +{ opcmethod => 'gist', opcname => 'tsvector_ops', + opcfamily => 'gist/tsvector_ops', opcintype => 'tsvector', + opckeytype => 'gtsvector' }, +{ opcmethod => 'gin', opcname => 'tsvector_ops', + opcfamily => 'gin/tsvector_ops', opcintype => 'tsvector', + opckeytype => 'text' }, +{ opcmethod => 'btree', opcname => 'tsquery_ops', + opcfamily => 'btree/tsquery_ops', opcintype => 'tsquery' }, +{ opcmethod => 'gist', opcname => 'tsquery_ops', + opcfamily => 'gist/tsquery_ops', opcintype => 'tsquery', + opckeytype => 'int8' }, +{ opcmethod => 'btree', opcname => 'range_ops', opcfamily => 'btree/range_ops', + opcintype => 'anyrange' }, +{ opcmethod => 'hash', opcname => 'range_ops', opcfamily => 'hash/range_ops', + opcintype => 'anyrange' }, +{ opcmethod => 'gist', opcname => 'range_ops', opcfamily => 'gist/range_ops', + opcintype => 'anyrange' }, +{ opcmethod => 'spgist', opcname => 'range_ops', + opcfamily => 'spgist/range_ops', opcintype => 'anyrange' }, +{ opcmethod => 'btree', opcname => 'multirange_ops', + opcfamily => 'btree/multirange_ops', opcintype => 'anymultirange' }, +{ opcmethod => 'hash', opcname => 'multirange_ops', + opcfamily => 'hash/multirange_ops', opcintype => 'anymultirange' }, +{ opcmethod => 'gist', opcname => 'multirange_ops', + opcfamily => 'gist/multirange_ops', opcintype => 'anymultirange', + opckeytype => 'anyrange' }, +{ opcmethod => 'spgist', opcname => 'box_ops', opcfamily => 'spgist/box_ops', + opcintype => 'box' }, +{ opcmethod => 'spgist', opcname => 'quad_point_ops', + opcfamily => 'spgist/quad_point_ops', opcintype => 'point' }, +{ opcmethod => 'spgist', opcname => 'kd_point_ops', + opcfamily => 'spgist/kd_point_ops', opcintype => 'point', opcdefault => 'f' }, +{ opcmethod => 'spgist', opcname => 'text_ops', opcfamily => 'spgist/text_ops', + opcintype => 'text' }, +{ opcmethod => 'spgist', opcname => 'poly_ops', opcfamily => 'spgist/poly_ops', + opcintype => 'polygon', opckeytype => 'box' }, +{ opcmethod => 'btree', opcname => 'jsonb_ops', opcfamily => 'btree/jsonb_ops', + opcintype => 'jsonb' }, +{ opcmethod => 'hash', opcname => 'jsonb_ops', opcfamily => 'hash/jsonb_ops', + opcintype => 'jsonb' }, +{ opcmethod => 'gin', opcname => 'jsonb_ops', opcfamily => 'gin/jsonb_ops', + opcintype => 'jsonb', opckeytype => 'text' }, +{ opcmethod => 'gin', opcname => 'jsonb_path_ops', + opcfamily => 'gin/jsonb_path_ops', opcintype => 'jsonb', opcdefault => 'f', + opckeytype => 'int4' }, + +# BRIN operator classes + +# no brin opclass for bool + +{ opcmethod => 'brin', opcname => 'bytea_minmax_ops', + opcfamily => 'brin/bytea_minmax_ops', opcintype => 'bytea', + opckeytype => 'bytea' }, +{ opcmethod => 'brin', opcname => 'bytea_bloom_ops', + opcfamily => 'brin/bytea_bloom_ops', opcintype => 'bytea', opcdefault => 'f', + opckeytype => 'bytea' }, +{ opcmethod => 'brin', opcname => 'char_minmax_ops', + opcfamily => 'brin/char_minmax_ops', opcintype => 'char', + opckeytype => 'char' }, +{ opcmethod => 'brin', opcname => 'char_bloom_ops', + opcfamily => 'brin/char_bloom_ops', opcintype => 'char', opcdefault => 'f', + opckeytype => 'char' }, +{ opcmethod => 'brin', opcname => 'name_minmax_ops', + opcfamily => 'brin/name_minmax_ops', opcintype => 'name', + opckeytype => 'name' }, +{ opcmethod => 'brin', opcname => 'name_bloom_ops', + opcfamily => 'brin/name_bloom_ops', opcintype => 'name', opcdefault => 'f', + opckeytype => 'name' }, +{ opcmethod => 'brin', opcname => 'int8_minmax_ops', + opcfamily => 'brin/integer_minmax_ops', opcintype => 'int8', + opckeytype => 'int8' }, +{ opcmethod => 'brin', opcname => 'int8_minmax_multi_ops', + opcfamily => 'brin/integer_minmax_multi_ops', opcintype => 'int8', + opcdefault => 'f', opckeytype => 'int8' }, +{ opcmethod => 'brin', opcname => 'int8_bloom_ops', + opcfamily => 'brin/integer_bloom_ops', opcintype => 'int8', opcdefault => 'f', + opckeytype => 'int8' }, +{ opcmethod => 'brin', opcname => 'int2_minmax_ops', + opcfamily => 'brin/integer_minmax_ops', opcintype => 'int2', + opckeytype => 'int2' }, +{ opcmethod => 'brin', opcname => 'int2_minmax_multi_ops', + opcfamily => 'brin/integer_minmax_multi_ops', opcintype => 'int2', + opcdefault => 'f', opckeytype => 'int2' }, +{ opcmethod => 'brin', opcname => 'int2_bloom_ops', + opcfamily => 'brin/integer_bloom_ops', opcintype => 'int2', opcdefault => 'f', + opckeytype => 'int2' }, +{ opcmethod => 'brin', opcname => 'int4_minmax_ops', + opcfamily => 'brin/integer_minmax_ops', opcintype => 'int4', + opckeytype => 'int4' }, +{ opcmethod => 'brin', opcname => 'int4_minmax_multi_ops', + opcfamily => 'brin/integer_minmax_multi_ops', opcintype => 'int4', + opcdefault => 'f', opckeytype => 'int4' }, +{ opcmethod => 'brin', opcname => 'int4_bloom_ops', + opcfamily => 'brin/integer_bloom_ops', opcintype => 'int4', opcdefault => 'f', + opckeytype => 'int4' }, +{ opcmethod => 'brin', opcname => 'text_minmax_ops', + opcfamily => 'brin/text_minmax_ops', opcintype => 'text', + opckeytype => 'text' }, +{ opcmethod => 'brin', opcname => 'text_bloom_ops', + opcfamily => 'brin/text_bloom_ops', opcintype => 'text', opcdefault => 'f', + opckeytype => 'text' }, +{ opcmethod => 'brin', opcname => 'oid_minmax_ops', + opcfamily => 'brin/oid_minmax_ops', opcintype => 'oid', opckeytype => 'oid' }, +{ opcmethod => 'brin', opcname => 'oid_minmax_multi_ops', + opcfamily => 'brin/oid_minmax_multi_ops', opcintype => 'oid', + opcdefault => 'f', opckeytype => 'oid' }, +{ opcmethod => 'brin', opcname => 'oid_bloom_ops', + opcfamily => 'brin/oid_bloom_ops', opcintype => 'oid', opcdefault => 'f', + opckeytype => 'oid' }, +{ opcmethod => 'brin', opcname => 'tid_minmax_ops', + opcfamily => 'brin/tid_minmax_ops', opcintype => 'tid', opckeytype => 'tid' }, +{ opcmethod => 'brin', opcname => 'tid_bloom_ops', + opcfamily => 'brin/tid_bloom_ops', opcintype => 'tid', opcdefault => 'f', + opckeytype => 'tid' }, +{ opcmethod => 'brin', opcname => 'tid_minmax_multi_ops', + opcfamily => 'brin/tid_minmax_multi_ops', opcintype => 'tid', + opcdefault => 'f', opckeytype => 'tid' }, +{ opcmethod => 'brin', opcname => 'float4_minmax_ops', + opcfamily => 'brin/float_minmax_ops', opcintype => 'float4', + opckeytype => 'float4' }, +{ opcmethod => 'brin', opcname => 'float4_minmax_multi_ops', + opcfamily => 'brin/float_minmax_multi_ops', opcintype => 'float4', + opcdefault => 'f', opckeytype => 'float4' }, +{ opcmethod => 'brin', opcname => 'float4_bloom_ops', + opcfamily => 'brin/float_bloom_ops', opcintype => 'float4', opcdefault => 'f', + opckeytype => 'float4' }, +{ opcmethod => 'brin', opcname => 'float8_minmax_ops', + opcfamily => 'brin/float_minmax_ops', opcintype => 'float8', + opckeytype => 'float8' }, +{ opcmethod => 'brin', opcname => 'float8_minmax_multi_ops', + opcfamily => 'brin/float_minmax_multi_ops', opcintype => 'float8', + opcdefault => 'f', opckeytype => 'float8' }, +{ opcmethod => 'brin', opcname => 'float8_bloom_ops', + opcfamily => 'brin/float_bloom_ops', opcintype => 'float8', opcdefault => 'f', + opckeytype => 'float8' }, +{ opcmethod => 'brin', opcname => 'macaddr_minmax_ops', + opcfamily => 'brin/macaddr_minmax_ops', opcintype => 'macaddr', + opckeytype => 'macaddr' }, +{ opcmethod => 'brin', opcname => 'macaddr_minmax_multi_ops', + opcfamily => 'brin/macaddr_minmax_multi_ops', opcintype => 'macaddr', + opcdefault => 'f', opckeytype => 'macaddr' }, +{ opcmethod => 'brin', opcname => 'macaddr_bloom_ops', + opcfamily => 'brin/macaddr_bloom_ops', opcintype => 'macaddr', + opcdefault => 'f', opckeytype => 'macaddr' }, +{ opcmethod => 'brin', opcname => 'macaddr8_minmax_ops', + opcfamily => 'brin/macaddr8_minmax_ops', opcintype => 'macaddr8', + opckeytype => 'macaddr8' }, +{ opcmethod => 'brin', opcname => 'macaddr8_minmax_multi_ops', + opcfamily => 'brin/macaddr8_minmax_multi_ops', opcintype => 'macaddr8', + opcdefault => 'f', opckeytype => 'macaddr8' }, +{ opcmethod => 'brin', opcname => 'macaddr8_bloom_ops', + opcfamily => 'brin/macaddr8_bloom_ops', opcintype => 'macaddr8', + opcdefault => 'f', opckeytype => 'macaddr8' }, +{ opcmethod => 'brin', opcname => 'inet_minmax_ops', + opcfamily => 'brin/network_minmax_ops', opcintype => 'inet', + opcdefault => 'f', opckeytype => 'inet' }, +{ opcmethod => 'brin', opcname => 'inet_minmax_multi_ops', + opcfamily => 'brin/network_minmax_multi_ops', opcintype => 'inet', + opcdefault => 'f', opckeytype => 'inet' }, +{ opcmethod => 'brin', opcname => 'inet_bloom_ops', + opcfamily => 'brin/network_bloom_ops', opcintype => 'inet', opcdefault => 'f', + opckeytype => 'inet' }, +{ opcmethod => 'brin', opcname => 'inet_inclusion_ops', + opcfamily => 'brin/network_inclusion_ops', opcintype => 'inet', + opckeytype => 'inet' }, +{ opcmethod => 'brin', opcname => 'bpchar_minmax_ops', + opcfamily => 'brin/bpchar_minmax_ops', opcintype => 'bpchar', + opckeytype => 'bpchar' }, +{ opcmethod => 'brin', opcname => 'bpchar_bloom_ops', + opcfamily => 'brin/bpchar_bloom_ops', opcintype => 'bpchar', + opcdefault => 'f', opckeytype => 'bpchar' }, +{ opcmethod => 'brin', opcname => 'time_minmax_ops', + opcfamily => 'brin/time_minmax_ops', opcintype => 'time', + opckeytype => 'time' }, +{ opcmethod => 'brin', opcname => 'time_minmax_multi_ops', + opcfamily => 'brin/time_minmax_multi_ops', opcintype => 'time', + opcdefault => 'f', opckeytype => 'time' }, +{ opcmethod => 'brin', opcname => 'time_bloom_ops', + opcfamily => 'brin/time_bloom_ops', opcintype => 'time', opcdefault => 'f', + opckeytype => 'time' }, +{ opcmethod => 'brin', opcname => 'date_minmax_ops', + opcfamily => 'brin/datetime_minmax_ops', opcintype => 'date', + opckeytype => 'date' }, +{ opcmethod => 'brin', opcname => 'date_minmax_multi_ops', + opcfamily => 'brin/datetime_minmax_multi_ops', opcintype => 'date', + opcdefault => 'f', opckeytype => 'date' }, +{ opcmethod => 'brin', opcname => 'date_bloom_ops', + opcfamily => 'brin/datetime_bloom_ops', opcintype => 'date', + opcdefault => 'f', opckeytype => 'date' }, +{ opcmethod => 'brin', opcname => 'timestamp_minmax_ops', + opcfamily => 'brin/datetime_minmax_ops', opcintype => 'timestamp', + opckeytype => 'timestamp' }, +{ opcmethod => 'brin', opcname => 'timestamp_minmax_multi_ops', + opcfamily => 'brin/datetime_minmax_multi_ops', opcintype => 'timestamp', + opcdefault => 'f', opckeytype => 'timestamp' }, +{ opcmethod => 'brin', opcname => 'timestamp_bloom_ops', + opcfamily => 'brin/datetime_bloom_ops', opcintype => 'timestamp', + opcdefault => 'f', opckeytype => 'timestamp' }, +{ opcmethod => 'brin', opcname => 'timestamptz_minmax_ops', + opcfamily => 'brin/datetime_minmax_ops', opcintype => 'timestamptz', + opckeytype => 'timestamptz' }, +{ opcmethod => 'brin', opcname => 'timestamptz_minmax_multi_ops', + opcfamily => 'brin/datetime_minmax_multi_ops', opcintype => 'timestamptz', + opcdefault => 'f', opckeytype => 'timestamptz' }, +{ opcmethod => 'brin', opcname => 'timestamptz_bloom_ops', + opcfamily => 'brin/datetime_bloom_ops', opcintype => 'timestamptz', + opcdefault => 'f', opckeytype => 'timestamptz' }, +{ opcmethod => 'brin', opcname => 'interval_minmax_ops', + opcfamily => 'brin/interval_minmax_ops', opcintype => 'interval', + opckeytype => 'interval' }, +{ opcmethod => 'brin', opcname => 'interval_minmax_multi_ops', + opcfamily => 'brin/interval_minmax_multi_ops', opcintype => 'interval', + opcdefault => 'f', opckeytype => 'interval' }, +{ opcmethod => 'brin', opcname => 'interval_bloom_ops', + opcfamily => 'brin/interval_bloom_ops', opcintype => 'interval', + opcdefault => 'f', opckeytype => 'interval' }, +{ opcmethod => 'brin', opcname => 'timetz_minmax_ops', + opcfamily => 'brin/timetz_minmax_ops', opcintype => 'timetz', + opckeytype => 'timetz' }, +{ opcmethod => 'brin', opcname => 'timetz_minmax_multi_ops', + opcfamily => 'brin/timetz_minmax_multi_ops', opcintype => 'timetz', + opcdefault => 'f', opckeytype => 'timetz' }, +{ opcmethod => 'brin', opcname => 'timetz_bloom_ops', + opcfamily => 'brin/timetz_bloom_ops', opcintype => 'timetz', + opcdefault => 'f', opckeytype => 'timetz' }, +{ opcmethod => 'brin', opcname => 'bit_minmax_ops', + opcfamily => 'brin/bit_minmax_ops', opcintype => 'bit', opckeytype => 'bit' }, +{ opcmethod => 'brin', opcname => 'varbit_minmax_ops', + opcfamily => 'brin/varbit_minmax_ops', opcintype => 'varbit', + opckeytype => 'varbit' }, +{ opcmethod => 'brin', opcname => 'numeric_minmax_ops', + opcfamily => 'brin/numeric_minmax_ops', opcintype => 'numeric', + opckeytype => 'numeric' }, +{ opcmethod => 'brin', opcname => 'numeric_minmax_multi_ops', + opcfamily => 'brin/numeric_minmax_multi_ops', opcintype => 'numeric', + opcdefault => 'f', opckeytype => 'numeric' }, +{ opcmethod => 'brin', opcname => 'numeric_bloom_ops', + opcfamily => 'brin/numeric_bloom_ops', opcintype => 'numeric', + opcdefault => 'f', opckeytype => 'numeric' }, + +# no brin opclass for record, anyarray + +{ opcmethod => 'brin', opcname => 'uuid_minmax_ops', + opcfamily => 'brin/uuid_minmax_ops', opcintype => 'uuid', + opckeytype => 'uuid' }, +{ opcmethod => 'brin', opcname => 'uuid_minmax_multi_ops', + opcfamily => 'brin/uuid_minmax_multi_ops', opcintype => 'uuid', + opcdefault => 'f', opckeytype => 'uuid' }, +{ opcmethod => 'brin', opcname => 'uuid_bloom_ops', + opcfamily => 'brin/uuid_bloom_ops', opcintype => 'uuid', opcdefault => 'f', + opckeytype => 'uuid' }, +{ opcmethod => 'brin', opcname => 'range_inclusion_ops', + opcfamily => 'brin/range_inclusion_ops', opcintype => 'anyrange', + opckeytype => 'anyrange' }, +{ opcmethod => 'brin', opcname => 'pg_lsn_minmax_ops', + opcfamily => 'brin/pg_lsn_minmax_ops', opcintype => 'pg_lsn', + opckeytype => 'pg_lsn' }, +{ opcmethod => 'brin', opcname => 'pg_lsn_minmax_multi_ops', + opcfamily => 'brin/pg_lsn_minmax_multi_ops', opcintype => 'pg_lsn', + opcdefault => 'f', opckeytype => 'pg_lsn' }, +{ opcmethod => 'brin', opcname => 'pg_lsn_bloom_ops', + opcfamily => 'brin/pg_lsn_bloom_ops', opcintype => 'pg_lsn', + opcdefault => 'f', opckeytype => 'pg_lsn' }, + +# no brin opclass for enum, tsvector, tsquery, jsonb + +{ opcmethod => 'brin', opcname => 'box_inclusion_ops', + opcfamily => 'brin/box_inclusion_ops', opcintype => 'box', + opckeytype => 'box' }, + +# no brin opclass for the geometric types except box + +] diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h new file mode 100644 index 0000000..3a3a19b --- /dev/null +++ b/src/include/catalog/pg_opclass.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------- + * + * pg_opclass.h + * definition of the "operator class" system catalog (pg_opclass) + * + * The primary key for this table is <opcmethod, opcname, opcnamespace> --- + * that is, there is a row for each valid combination of opclass name and + * index access method type. This row specifies the expected input data type + * for the opclass (the type of the heap column, or the expression output type + * in the case of an index expression). Note that types binary-coercible to + * the specified type will be accepted too. + * + * For a given <opcmethod, opcintype> pair, there can be at most one row that + * has opcdefault = true; this row is the default opclass for such data in + * such an index. (This is not currently enforced by an index, because we + * don't support partial indexes on system catalogs.) + * + * Normally opckeytype = InvalidOid (zero), indicating that the data stored + * in the index is the same as the data in the indexed column. If opckeytype + * is nonzero then it indicates that a conversion step is needed to produce + * the stored index data, which will be of type opckeytype (which might be + * the same or different from the input datatype). Performing such a + * conversion is the responsibility of the index access method --- not all + * AMs support this. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_opclass.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPCLASS_H +#define PG_OPCLASS_H + +#include "catalog/genbki.h" +#include "catalog/pg_opclass_d.h" + +/* ---------------- + * pg_opclass definition. cpp turns this into + * typedef struct FormData_pg_opclass + * ---------------- + */ +CATALOG(pg_opclass,2616,OperatorClassRelationId) +{ + Oid oid; /* oid */ + + /* index access method opclass is for */ + Oid opcmethod BKI_LOOKUP(pg_am); + + /* name of this opclass */ + NameData opcname; + + /* namespace of this opclass */ + Oid opcnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* opclass owner */ + Oid opcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* containing operator family */ + Oid opcfamily BKI_LOOKUP(pg_opfamily); + + /* type of data indexed by opclass */ + Oid opcintype BKI_LOOKUP(pg_type); + + /* T if opclass is default for opcintype */ + bool opcdefault BKI_DEFAULT(t); + + /* type of data in index, or InvalidOid if same as input column type */ + Oid opckeytype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); +} FormData_pg_opclass; + +/* ---------------- + * Form_pg_opclass corresponds to a pointer to a tuple with + * the format of pg_opclass relation. + * ---------------- + */ +typedef FormData_pg_opclass *Form_pg_opclass; + +DECLARE_UNIQUE_INDEX(pg_opclass_am_name_nsp_index, 2686, OpclassAmNameNspIndexId, on pg_opclass using btree(opcmethod oid_ops, opcname name_ops, opcnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_opclass_oid_index, 2687, OpclassOidIndexId, on pg_opclass using btree(oid oid_ops)); + +#endif /* PG_OPCLASS_H */ diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat new file mode 100644 index 0000000..bc5f821 --- /dev/null +++ b/src/include/catalog/pg_operator.dat @@ -0,0 +1,3461 @@ +#---------------------------------------------------------------------- +# +# pg_operator.dat +# Initial contents of the pg_operator system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_operator.dat +# +#---------------------------------------------------------------------- + +[ + +# Note: every entry in pg_operator.dat is expected to have a 'descr' comment. +# If the operator is a deprecated equivalent of some other entry, be sure +# to comment it as such so that initdb doesn't think it's a preferred name +# for the underlying function. + +{ oid => '15', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int4', + oprright => 'int8', oprresult => 'bool', oprcom => '=(int8,int4)', + oprnegate => '<>(int4,int8)', oprcode => 'int48eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '36', descr => 'not equal', + oprname => '<>', oprleft => 'int4', oprright => 'int8', oprresult => 'bool', + oprcom => '<>(int8,int4)', oprnegate => '=(int4,int8)', oprcode => 'int48ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '37', descr => 'less than', + oprname => '<', oprleft => 'int4', oprright => 'int8', oprresult => 'bool', + oprcom => '>(int8,int4)', oprnegate => '>=(int4,int8)', oprcode => 'int48lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '76', descr => 'greater than', + oprname => '>', oprleft => 'int4', oprright => 'int8', oprresult => 'bool', + oprcom => '<(int8,int4)', oprnegate => '<=(int4,int8)', oprcode => 'int48gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '80', descr => 'less than or equal', + oprname => '<=', oprleft => 'int4', oprright => 'int8', oprresult => 'bool', + oprcom => '>=(int8,int4)', oprnegate => '>(int4,int8)', oprcode => 'int48le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '82', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int4', oprright => 'int8', oprresult => 'bool', + oprcom => '<=(int8,int4)', oprnegate => '<(int4,int8)', oprcode => 'int48ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '58', descr => 'less than', + oprname => '<', oprleft => 'bool', oprright => 'bool', oprresult => 'bool', + oprcom => '>(bool,bool)', oprnegate => '>=(bool,bool)', oprcode => 'boollt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '59', descr => 'greater than', + oprname => '>', oprleft => 'bool', oprright => 'bool', oprresult => 'bool', + oprcom => '<(bool,bool)', oprnegate => '<=(bool,bool)', oprcode => 'boolgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '85', oid_symbol => 'BooleanNotEqualOperator', descr => 'not equal', + oprname => '<>', oprleft => 'bool', oprright => 'bool', oprresult => 'bool', + oprcom => '<>(bool,bool)', oprnegate => '=(bool,bool)', oprcode => 'boolne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '91', oid_symbol => 'BooleanEqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'bool', + oprright => 'bool', oprresult => 'bool', oprcom => '=(bool,bool)', + oprnegate => '<>(bool,bool)', oprcode => 'booleq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1694', descr => 'less than or equal', + oprname => '<=', oprleft => 'bool', oprright => 'bool', oprresult => 'bool', + oprcom => '>=(bool,bool)', oprnegate => '>(bool,bool)', oprcode => 'boolle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1695', descr => 'greater than or equal', + oprname => '>=', oprleft => 'bool', oprright => 'bool', oprresult => 'bool', + oprcom => '<=(bool,bool)', oprnegate => '<(bool,bool)', oprcode => 'boolge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '92', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'char', + oprright => 'char', oprresult => 'bool', oprcom => '=(char,char)', + oprnegate => '<>(char,char)', oprcode => 'chareq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '93', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'name', + oprright => 'name', oprresult => 'bool', oprcom => '=(name,name)', + oprnegate => '<>(name,name)', oprcode => 'nameeq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '94', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int2', + oprright => 'int2', oprresult => 'bool', oprcom => '=(int2,int2)', + oprnegate => '<>(int2,int2)', oprcode => 'int2eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '95', descr => 'less than', + oprname => '<', oprleft => 'int2', oprright => 'int2', oprresult => 'bool', + oprcom => '>(int2,int2)', oprnegate => '>=(int2,int2)', oprcode => 'int2lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '96', oid_symbol => 'Int4EqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int4', + oprright => 'int4', oprresult => 'bool', oprcom => '=(int4,int4)', + oprnegate => '<>(int4,int4)', oprcode => 'int4eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '97', oid_symbol => 'Int4LessOperator', descr => 'less than', + oprname => '<', oprleft => 'int4', oprright => 'int4', oprresult => 'bool', + oprcom => '>(int4,int4)', oprnegate => '>=(int4,int4)', oprcode => 'int4lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '98', oid_symbol => 'TextEqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'text', + oprright => 'text', oprresult => 'bool', oprcom => '=(text,text)', + oprnegate => '<>(text,text)', oprcode => 'texteq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '3877', oid_symbol => 'TextPrefixOperator', descr => 'starts with', + oprname => '^@', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcode => 'starts_with', oprrest => 'prefixsel', + oprjoin => 'prefixjoinsel' }, + +{ oid => '254', oid_symbol => 'NameEqualTextOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'name', + oprright => 'text', oprresult => 'bool', oprcom => '=(text,name)', + oprnegate => '<>(name,text)', oprcode => 'nameeqtext', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '255', oid_symbol => 'NameLessTextOperator', descr => 'less than', + oprname => '<', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprcom => '>(text,name)', oprnegate => '>=(name,text)', + oprcode => 'namelttext', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '256', descr => 'less than or equal', + oprname => '<=', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprcom => '>=(text,name)', oprnegate => '>(name,text)', + oprcode => 'nameletext', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '257', oid_symbol => 'NameGreaterEqualTextOperator', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprcom => '<=(text,name)', oprnegate => '<(name,text)', + oprcode => 'namegetext', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '258', descr => 'greater than', + oprname => '>', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprcom => '<(text,name)', oprnegate => '<=(name,text)', + oprcode => 'namegttext', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '259', descr => 'not equal', + oprname => '<>', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprcom => '<>(text,name)', oprnegate => '=(name,text)', + oprcode => 'namenetext', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '260', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'text', + oprright => 'name', oprresult => 'bool', oprcom => '=(name,text)', + oprnegate => '<>(text,name)', oprcode => 'texteqname', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '261', descr => 'less than', + oprname => '<', oprleft => 'text', oprright => 'name', oprresult => 'bool', + oprcom => '>(name,text)', oprnegate => '>=(text,name)', + oprcode => 'textltname', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '262', descr => 'less than or equal', + oprname => '<=', oprleft => 'text', oprright => 'name', oprresult => 'bool', + oprcom => '>=(name,text)', oprnegate => '>(text,name)', + oprcode => 'textlename', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '263', descr => 'greater than or equal', + oprname => '>=', oprleft => 'text', oprright => 'name', oprresult => 'bool', + oprcom => '<=(name,text)', oprnegate => '<(text,name)', + oprcode => 'textgename', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '264', descr => 'greater than', + oprname => '>', oprleft => 'text', oprright => 'name', oprresult => 'bool', + oprcom => '<(name,text)', oprnegate => '<=(text,name)', + oprcode => 'textgtname', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '265', descr => 'not equal', + oprname => '<>', oprleft => 'text', oprright => 'name', oprresult => 'bool', + oprcom => '<>(name,text)', oprnegate => '=(text,name)', + oprcode => 'textnename', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +{ oid => '349', descr => 'append element onto end of array', + oprname => '||', oprleft => 'anycompatiblearray', oprright => 'anycompatible', + oprresult => 'anycompatiblearray', oprcode => 'array_append' }, +{ oid => '374', descr => 'prepend element onto front of array', + oprname => '||', oprleft => 'anycompatible', oprright => 'anycompatiblearray', + oprresult => 'anycompatiblearray', oprcode => 'array_prepend' }, +{ oid => '375', descr => 'concatenate', + oprname => '||', oprleft => 'anycompatiblearray', + oprright => 'anycompatiblearray', oprresult => 'anycompatiblearray', + oprcode => 'array_cat' }, + +{ oid => '352', descr => 'equal', + oprname => '=', oprcanhash => 't', oprleft => 'xid', oprright => 'xid', + oprresult => 'bool', oprcom => '=(xid,xid)', oprnegate => '<>(xid,xid)', + oprcode => 'xideq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '353', descr => 'equal', + oprname => '=', oprleft => 'xid', oprright => 'int4', oprresult => 'bool', + oprnegate => '<>(xid,int4)', oprcode => 'xideqint4', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '3315', descr => 'not equal', + oprname => '<>', oprleft => 'xid', oprright => 'xid', oprresult => 'bool', + oprcom => '<>(xid,xid)', oprnegate => '=(xid,xid)', oprcode => 'xidneq', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3316', descr => 'not equal', + oprname => '<>', oprleft => 'xid', oprright => 'int4', oprresult => 'bool', + oprnegate => '=(xid,int4)', oprcode => 'xidneqint4', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '5068', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'xid8', + oprright => 'xid8', oprresult => 'bool', oprcom => '=(xid8,xid8)', + oprnegate => '<>(xid8,xid8)', oprcode => 'xid8eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '5072', descr => 'not equal', + oprname => '<>', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', + oprcom => '<>(xid8,xid8)', oprnegate => '=(xid8,xid8)', oprcode => 'xid8ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '5073', descr => 'less than', + oprname => '<', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', + oprcom => '>(xid8,xid8)', oprnegate => '>=(xid8,xid8)', oprcode => 'xid8lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '5074', descr => 'greater than', + oprname => '>', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', + oprcom => '<(xid8,xid8)', oprnegate => '<=(xid8,xid8)', oprcode => 'xid8gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '5075', descr => 'less than or equal', + oprname => '<=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', + oprcom => '>=(xid8,xid8)', oprnegate => '>(xid8,xid8)', oprcode => 'xid8le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '5076', descr => 'greater than or equal', + oprname => '>=', oprleft => 'xid8', oprright => 'xid8', oprresult => 'bool', + oprcom => '<=(xid8,xid8)', oprnegate => '<(xid8,xid8)', oprcode => 'xid8ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '385', descr => 'equal', + oprname => '=', oprcanhash => 't', oprleft => 'cid', oprright => 'cid', + oprresult => 'bool', oprcom => '=(cid,cid)', oprcode => 'cideq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, + +{ oid => '387', oid_symbol => 'TIDEqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'tid', + oprright => 'tid', oprresult => 'bool', oprcom => '=(tid,tid)', + oprnegate => '<>(tid,tid)', oprcode => 'tideq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '402', descr => 'not equal', + oprname => '<>', oprleft => 'tid', oprright => 'tid', oprresult => 'bool', + oprcom => '<>(tid,tid)', oprnegate => '=(tid,tid)', oprcode => 'tidne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '2799', oid_symbol => 'TIDLessOperator', descr => 'less than', + oprname => '<', oprleft => 'tid', oprright => 'tid', oprresult => 'bool', + oprcom => '>(tid,tid)', oprnegate => '>=(tid,tid)', oprcode => 'tidlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2800', oid_symbol => 'TIDGreaterOperator', descr => 'greater than', + oprname => '>', oprleft => 'tid', oprright => 'tid', oprresult => 'bool', + oprcom => '<(tid,tid)', oprnegate => '<=(tid,tid)', oprcode => 'tidgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2801', oid_symbol => 'TIDLessEqOperator', + descr => 'less than or equal', + oprname => '<=', oprleft => 'tid', oprright => 'tid', oprresult => 'bool', + oprcom => '>=(tid,tid)', oprnegate => '>(tid,tid)', oprcode => 'tidle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2802', oid_symbol => 'TIDGreaterEqOperator', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'tid', oprright => 'tid', oprresult => 'bool', + oprcom => '<=(tid,tid)', oprnegate => '<(tid,tid)', oprcode => 'tidge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '410', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int8', + oprright => 'int8', oprresult => 'bool', oprcom => '=(int8,int8)', + oprnegate => '<>(int8,int8)', oprcode => 'int8eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '411', descr => 'not equal', + oprname => '<>', oprleft => 'int8', oprright => 'int8', oprresult => 'bool', + oprcom => '<>(int8,int8)', oprnegate => '=(int8,int8)', oprcode => 'int8ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '412', oid_symbol => 'Int8LessOperator', descr => 'less than', + oprname => '<', oprleft => 'int8', oprright => 'int8', oprresult => 'bool', + oprcom => '>(int8,int8)', oprnegate => '>=(int8,int8)', oprcode => 'int8lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '413', descr => 'greater than', + oprname => '>', oprleft => 'int8', oprright => 'int8', oprresult => 'bool', + oprcom => '<(int8,int8)', oprnegate => '<=(int8,int8)', oprcode => 'int8gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '414', descr => 'less than or equal', + oprname => '<=', oprleft => 'int8', oprright => 'int8', oprresult => 'bool', + oprcom => '>=(int8,int8)', oprnegate => '>(int8,int8)', oprcode => 'int8le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '415', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int8', oprright => 'int8', oprresult => 'bool', + oprcom => '<=(int8,int8)', oprnegate => '<(int8,int8)', oprcode => 'int8ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '416', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int8', + oprright => 'int4', oprresult => 'bool', oprcom => '=(int4,int8)', + oprnegate => '<>(int8,int4)', oprcode => 'int84eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '417', descr => 'not equal', + oprname => '<>', oprleft => 'int8', oprright => 'int4', oprresult => 'bool', + oprcom => '<>(int4,int8)', oprnegate => '=(int8,int4)', oprcode => 'int84ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '418', descr => 'less than', + oprname => '<', oprleft => 'int8', oprright => 'int4', oprresult => 'bool', + oprcom => '>(int4,int8)', oprnegate => '>=(int8,int4)', oprcode => 'int84lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '419', descr => 'greater than', + oprname => '>', oprleft => 'int8', oprright => 'int4', oprresult => 'bool', + oprcom => '<(int4,int8)', oprnegate => '<=(int8,int4)', oprcode => 'int84gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '420', descr => 'less than or equal', + oprname => '<=', oprleft => 'int8', oprright => 'int4', oprresult => 'bool', + oprcom => '>=(int4,int8)', oprnegate => '>(int8,int4)', oprcode => 'int84le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '430', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int8', oprright => 'int4', oprresult => 'bool', + oprcom => '<=(int4,int8)', oprnegate => '<(int8,int4)', oprcode => 'int84ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '439', descr => 'modulus', + oprname => '%', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcode => 'int8mod' }, +{ oid => '473', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'int8', + oprresult => 'int8', oprcode => 'int8abs' }, + +{ oid => '484', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'int8', + oprresult => 'int8', oprcode => 'int8um' }, +{ oid => '485', descr => 'is left of', + oprname => '<<', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_left', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '486', descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_overleft', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '487', descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_overright', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '488', descr => 'is right of', + oprname => '>>', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_right', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '489', descr => 'is contained by', + oprname => '<@', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcom => '@>(polygon,polygon)', + oprcode => 'poly_contained', oprrest => 'contsel', oprjoin => 'contjoinsel' }, +{ oid => '490', descr => 'contains', + oprname => '@>', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcom => '<@(polygon,polygon)', + oprcode => 'poly_contain', oprrest => 'contsel', oprjoin => 'contjoinsel' }, +{ oid => '491', descr => 'same as', + oprname => '~=', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcom => '~=(polygon,polygon)', oprcode => 'poly_same', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '492', descr => 'overlaps', + oprname => '&&', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcom => '&&(polygon,polygon)', + oprcode => 'poly_overlap', oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '493', descr => 'is left of', + oprname => '<<', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_left', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '494', descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_overleft', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '495', descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_overright', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '496', descr => 'is right of', + oprname => '>>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_right', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '497', descr => 'is contained by', + oprname => '<@', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '@>(box,box)', oprcode => 'box_contained', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '498', descr => 'contains', + oprname => '@>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '<@(box,box)', oprcode => 'box_contain', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '499', descr => 'same as', + oprname => '~=', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '~=(box,box)', oprcode => 'box_same', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '500', descr => 'overlaps', + oprname => '&&', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '&&(box,box)', oprcode => 'box_overlap', oprrest => 'areasel', + oprjoin => 'areajoinsel' }, +{ oid => '501', descr => 'greater than or equal by area', + oprname => '>=', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '<=(box,box)', oprnegate => '<(box,box)', oprcode => 'box_ge', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '502', descr => 'greater than by area', + oprname => '>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '<(box,box)', oprnegate => '<=(box,box)', oprcode => 'box_gt', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '503', descr => 'equal by area', + oprname => '=', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '=(box,box)', oprcode => 'box_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '504', descr => 'less than by area', + oprname => '<', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '>(box,box)', oprnegate => '>=(box,box)', oprcode => 'box_lt', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '505', descr => 'less than or equal by area', + oprname => '<=', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcom => '>=(box,box)', oprnegate => '>(box,box)', oprcode => 'box_le', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '506', descr => 'deprecated, use |>> instead', + oprname => '>^', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcode => 'point_above', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '507', descr => 'is left of', + oprname => '<<', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcode => 'point_left', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '508', descr => 'is right of', + oprname => '>>', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcode => 'point_right', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '509', descr => 'deprecated, use <<| instead', + oprname => '<^', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcode => 'point_below', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '510', descr => 'same as', + oprname => '~=', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcom => '~=(point,point)', oprnegate => '<>(point,point)', + oprcode => 'point_eq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '511', descr => 'point inside box', + oprname => '<@', oprleft => 'point', oprright => 'box', oprresult => 'bool', + oprcom => '@>(box,point)', oprcode => 'on_pb', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '433', descr => 'contains', + oprname => '@>', oprleft => 'box', oprright => 'point', oprresult => 'bool', + oprcom => '<@(point,box)', oprcode => 'box_contain_pt', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '512', descr => 'point within closed path, or point on open path', + oprname => '<@', oprleft => 'point', oprright => 'path', oprresult => 'bool', + oprcom => '@>(path,point)', oprcode => 'on_ppath' }, +{ oid => '513', descr => 'center of', + oprname => '@@', oprkind => 'l', oprleft => '0', oprright => 'box', + oprresult => 'point', oprcode => 'box_center' }, +{ oid => '514', descr => 'multiply', + oprname => '*', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcom => '*(int4,int4)', oprcode => 'int4mul' }, +{ oid => '517', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,point)', + oprcode => 'point_distance' }, +{ oid => '518', descr => 'not equal', + oprname => '<>', oprleft => 'int4', oprright => 'int4', oprresult => 'bool', + oprcom => '<>(int4,int4)', oprnegate => '=(int4,int4)', oprcode => 'int4ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '519', descr => 'not equal', + oprname => '<>', oprleft => 'int2', oprright => 'int2', oprresult => 'bool', + oprcom => '<>(int2,int2)', oprnegate => '=(int2,int2)', oprcode => 'int2ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '520', descr => 'greater than', + oprname => '>', oprleft => 'int2', oprright => 'int2', oprresult => 'bool', + oprcom => '<(int2,int2)', oprnegate => '<=(int2,int2)', oprcode => 'int2gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '521', descr => 'greater than', + oprname => '>', oprleft => 'int4', oprright => 'int4', oprresult => 'bool', + oprcom => '<(int4,int4)', oprnegate => '<=(int4,int4)', oprcode => 'int4gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '522', descr => 'less than or equal', + oprname => '<=', oprleft => 'int2', oprright => 'int2', oprresult => 'bool', + oprcom => '>=(int2,int2)', oprnegate => '>(int2,int2)', oprcode => 'int2le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '523', descr => 'less than or equal', + oprname => '<=', oprleft => 'int4', oprright => 'int4', oprresult => 'bool', + oprcom => '>=(int4,int4)', oprnegate => '>(int4,int4)', oprcode => 'int4le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '524', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int2', oprright => 'int2', oprresult => 'bool', + oprcom => '<=(int2,int2)', oprnegate => '<(int2,int2)', oprcode => 'int2ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '525', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int4', oprright => 'int4', oprresult => 'bool', + oprcom => '<=(int4,int4)', oprnegate => '<(int4,int4)', oprcode => 'int4ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '526', descr => 'multiply', + oprname => '*', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcom => '*(int2,int2)', oprcode => 'int2mul' }, +{ oid => '527', descr => 'divide', + oprname => '/', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcode => 'int2div' }, +{ oid => '528', descr => 'divide', + oprname => '/', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcode => 'int4div' }, +{ oid => '529', descr => 'modulus', + oprname => '%', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcode => 'int2mod' }, +{ oid => '530', descr => 'modulus', + oprname => '%', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcode => 'int4mod' }, +{ oid => '531', descr => 'not equal', + oprname => '<>', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '<>(text,text)', oprnegate => '=(text,text)', oprcode => 'textne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '532', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int2', + oprright => 'int4', oprresult => 'bool', oprcom => '=(int4,int2)', + oprnegate => '<>(int2,int4)', oprcode => 'int24eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '533', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int4', + oprright => 'int2', oprresult => 'bool', oprcom => '=(int2,int4)', + oprnegate => '<>(int4,int2)', oprcode => 'int42eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '534', descr => 'less than', + oprname => '<', oprleft => 'int2', oprright => 'int4', oprresult => 'bool', + oprcom => '>(int4,int2)', oprnegate => '>=(int2,int4)', oprcode => 'int24lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '535', descr => 'less than', + oprname => '<', oprleft => 'int4', oprright => 'int2', oprresult => 'bool', + oprcom => '>(int2,int4)', oprnegate => '>=(int4,int2)', oprcode => 'int42lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '536', descr => 'greater than', + oprname => '>', oprleft => 'int2', oprright => 'int4', oprresult => 'bool', + oprcom => '<(int4,int2)', oprnegate => '<=(int2,int4)', oprcode => 'int24gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '537', descr => 'greater than', + oprname => '>', oprleft => 'int4', oprright => 'int2', oprresult => 'bool', + oprcom => '<(int2,int4)', oprnegate => '<=(int4,int2)', oprcode => 'int42gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '538', descr => 'not equal', + oprname => '<>', oprleft => 'int2', oprright => 'int4', oprresult => 'bool', + oprcom => '<>(int4,int2)', oprnegate => '=(int2,int4)', oprcode => 'int24ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '539', descr => 'not equal', + oprname => '<>', oprleft => 'int4', oprright => 'int2', oprresult => 'bool', + oprcom => '<>(int2,int4)', oprnegate => '=(int4,int2)', oprcode => 'int42ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '540', descr => 'less than or equal', + oprname => '<=', oprleft => 'int2', oprright => 'int4', oprresult => 'bool', + oprcom => '>=(int4,int2)', oprnegate => '>(int2,int4)', oprcode => 'int24le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '541', descr => 'less than or equal', + oprname => '<=', oprleft => 'int4', oprright => 'int2', oprresult => 'bool', + oprcom => '>=(int2,int4)', oprnegate => '>(int4,int2)', oprcode => 'int42le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '542', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int2', oprright => 'int4', oprresult => 'bool', + oprcom => '<=(int4,int2)', oprnegate => '<(int2,int4)', oprcode => 'int24ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '543', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int4', oprright => 'int2', oprresult => 'bool', + oprcom => '<=(int2,int4)', oprnegate => '<(int4,int2)', oprcode => 'int42ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '544', descr => 'multiply', + oprname => '*', oprleft => 'int2', oprright => 'int4', oprresult => 'int4', + oprcom => '*(int4,int2)', oprcode => 'int24mul' }, +{ oid => '545', descr => 'multiply', + oprname => '*', oprleft => 'int4', oprright => 'int2', oprresult => 'int4', + oprcom => '*(int2,int4)', oprcode => 'int42mul' }, +{ oid => '546', descr => 'divide', + oprname => '/', oprleft => 'int2', oprright => 'int4', oprresult => 'int4', + oprcode => 'int24div' }, +{ oid => '547', descr => 'divide', + oprname => '/', oprleft => 'int4', oprright => 'int2', oprresult => 'int4', + oprcode => 'int42div' }, +{ oid => '550', descr => 'add', + oprname => '+', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcom => '+(int2,int2)', oprcode => 'int2pl' }, +{ oid => '551', descr => 'add', + oprname => '+', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcom => '+(int4,int4)', oprcode => 'int4pl' }, +{ oid => '552', descr => 'add', + oprname => '+', oprleft => 'int2', oprright => 'int4', oprresult => 'int4', + oprcom => '+(int4,int2)', oprcode => 'int24pl' }, +{ oid => '553', descr => 'add', + oprname => '+', oprleft => 'int4', oprright => 'int2', oprresult => 'int4', + oprcom => '+(int2,int4)', oprcode => 'int42pl' }, +{ oid => '554', descr => 'subtract', + oprname => '-', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcode => 'int2mi' }, +{ oid => '555', descr => 'subtract', + oprname => '-', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcode => 'int4mi' }, +{ oid => '556', descr => 'subtract', + oprname => '-', oprleft => 'int2', oprright => 'int4', oprresult => 'int4', + oprcode => 'int24mi' }, +{ oid => '557', descr => 'subtract', + oprname => '-', oprleft => 'int4', oprright => 'int2', oprresult => 'int4', + oprcode => 'int42mi' }, +{ oid => '558', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'int4', + oprresult => 'int4', oprcode => 'int4um' }, +{ oid => '559', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'int2', + oprresult => 'int2', oprcode => 'int2um' }, +{ oid => '584', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'float4', + oprresult => 'float4', oprcode => 'float4um' }, +{ oid => '585', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'float8', + oprresult => 'float8', oprcode => 'float8um' }, +{ oid => '586', descr => 'add', + oprname => '+', oprleft => 'float4', oprright => 'float4', + oprresult => 'float4', oprcom => '+(float4,float4)', oprcode => 'float4pl' }, +{ oid => '587', descr => 'subtract', + oprname => '-', oprleft => 'float4', oprright => 'float4', + oprresult => 'float4', oprcode => 'float4mi' }, +{ oid => '588', descr => 'divide', + oprname => '/', oprleft => 'float4', oprright => 'float4', + oprresult => 'float4', oprcode => 'float4div' }, +{ oid => '589', descr => 'multiply', + oprname => '*', oprleft => 'float4', oprright => 'float4', + oprresult => 'float4', oprcom => '*(float4,float4)', oprcode => 'float4mul' }, +{ oid => '590', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'float4', + oprresult => 'float4', oprcode => 'float4abs' }, +{ oid => '591', descr => 'add', + oprname => '+', oprleft => 'float8', oprright => 'float8', + oprresult => 'float8', oprcom => '+(float8,float8)', oprcode => 'float8pl' }, +{ oid => '592', descr => 'subtract', + oprname => '-', oprleft => 'float8', oprright => 'float8', + oprresult => 'float8', oprcode => 'float8mi' }, +{ oid => '593', descr => 'divide', + oprname => '/', oprleft => 'float8', oprright => 'float8', + oprresult => 'float8', oprcode => 'float8div' }, +{ oid => '594', descr => 'multiply', + oprname => '*', oprleft => 'float8', oprright => 'float8', + oprresult => 'float8', oprcom => '*(float8,float8)', oprcode => 'float8mul' }, +{ oid => '595', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'float8', + oprresult => 'float8', oprcode => 'float8abs' }, +{ oid => '596', descr => 'square root', + oprname => '|/', oprkind => 'l', oprleft => '0', oprright => 'float8', + oprresult => 'float8', oprcode => 'dsqrt' }, +{ oid => '597', descr => 'cube root', + oprname => '||/', oprkind => 'l', oprleft => '0', oprright => 'float8', + oprresult => 'float8', oprcode => 'dcbrt' }, + +{ oid => '607', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'oid', + oprright => 'oid', oprresult => 'bool', oprcom => '=(oid,oid)', + oprnegate => '<>(oid,oid)', oprcode => 'oideq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '608', descr => 'not equal', + oprname => '<>', oprleft => 'oid', oprright => 'oid', oprresult => 'bool', + oprcom => '<>(oid,oid)', oprnegate => '=(oid,oid)', oprcode => 'oidne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '609', descr => 'less than', + oprname => '<', oprleft => 'oid', oprright => 'oid', oprresult => 'bool', + oprcom => '>(oid,oid)', oprnegate => '>=(oid,oid)', oprcode => 'oidlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '610', descr => 'greater than', + oprname => '>', oprleft => 'oid', oprright => 'oid', oprresult => 'bool', + oprcom => '<(oid,oid)', oprnegate => '<=(oid,oid)', oprcode => 'oidgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '611', descr => 'less than or equal', + oprname => '<=', oprleft => 'oid', oprright => 'oid', oprresult => 'bool', + oprcom => '>=(oid,oid)', oprnegate => '>(oid,oid)', oprcode => 'oidle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '612', descr => 'greater than or equal', + oprname => '>=', oprleft => 'oid', oprright => 'oid', oprresult => 'bool', + oprcom => '<=(oid,oid)', oprnegate => '<(oid,oid)', oprcode => 'oidge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '644', descr => 'not equal', + oprname => '<>', oprleft => 'oidvector', oprright => 'oidvector', + oprresult => 'bool', oprcom => '<>(oidvector,oidvector)', + oprnegate => '=(oidvector,oidvector)', oprcode => 'oidvectorne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '645', descr => 'less than', + oprname => '<', oprleft => 'oidvector', oprright => 'oidvector', + oprresult => 'bool', oprcom => '>(oidvector,oidvector)', + oprnegate => '>=(oidvector,oidvector)', oprcode => 'oidvectorlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '646', descr => 'greater than', + oprname => '>', oprleft => 'oidvector', oprright => 'oidvector', + oprresult => 'bool', oprcom => '<(oidvector,oidvector)', + oprnegate => '<=(oidvector,oidvector)', oprcode => 'oidvectorgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '647', descr => 'less than or equal', + oprname => '<=', oprleft => 'oidvector', oprright => 'oidvector', + oprresult => 'bool', oprcom => '>=(oidvector,oidvector)', + oprnegate => '>(oidvector,oidvector)', oprcode => 'oidvectorle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '648', descr => 'greater than or equal', + oprname => '>=', oprleft => 'oidvector', oprright => 'oidvector', + oprresult => 'bool', oprcom => '<=(oidvector,oidvector)', + oprnegate => '<(oidvector,oidvector)', oprcode => 'oidvectorge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '649', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'oidvector', + oprright => 'oidvector', oprresult => 'bool', + oprcom => '=(oidvector,oidvector)', oprnegate => '<>(oidvector,oidvector)', + oprcode => 'oidvectoreq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, + +{ oid => '613', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'line', + oprresult => 'float8', oprcom => '<->(line,point)', oprcode => 'dist_pl' }, +{ oid => '760', descr => 'distance between', + oprname => '<->', oprleft => 'line', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,line)', oprcode => 'dist_lp' }, +{ oid => '614', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'lseg', + oprresult => 'float8', oprcom => '<->(lseg,point)', oprcode => 'dist_ps' }, +{ oid => '761', descr => 'distance between', + oprname => '<->', oprleft => 'lseg', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,lseg)', oprcode => 'dist_sp' }, +{ oid => '615', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'box', + oprresult => 'float8', oprcom => '<->(box,point)', oprcode => 'dist_pb' }, +{ oid => '606', descr => 'distance between', + oprname => '<->', oprleft => 'box', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,box)', oprcode => 'dist_bp' }, +{ oid => '616', descr => 'distance between', + oprname => '<->', oprleft => 'lseg', oprright => 'line', + oprresult => 'float8', oprcom => '<->(line,lseg)', oprcode => 'dist_sl' }, +{ oid => '762', descr => 'distance between', + oprname => '<->', oprleft => 'line', oprright => 'lseg', + oprresult => 'float8', oprcom => '<->(lseg,line)', oprcode => 'dist_ls' }, +{ oid => '617', descr => 'distance between', + oprname => '<->', oprleft => 'lseg', oprright => 'box', oprresult => 'float8', + oprcom => '<->(box,lseg)', oprcode => 'dist_sb' }, +{ oid => '763', descr => 'distance between', + oprname => '<->', oprleft => 'box', oprright => 'lseg', oprresult => 'float8', + oprcom => '<->(lseg,box)', oprcode => 'dist_bs' }, +{ oid => '618', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'path', + oprresult => 'float8', oprcom => '<->(path,point)', oprcode => 'dist_ppath' }, +{ oid => '784', descr => 'distance between', + oprname => '<->', oprleft => 'path', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,path)', oprcode => 'dist_pathp' }, + +{ oid => '620', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'float4', + oprright => 'float4', oprresult => 'bool', oprcom => '=(float4,float4)', + oprnegate => '<>(float4,float4)', oprcode => 'float4eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '621', descr => 'not equal', + oprname => '<>', oprleft => 'float4', oprright => 'float4', + oprresult => 'bool', oprcom => '<>(float4,float4)', + oprnegate => '=(float4,float4)', oprcode => 'float4ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '622', descr => 'less than', + oprname => '<', oprleft => 'float4', oprright => 'float4', + oprresult => 'bool', oprcom => '>(float4,float4)', + oprnegate => '>=(float4,float4)', oprcode => 'float4lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '623', descr => 'greater than', + oprname => '>', oprleft => 'float4', oprright => 'float4', + oprresult => 'bool', oprcom => '<(float4,float4)', + oprnegate => '<=(float4,float4)', oprcode => 'float4gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '624', descr => 'less than or equal', + oprname => '<=', oprleft => 'float4', oprright => 'float4', + oprresult => 'bool', oprcom => '>=(float4,float4)', + oprnegate => '>(float4,float4)', oprcode => 'float4le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '625', descr => 'greater than or equal', + oprname => '>=', oprleft => 'float4', oprright => 'float4', + oprresult => 'bool', oprcom => '<=(float4,float4)', + oprnegate => '<(float4,float4)', oprcode => 'float4ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '630', descr => 'not equal', + oprname => '<>', oprleft => 'char', oprright => 'char', oprresult => 'bool', + oprcom => '<>(char,char)', oprnegate => '=(char,char)', oprcode => 'charne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +{ oid => '631', descr => 'less than', + oprname => '<', oprleft => 'char', oprright => 'char', oprresult => 'bool', + oprcom => '>(char,char)', oprnegate => '>=(char,char)', oprcode => 'charlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '632', descr => 'less than or equal', + oprname => '<=', oprleft => 'char', oprright => 'char', oprresult => 'bool', + oprcom => '>=(char,char)', oprnegate => '>(char,char)', oprcode => 'charle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '633', descr => 'greater than', + oprname => '>', oprleft => 'char', oprright => 'char', oprresult => 'bool', + oprcom => '<(char,char)', oprnegate => '<=(char,char)', oprcode => 'chargt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '634', descr => 'greater than or equal', + oprname => '>=', oprleft => 'char', oprright => 'char', oprresult => 'bool', + oprcom => '<=(char,char)', oprnegate => '<(char,char)', oprcode => 'charge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '639', oid_symbol => 'OID_NAME_REGEXEQ_OP', + descr => 'matches regular expression, case-sensitive', + oprname => '~', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '!~(name,text)', oprcode => 'nameregexeq', + oprrest => 'regexeqsel', oprjoin => 'regexeqjoinsel' }, +{ oid => '640', descr => 'does not match regular expression, case-sensitive', + oprname => '!~', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '~(name,text)', oprcode => 'nameregexne', + oprrest => 'regexnesel', oprjoin => 'regexnejoinsel' }, +{ oid => '641', oid_symbol => 'OID_TEXT_REGEXEQ_OP', + descr => 'matches regular expression, case-sensitive', + oprname => '~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '!~(text,text)', oprcode => 'textregexeq', + oprrest => 'regexeqsel', oprjoin => 'regexeqjoinsel' }, +{ oid => '642', descr => 'does not match regular expression, case-sensitive', + oprname => '!~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '~(text,text)', oprcode => 'textregexne', + oprrest => 'regexnesel', oprjoin => 'regexnejoinsel' }, +{ oid => '643', descr => 'not equal', + oprname => '<>', oprleft => 'name', oprright => 'name', oprresult => 'bool', + oprcom => '<>(name,name)', oprnegate => '=(name,name)', oprcode => 'namene', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '654', descr => 'concatenate', + oprname => '||', oprleft => 'text', oprright => 'text', oprresult => 'text', + oprcode => 'textcat' }, + +{ oid => '660', descr => 'less than', + oprname => '<', oprleft => 'name', oprright => 'name', oprresult => 'bool', + oprcom => '>(name,name)', oprnegate => '>=(name,name)', oprcode => 'namelt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '661', descr => 'less than or equal', + oprname => '<=', oprleft => 'name', oprright => 'name', oprresult => 'bool', + oprcom => '>=(name,name)', oprnegate => '>(name,name)', oprcode => 'namele', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '662', descr => 'greater than', + oprname => '>', oprleft => 'name', oprright => 'name', oprresult => 'bool', + oprcom => '<(name,name)', oprnegate => '<=(name,name)', oprcode => 'namegt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '663', descr => 'greater than or equal', + oprname => '>=', oprleft => 'name', oprright => 'name', oprresult => 'bool', + oprcom => '<=(name,name)', oprnegate => '<(name,name)', oprcode => 'namege', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '664', oid_symbol => 'TextLessOperator', descr => 'less than', + oprname => '<', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '>(text,text)', oprnegate => '>=(text,text)', oprcode => 'text_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '665', descr => 'less than or equal', + oprname => '<=', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '>=(text,text)', oprnegate => '>(text,text)', oprcode => 'text_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '666', descr => 'greater than', + oprname => '>', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '<(text,text)', oprnegate => '<=(text,text)', oprcode => 'text_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '667', oid_symbol => 'TextGreaterEqualOperator', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '<=(text,text)', oprnegate => '<(text,text)', oprcode => 'text_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '670', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'float8', + oprright => 'float8', oprresult => 'bool', oprcom => '=(float8,float8)', + oprnegate => '<>(float8,float8)', oprcode => 'float8eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '671', descr => 'not equal', + oprname => '<>', oprleft => 'float8', oprright => 'float8', + oprresult => 'bool', oprcom => '<>(float8,float8)', + oprnegate => '=(float8,float8)', oprcode => 'float8ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '672', oid_symbol => 'Float8LessOperator', descr => 'less than', + oprname => '<', oprleft => 'float8', oprright => 'float8', + oprresult => 'bool', oprcom => '>(float8,float8)', + oprnegate => '>=(float8,float8)', oprcode => 'float8lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '673', descr => 'less than or equal', + oprname => '<=', oprleft => 'float8', oprright => 'float8', + oprresult => 'bool', oprcom => '>=(float8,float8)', + oprnegate => '>(float8,float8)', oprcode => 'float8le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '674', descr => 'greater than', + oprname => '>', oprleft => 'float8', oprright => 'float8', + oprresult => 'bool', oprcom => '<(float8,float8)', + oprnegate => '<=(float8,float8)', oprcode => 'float8gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '675', descr => 'greater than or equal', + oprname => '>=', oprleft => 'float8', oprright => 'float8', + oprresult => 'bool', oprcom => '<=(float8,float8)', + oprnegate => '<(float8,float8)', oprcode => 'float8ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '682', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'int2', + oprresult => 'int2', oprcode => 'int2abs' }, +{ oid => '684', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcom => '+(int8,int8)', oprcode => 'int8pl' }, +{ oid => '685', descr => 'subtract', + oprname => '-', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcode => 'int8mi' }, +{ oid => '686', descr => 'multiply', + oprname => '*', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcom => '*(int8,int8)', oprcode => 'int8mul' }, +{ oid => '687', descr => 'divide', + oprname => '/', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcode => 'int8div' }, + +{ oid => '688', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcom => '+(int4,int8)', oprcode => 'int84pl' }, +{ oid => '689', descr => 'subtract', + oprname => '-', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcode => 'int84mi' }, +{ oid => '690', descr => 'multiply', + oprname => '*', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcom => '*(int4,int8)', oprcode => 'int84mul' }, +{ oid => '691', descr => 'divide', + oprname => '/', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcode => 'int84div' }, +{ oid => '692', descr => 'add', + oprname => '+', oprleft => 'int4', oprright => 'int8', oprresult => 'int8', + oprcom => '+(int8,int4)', oprcode => 'int48pl' }, +{ oid => '693', descr => 'subtract', + oprname => '-', oprleft => 'int4', oprright => 'int8', oprresult => 'int8', + oprcode => 'int48mi' }, +{ oid => '694', descr => 'multiply', + oprname => '*', oprleft => 'int4', oprright => 'int8', oprresult => 'int8', + oprcom => '*(int8,int4)', oprcode => 'int48mul' }, +{ oid => '695', descr => 'divide', + oprname => '/', oprleft => 'int4', oprright => 'int8', oprresult => 'int8', + oprcode => 'int48div' }, + +{ oid => '818', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'int2', oprresult => 'int8', + oprcom => '+(int2,int8)', oprcode => 'int82pl' }, +{ oid => '819', descr => 'subtract', + oprname => '-', oprleft => 'int8', oprright => 'int2', oprresult => 'int8', + oprcode => 'int82mi' }, +{ oid => '820', descr => 'multiply', + oprname => '*', oprleft => 'int8', oprright => 'int2', oprresult => 'int8', + oprcom => '*(int2,int8)', oprcode => 'int82mul' }, +{ oid => '821', descr => 'divide', + oprname => '/', oprleft => 'int8', oprright => 'int2', oprresult => 'int8', + oprcode => 'int82div' }, +{ oid => '822', descr => 'add', + oprname => '+', oprleft => 'int2', oprright => 'int8', oprresult => 'int8', + oprcom => '+(int8,int2)', oprcode => 'int28pl' }, +{ oid => '823', descr => 'subtract', + oprname => '-', oprleft => 'int2', oprright => 'int8', oprresult => 'int8', + oprcode => 'int28mi' }, +{ oid => '824', descr => 'multiply', + oprname => '*', oprleft => 'int2', oprright => 'int8', oprresult => 'int8', + oprcom => '*(int8,int2)', oprcode => 'int28mul' }, +{ oid => '825', descr => 'divide', + oprname => '/', oprleft => 'int2', oprright => 'int8', oprresult => 'int8', + oprcode => 'int28div' }, + +{ oid => '706', descr => 'distance between', + oprname => '<->', oprleft => 'box', oprright => 'box', oprresult => 'float8', + oprcom => '<->(box,box)', oprcode => 'box_distance' }, +{ oid => '707', descr => 'distance between', + oprname => '<->', oprleft => 'path', oprright => 'path', + oprresult => 'float8', oprcom => '<->(path,path)', + oprcode => 'path_distance' }, +{ oid => '708', descr => 'distance between', + oprname => '<->', oprleft => 'line', oprright => 'line', + oprresult => 'float8', oprcom => '<->(line,line)', + oprcode => 'line_distance' }, +{ oid => '709', descr => 'distance between', + oprname => '<->', oprleft => 'lseg', oprright => 'lseg', + oprresult => 'float8', oprcom => '<->(lseg,lseg)', + oprcode => 'lseg_distance' }, +{ oid => '712', descr => 'distance between', + oprname => '<->', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'float8', oprcom => '<->(polygon,polygon)', + oprcode => 'poly_distance' }, + +{ oid => '713', descr => 'not equal', + oprname => '<>', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcom => '<>(point,point)', oprnegate => '~=(point,point)', + oprcode => 'point_ne', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +# add translation/rotation/scaling operators for geometric types. - thomas 97/05/10 +{ oid => '731', descr => 'add points (translate)', + oprname => '+', oprleft => 'point', oprright => 'point', oprresult => 'point', + oprcom => '+(point,point)', oprcode => 'point_add' }, +{ oid => '732', descr => 'subtract points (translate)', + oprname => '-', oprleft => 'point', oprright => 'point', oprresult => 'point', + oprcode => 'point_sub' }, +{ oid => '733', descr => 'multiply points (scale/rotate)', + oprname => '*', oprleft => 'point', oprright => 'point', oprresult => 'point', + oprcom => '*(point,point)', oprcode => 'point_mul' }, +{ oid => '734', descr => 'divide points (scale/rotate)', + oprname => '/', oprleft => 'point', oprright => 'point', oprresult => 'point', + oprcode => 'point_div' }, +{ oid => '735', descr => 'concatenate', + oprname => '+', oprleft => 'path', oprright => 'path', oprresult => 'path', + oprcom => '+(path,path)', oprcode => 'path_add' }, +{ oid => '736', descr => 'add (translate path)', + oprname => '+', oprleft => 'path', oprright => 'point', oprresult => 'path', + oprcode => 'path_add_pt' }, +{ oid => '737', descr => 'subtract (translate path)', + oprname => '-', oprleft => 'path', oprright => 'point', oprresult => 'path', + oprcode => 'path_sub_pt' }, +{ oid => '738', descr => 'multiply (rotate/scale path)', + oprname => '*', oprleft => 'path', oprright => 'point', oprresult => 'path', + oprcode => 'path_mul_pt' }, +{ oid => '739', descr => 'divide (rotate/scale path)', + oprname => '/', oprleft => 'path', oprright => 'point', oprresult => 'path', + oprcode => 'path_div_pt' }, +{ oid => '755', descr => 'contains', + oprname => '@>', oprleft => 'path', oprright => 'point', oprresult => 'bool', + oprcom => '<@(point,path)', oprcode => 'path_contain_pt' }, +{ oid => '756', descr => 'is contained by', + oprname => '<@', oprleft => 'point', oprright => 'polygon', + oprresult => 'bool', oprcom => '@>(polygon,point)', + oprcode => 'pt_contained_poly', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '757', descr => 'contains', + oprname => '@>', oprleft => 'polygon', oprright => 'point', + oprresult => 'bool', oprcom => '<@(point,polygon)', + oprcode => 'poly_contain_pt', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '758', descr => 'is contained by', + oprname => '<@', oprleft => 'point', oprright => 'circle', + oprresult => 'bool', oprcom => '@>(circle,point)', + oprcode => 'pt_contained_circle', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '759', descr => 'contains', + oprname => '@>', oprleft => 'circle', oprright => 'point', + oprresult => 'bool', oprcom => '<@(point,circle)', + oprcode => 'circle_contain_pt', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, + +{ oid => '773', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'int4', + oprresult => 'int4', oprcode => 'int4abs' }, + +# additional operators for geometric types - thomas 1997-07-09 +{ oid => '792', descr => 'equal', + oprname => '=', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcom => '=(path,path)', oprcode => 'path_n_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '793', descr => 'less than', + oprname => '<', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcom => '>(path,path)', oprcode => 'path_n_lt' }, +{ oid => '794', descr => 'greater than', + oprname => '>', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcom => '<(path,path)', oprcode => 'path_n_gt' }, +{ oid => '795', descr => 'less than or equal', + oprname => '<=', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcom => '>=(path,path)', oprcode => 'path_n_le' }, +{ oid => '796', descr => 'greater than or equal', + oprname => '>=', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcom => '<=(path,path)', oprcode => 'path_n_ge' }, +{ oid => '797', descr => 'number of points', + oprname => '#', oprkind => 'l', oprleft => '0', oprright => 'path', + oprresult => 'int4', oprcode => 'path_npoints' }, +{ oid => '798', descr => 'intersect', + oprname => '?#', oprleft => 'path', oprright => 'path', oprresult => 'bool', + oprcode => 'path_inter' }, +{ oid => '799', descr => 'sum of path segment lengths', + oprname => '@-@', oprkind => 'l', oprleft => '0', oprright => 'path', + oprresult => 'float8', oprcode => 'path_length' }, +{ oid => '800', descr => 'is above (allows touching)', + oprname => '>^', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_above_eq', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '801', descr => 'is below (allows touching)', + oprname => '<^', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_below_eq', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '802', descr => 'deprecated, use && instead', + oprname => '?#', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_overlap', oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '803', descr => 'box intersection', + oprname => '#', oprleft => 'box', oprright => 'box', oprresult => 'box', + oprcode => 'box_intersect' }, +{ oid => '804', descr => 'add point to box (translate)', + oprname => '+', oprleft => 'box', oprright => 'point', oprresult => 'box', + oprcode => 'box_add' }, +{ oid => '805', descr => 'subtract point from box (translate)', + oprname => '-', oprleft => 'box', oprright => 'point', oprresult => 'box', + oprcode => 'box_sub' }, +{ oid => '806', descr => 'multiply box by point (scale)', + oprname => '*', oprleft => 'box', oprright => 'point', oprresult => 'box', + oprcode => 'box_mul' }, +{ oid => '807', descr => 'divide box by point (scale)', + oprname => '/', oprleft => 'box', oprright => 'point', oprresult => 'box', + oprcode => 'box_div' }, +{ oid => '808', descr => 'horizontally aligned', + oprname => '?-', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcom => '?-(point,point)', oprcode => 'point_horiz' }, +{ oid => '809', descr => 'vertically aligned', + oprname => '?|', oprleft => 'point', oprright => 'point', oprresult => 'bool', + oprcom => '?|(point,point)', oprcode => 'point_vert' }, + +{ oid => '843', descr => 'multiply', + oprname => '*', oprleft => 'money', oprright => 'float4', + oprresult => 'money', oprcom => '*(float4,money)', + oprcode => 'cash_mul_flt4' }, +{ oid => '844', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'float4', + oprresult => 'money', oprcode => 'cash_div_flt4' }, +{ oid => '845', descr => 'multiply', + oprname => '*', oprleft => 'float4', oprright => 'money', + oprresult => 'money', oprcom => '*(money,float4)', + oprcode => 'flt4_mul_cash' }, + +{ oid => '900', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'money', oprright => 'money', + oprresult => 'bool', oprcom => '=(money,money)', + oprnegate => '<>(money,money)', oprcode => 'cash_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '901', descr => 'not equal', + oprname => '<>', oprleft => 'money', oprright => 'money', oprresult => 'bool', + oprcom => '<>(money,money)', oprnegate => '=(money,money)', + oprcode => 'cash_ne', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '902', descr => 'less than', + oprname => '<', oprleft => 'money', oprright => 'money', oprresult => 'bool', + oprcom => '>(money,money)', oprnegate => '>=(money,money)', + oprcode => 'cash_lt', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '903', descr => 'greater than', + oprname => '>', oprleft => 'money', oprright => 'money', oprresult => 'bool', + oprcom => '<(money,money)', oprnegate => '<=(money,money)', + oprcode => 'cash_gt', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '904', descr => 'less than or equal', + oprname => '<=', oprleft => 'money', oprright => 'money', oprresult => 'bool', + oprcom => '>=(money,money)', oprnegate => '>(money,money)', + oprcode => 'cash_le', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '905', descr => 'greater than or equal', + oprname => '>=', oprleft => 'money', oprright => 'money', oprresult => 'bool', + oprcom => '<=(money,money)', oprnegate => '<(money,money)', + oprcode => 'cash_ge', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '906', descr => 'add', + oprname => '+', oprleft => 'money', oprright => 'money', oprresult => 'money', + oprcom => '+(money,money)', oprcode => 'cash_pl' }, +{ oid => '907', descr => 'subtract', + oprname => '-', oprleft => 'money', oprright => 'money', oprresult => 'money', + oprcode => 'cash_mi' }, +{ oid => '908', descr => 'multiply', + oprname => '*', oprleft => 'money', oprright => 'float8', + oprresult => 'money', oprcom => '*(float8,money)', + oprcode => 'cash_mul_flt8' }, +{ oid => '909', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'float8', + oprresult => 'money', oprcode => 'cash_div_flt8' }, +{ oid => '3346', descr => 'multiply', + oprname => '*', oprleft => 'money', oprright => 'int8', oprresult => 'money', + oprcom => '*(int8,money)', oprcode => 'cash_mul_int8' }, +{ oid => '3347', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'int8', oprresult => 'money', + oprcode => 'cash_div_int8' }, +{ oid => '912', descr => 'multiply', + oprname => '*', oprleft => 'money', oprright => 'int4', oprresult => 'money', + oprcom => '*(int4,money)', oprcode => 'cash_mul_int4' }, +{ oid => '913', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'int4', oprresult => 'money', + oprcode => 'cash_div_int4' }, +{ oid => '914', descr => 'multiply', + oprname => '*', oprleft => 'money', oprright => 'int2', oprresult => 'money', + oprcom => '*(int2,money)', oprcode => 'cash_mul_int2' }, +{ oid => '915', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'int2', oprresult => 'money', + oprcode => 'cash_div_int2' }, +{ oid => '916', descr => 'multiply', + oprname => '*', oprleft => 'float8', oprright => 'money', + oprresult => 'money', oprcom => '*(money,float8)', + oprcode => 'flt8_mul_cash' }, +{ oid => '3349', descr => 'multiply', + oprname => '*', oprleft => 'int8', oprright => 'money', oprresult => 'money', + oprcom => '*(money,int8)', oprcode => 'int8_mul_cash' }, +{ oid => '917', descr => 'multiply', + oprname => '*', oprleft => 'int4', oprright => 'money', oprresult => 'money', + oprcom => '*(money,int4)', oprcode => 'int4_mul_cash' }, +{ oid => '918', descr => 'multiply', + oprname => '*', oprleft => 'int2', oprright => 'money', oprresult => 'money', + oprcom => '*(money,int2)', oprcode => 'int2_mul_cash' }, +{ oid => '3825', descr => 'divide', + oprname => '/', oprleft => 'money', oprright => 'money', + oprresult => 'float8', oprcode => 'cash_div_cash' }, + +{ oid => '965', descr => 'exponentiation', + oprname => '^', oprleft => 'float8', oprright => 'float8', + oprresult => 'float8', oprcode => 'dpow' }, +{ oid => '966', descr => 'add/update ACL item', + oprname => '+', oprleft => '_aclitem', oprright => 'aclitem', + oprresult => '_aclitem', oprcode => 'aclinsert' }, +{ oid => '967', descr => 'remove ACL item', + oprname => '-', oprleft => '_aclitem', oprright => 'aclitem', + oprresult => '_aclitem', oprcode => 'aclremove' }, +{ oid => '968', descr => 'contains', + oprname => '@>', oprleft => '_aclitem', oprright => 'aclitem', + oprresult => 'bool', oprcode => 'aclcontains' }, +{ oid => '974', descr => 'equal', + oprname => '=', oprcanhash => 't', oprleft => 'aclitem', + oprright => 'aclitem', oprresult => 'bool', oprcom => '=(aclitem,aclitem)', + oprcode => 'aclitemeq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, + +# additional geometric operators - thomas 1997-07-09 +{ oid => '969', descr => 'center of', + oprname => '@@', oprkind => 'l', oprleft => '0', oprright => 'lseg', + oprresult => 'point', oprcode => 'lseg_center' }, +{ oid => '971', descr => 'center of', + oprname => '@@', oprkind => 'l', oprleft => '0', oprright => 'polygon', + oprresult => 'point', oprcode => 'poly_center' }, + +{ oid => '1054', oid_symbol => 'BpcharEqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'bpchar', + oprright => 'bpchar', oprresult => 'bool', oprcom => '=(bpchar,bpchar)', + oprnegate => '<>(bpchar,bpchar)', oprcode => 'bpchareq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, + +{ oid => '1055', oid_symbol => 'OID_BPCHAR_REGEXEQ_OP', + descr => 'matches regular expression, case-sensitive', + oprname => '~', oprleft => 'bpchar', oprright => 'text', oprresult => 'bool', + oprnegate => '!~(bpchar,text)', oprcode => 'bpcharregexeq', + oprrest => 'regexeqsel', oprjoin => 'regexeqjoinsel' }, +{ oid => '1056', descr => 'does not match regular expression, case-sensitive', + oprname => '!~', oprleft => 'bpchar', oprright => 'text', oprresult => 'bool', + oprnegate => '~(bpchar,text)', oprcode => 'bpcharregexne', + oprrest => 'regexnesel', oprjoin => 'regexnejoinsel' }, +{ oid => '1057', descr => 'not equal', + oprname => '<>', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '<>(bpchar,bpchar)', + oprnegate => '=(bpchar,bpchar)', oprcode => 'bpcharne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1058', oid_symbol => 'BpcharLessOperator', descr => 'less than', + oprname => '<', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '>(bpchar,bpchar)', + oprnegate => '>=(bpchar,bpchar)', oprcode => 'bpcharlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1059', descr => 'less than or equal', + oprname => '<=', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '>=(bpchar,bpchar)', + oprnegate => '>(bpchar,bpchar)', oprcode => 'bpcharle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1060', descr => 'greater than', + oprname => '>', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '<(bpchar,bpchar)', + oprnegate => '<=(bpchar,bpchar)', oprcode => 'bpchargt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1061', oid_symbol => 'BpcharGreaterEqualOperator', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '<=(bpchar,bpchar)', + oprnegate => '<(bpchar,bpchar)', oprcode => 'bpcharge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# generic array comparison operators +{ oid => '1070', oid_symbol => 'ARRAY_EQ_OP', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'anyarray', + oprright => 'anyarray', oprresult => 'bool', oprcom => '=(anyarray,anyarray)', + oprnegate => '<>(anyarray,anyarray)', oprcode => 'array_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1071', descr => 'not equal', + oprname => '<>', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '<>(anyarray,anyarray)', + oprnegate => '=(anyarray,anyarray)', oprcode => 'array_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1072', oid_symbol => 'ARRAY_LT_OP', descr => 'less than', + oprname => '<', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '>(anyarray,anyarray)', + oprnegate => '>=(anyarray,anyarray)', oprcode => 'array_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1073', oid_symbol => 'ARRAY_GT_OP', descr => 'greater than', + oprname => '>', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '<(anyarray,anyarray)', + oprnegate => '<=(anyarray,anyarray)', oprcode => 'array_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1074', descr => 'less than or equal', + oprname => '<=', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '>=(anyarray,anyarray)', + oprnegate => '>(anyarray,anyarray)', oprcode => 'array_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1075', descr => 'greater than or equal', + oprname => '>=', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '<=(anyarray,anyarray)', + oprnegate => '<(anyarray,anyarray)', oprcode => 'array_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# date operators +{ oid => '1076', descr => 'add', + oprname => '+', oprleft => 'date', oprright => 'interval', + oprresult => 'timestamp', oprcom => '+(interval,date)', + oprcode => 'date_pl_interval' }, +{ oid => '1077', descr => 'subtract', + oprname => '-', oprleft => 'date', oprright => 'interval', + oprresult => 'timestamp', oprcode => 'date_mi_interval' }, +{ oid => '1093', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'date', + oprright => 'date', oprresult => 'bool', oprcom => '=(date,date)', + oprnegate => '<>(date,date)', oprcode => 'date_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1094', descr => 'not equal', + oprname => '<>', oprleft => 'date', oprright => 'date', oprresult => 'bool', + oprcom => '<>(date,date)', oprnegate => '=(date,date)', oprcode => 'date_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1095', descr => 'less than', + oprname => '<', oprleft => 'date', oprright => 'date', oprresult => 'bool', + oprcom => '>(date,date)', oprnegate => '>=(date,date)', oprcode => 'date_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1096', descr => 'less than or equal', + oprname => '<=', oprleft => 'date', oprright => 'date', oprresult => 'bool', + oprcom => '>=(date,date)', oprnegate => '>(date,date)', oprcode => 'date_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1097', descr => 'greater than', + oprname => '>', oprleft => 'date', oprright => 'date', oprresult => 'bool', + oprcom => '<(date,date)', oprnegate => '<=(date,date)', oprcode => 'date_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1098', descr => 'greater than or equal', + oprname => '>=', oprleft => 'date', oprright => 'date', oprresult => 'bool', + oprcom => '<=(date,date)', oprnegate => '<(date,date)', oprcode => 'date_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '1099', descr => 'subtract', + oprname => '-', oprleft => 'date', oprright => 'date', oprresult => 'int4', + oprcode => 'date_mi' }, +{ oid => '1100', descr => 'add', + oprname => '+', oprleft => 'date', oprright => 'int4', oprresult => 'date', + oprcom => '+(int4,date)', oprcode => 'date_pli' }, +{ oid => '1101', descr => 'subtract', + oprname => '-', oprleft => 'date', oprright => 'int4', oprresult => 'date', + oprcode => 'date_mii' }, + +# time operators +{ oid => '1108', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'time', + oprright => 'time', oprresult => 'bool', oprcom => '=(time,time)', + oprnegate => '<>(time,time)', oprcode => 'time_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1109', descr => 'not equal', + oprname => '<>', oprleft => 'time', oprright => 'time', oprresult => 'bool', + oprcom => '<>(time,time)', oprnegate => '=(time,time)', oprcode => 'time_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1110', descr => 'less than', + oprname => '<', oprleft => 'time', oprright => 'time', oprresult => 'bool', + oprcom => '>(time,time)', oprnegate => '>=(time,time)', oprcode => 'time_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1111', descr => 'less than or equal', + oprname => '<=', oprleft => 'time', oprright => 'time', oprresult => 'bool', + oprcom => '>=(time,time)', oprnegate => '>(time,time)', oprcode => 'time_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1112', descr => 'greater than', + oprname => '>', oprleft => 'time', oprright => 'time', oprresult => 'bool', + oprcom => '<(time,time)', oprnegate => '<=(time,time)', oprcode => 'time_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1113', descr => 'greater than or equal', + oprname => '>=', oprleft => 'time', oprright => 'time', oprresult => 'bool', + oprcom => '<=(time,time)', oprnegate => '<(time,time)', oprcode => 'time_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# timetz operators +{ oid => '1550', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'timetz', + oprright => 'timetz', oprresult => 'bool', oprcom => '=(timetz,timetz)', + oprnegate => '<>(timetz,timetz)', oprcode => 'timetz_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1551', descr => 'not equal', + oprname => '<>', oprleft => 'timetz', oprright => 'timetz', + oprresult => 'bool', oprcom => '<>(timetz,timetz)', + oprnegate => '=(timetz,timetz)', oprcode => 'timetz_ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1552', descr => 'less than', + oprname => '<', oprleft => 'timetz', oprright => 'timetz', + oprresult => 'bool', oprcom => '>(timetz,timetz)', + oprnegate => '>=(timetz,timetz)', oprcode => 'timetz_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1553', descr => 'less than or equal', + oprname => '<=', oprleft => 'timetz', oprright => 'timetz', + oprresult => 'bool', oprcom => '>=(timetz,timetz)', + oprnegate => '>(timetz,timetz)', oprcode => 'timetz_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1554', descr => 'greater than', + oprname => '>', oprleft => 'timetz', oprright => 'timetz', + oprresult => 'bool', oprcom => '<(timetz,timetz)', + oprnegate => '<=(timetz,timetz)', oprcode => 'timetz_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1555', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timetz', oprright => 'timetz', + oprresult => 'bool', oprcom => '<=(timetz,timetz)', + oprnegate => '<(timetz,timetz)', oprcode => 'timetz_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# float48 operators +{ oid => '1116', descr => 'add', + oprname => '+', oprleft => 'float4', oprright => 'float8', + oprresult => 'float8', oprcom => '+(float8,float4)', oprcode => 'float48pl' }, +{ oid => '1117', descr => 'subtract', + oprname => '-', oprleft => 'float4', oprright => 'float8', + oprresult => 'float8', oprcode => 'float48mi' }, +{ oid => '1118', descr => 'divide', + oprname => '/', oprleft => 'float4', oprright => 'float8', + oprresult => 'float8', oprcode => 'float48div' }, +{ oid => '1119', descr => 'multiply', + oprname => '*', oprleft => 'float4', oprright => 'float8', + oprresult => 'float8', oprcom => '*(float8,float4)', + oprcode => 'float48mul' }, +{ oid => '1120', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'float4', + oprright => 'float8', oprresult => 'bool', oprcom => '=(float8,float4)', + oprnegate => '<>(float4,float8)', oprcode => 'float48eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1121', descr => 'not equal', + oprname => '<>', oprleft => 'float4', oprright => 'float8', + oprresult => 'bool', oprcom => '<>(float8,float4)', + oprnegate => '=(float4,float8)', oprcode => 'float48ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1122', descr => 'less than', + oprname => '<', oprleft => 'float4', oprright => 'float8', + oprresult => 'bool', oprcom => '>(float8,float4)', + oprnegate => '>=(float4,float8)', oprcode => 'float48lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1123', descr => 'greater than', + oprname => '>', oprleft => 'float4', oprright => 'float8', + oprresult => 'bool', oprcom => '<(float8,float4)', + oprnegate => '<=(float4,float8)', oprcode => 'float48gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1124', descr => 'less than or equal', + oprname => '<=', oprleft => 'float4', oprright => 'float8', + oprresult => 'bool', oprcom => '>=(float8,float4)', + oprnegate => '>(float4,float8)', oprcode => 'float48le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1125', descr => 'greater than or equal', + oprname => '>=', oprleft => 'float4', oprright => 'float8', + oprresult => 'bool', oprcom => '<=(float8,float4)', + oprnegate => '<(float4,float8)', oprcode => 'float48ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# float84 operators +{ oid => '1126', descr => 'add', + oprname => '+', oprleft => 'float8', oprright => 'float4', + oprresult => 'float8', oprcom => '+(float4,float8)', oprcode => 'float84pl' }, +{ oid => '1127', descr => 'subtract', + oprname => '-', oprleft => 'float8', oprright => 'float4', + oprresult => 'float8', oprcode => 'float84mi' }, +{ oid => '1128', descr => 'divide', + oprname => '/', oprleft => 'float8', oprright => 'float4', + oprresult => 'float8', oprcode => 'float84div' }, +{ oid => '1129', descr => 'multiply', + oprname => '*', oprleft => 'float8', oprright => 'float4', + oprresult => 'float8', oprcom => '*(float4,float8)', + oprcode => 'float84mul' }, +{ oid => '1130', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'float8', + oprright => 'float4', oprresult => 'bool', oprcom => '=(float4,float8)', + oprnegate => '<>(float8,float4)', oprcode => 'float84eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1131', descr => 'not equal', + oprname => '<>', oprleft => 'float8', oprright => 'float4', + oprresult => 'bool', oprcom => '<>(float4,float8)', + oprnegate => '=(float8,float4)', oprcode => 'float84ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1132', descr => 'less than', + oprname => '<', oprleft => 'float8', oprright => 'float4', + oprresult => 'bool', oprcom => '>(float4,float8)', + oprnegate => '>=(float8,float4)', oprcode => 'float84lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1133', descr => 'greater than', + oprname => '>', oprleft => 'float8', oprright => 'float4', + oprresult => 'bool', oprcom => '<(float4,float8)', + oprnegate => '<=(float8,float4)', oprcode => 'float84gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1134', descr => 'less than or equal', + oprname => '<=', oprleft => 'float8', oprright => 'float4', + oprresult => 'bool', oprcom => '>=(float4,float8)', + oprnegate => '>(float8,float4)', oprcode => 'float84le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1135', descr => 'greater than or equal', + oprname => '>=', oprleft => 'float8', oprright => 'float4', + oprresult => 'bool', oprcom => '<=(float4,float8)', + oprnegate => '<(float8,float4)', oprcode => 'float84ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# LIKE hacks by Keith Parks. +{ oid => '1207', oid_symbol => 'OID_NAME_LIKE_OP', + descr => 'matches LIKE expression', + oprname => '~~', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '!~~(name,text)', oprcode => 'namelike', oprrest => 'likesel', + oprjoin => 'likejoinsel' }, +{ oid => '1208', descr => 'does not match LIKE expression', + oprname => '!~~', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '~~(name,text)', oprcode => 'namenlike', oprrest => 'nlikesel', + oprjoin => 'nlikejoinsel' }, +{ oid => '1209', oid_symbol => 'OID_TEXT_LIKE_OP', + descr => 'matches LIKE expression', + oprname => '~~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '!~~(text,text)', oprcode => 'textlike', oprrest => 'likesel', + oprjoin => 'likejoinsel' }, +{ oid => '1210', descr => 'does not match LIKE expression', + oprname => '!~~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '~~(text,text)', oprcode => 'textnlike', oprrest => 'nlikesel', + oprjoin => 'nlikejoinsel' }, +{ oid => '1211', oid_symbol => 'OID_BPCHAR_LIKE_OP', + descr => 'matches LIKE expression', + oprname => '~~', oprleft => 'bpchar', oprright => 'text', oprresult => 'bool', + oprnegate => '!~~(bpchar,text)', oprcode => 'bpcharlike', + oprrest => 'likesel', oprjoin => 'likejoinsel' }, +{ oid => '1212', descr => 'does not match LIKE expression', + oprname => '!~~', oprleft => 'bpchar', oprright => 'text', + oprresult => 'bool', oprnegate => '~~(bpchar,text)', oprcode => 'bpcharnlike', + oprrest => 'nlikesel', oprjoin => 'nlikejoinsel' }, + +# case-insensitive regex hacks +{ oid => '1226', oid_symbol => 'OID_NAME_ICREGEXEQ_OP', + descr => 'matches regular expression, case-insensitive', + oprname => '~*', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '!~*(name,text)', oprcode => 'nameicregexeq', + oprrest => 'icregexeqsel', oprjoin => 'icregexeqjoinsel' }, +{ oid => '1227', + descr => 'does not match regular expression, case-insensitive', + oprname => '!~*', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '~*(name,text)', oprcode => 'nameicregexne', + oprrest => 'icregexnesel', oprjoin => 'icregexnejoinsel' }, +{ oid => '1228', oid_symbol => 'OID_TEXT_ICREGEXEQ_OP', + descr => 'matches regular expression, case-insensitive', + oprname => '~*', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '!~*(text,text)', oprcode => 'texticregexeq', + oprrest => 'icregexeqsel', oprjoin => 'icregexeqjoinsel' }, +{ oid => '1229', + descr => 'does not match regular expression, case-insensitive', + oprname => '!~*', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '~*(text,text)', oprcode => 'texticregexne', + oprrest => 'icregexnesel', oprjoin => 'icregexnejoinsel' }, +{ oid => '1234', oid_symbol => 'OID_BPCHAR_ICREGEXEQ_OP', + descr => 'matches regular expression, case-insensitive', + oprname => '~*', oprleft => 'bpchar', oprright => 'text', oprresult => 'bool', + oprnegate => '!~*(bpchar,text)', oprcode => 'bpcharicregexeq', + oprrest => 'icregexeqsel', oprjoin => 'icregexeqjoinsel' }, +{ oid => '1235', + descr => 'does not match regular expression, case-insensitive', + oprname => '!~*', oprleft => 'bpchar', oprright => 'text', + oprresult => 'bool', oprnegate => '~*(bpchar,text)', + oprcode => 'bpcharicregexne', oprrest => 'icregexnesel', + oprjoin => 'icregexnejoinsel' }, + +# timestamptz operators +{ oid => '1320', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', + oprleft => 'timestamptz', oprright => 'timestamptz', oprresult => 'bool', + oprcom => '=(timestamptz,timestamptz)', + oprnegate => '<>(timestamptz,timestamptz)', oprcode => 'timestamptz_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1321', descr => 'not equal', + oprname => '<>', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<>(timestamptz,timestamptz)', + oprnegate => '=(timestamptz,timestamptz)', oprcode => 'timestamptz_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1322', descr => 'less than', + oprname => '<', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>(timestamptz,timestamptz)', + oprnegate => '>=(timestamptz,timestamptz)', oprcode => 'timestamptz_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1323', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>=(timestamptz,timestamptz)', + oprnegate => '>(timestamptz,timestamptz)', oprcode => 'timestamptz_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1324', descr => 'greater than', + oprname => '>', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<(timestamptz,timestamptz)', + oprnegate => '<=(timestamptz,timestamptz)', oprcode => 'timestamptz_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1325', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<=(timestamptz,timestamptz)', + oprnegate => '<(timestamptz,timestamptz)', oprcode => 'timestamptz_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '1327', descr => 'add', + oprname => '+', oprleft => 'timestamptz', oprright => 'interval', + oprresult => 'timestamptz', oprcom => '+(interval,timestamptz)', + oprcode => 'timestamptz_pl_interval' }, +{ oid => '1328', descr => 'subtract', + oprname => '-', oprleft => 'timestamptz', oprright => 'timestamptz', + oprresult => 'interval', oprcode => 'timestamptz_mi' }, +{ oid => '1329', descr => 'subtract', + oprname => '-', oprleft => 'timestamptz', oprright => 'interval', + oprresult => 'timestamptz', oprcode => 'timestamptz_mi_interval' }, + +# interval operators +{ oid => '1330', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'interval', + oprright => 'interval', oprresult => 'bool', oprcom => '=(interval,interval)', + oprnegate => '<>(interval,interval)', oprcode => 'interval_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1331', descr => 'not equal', + oprname => '<>', oprleft => 'interval', oprright => 'interval', + oprresult => 'bool', oprcom => '<>(interval,interval)', + oprnegate => '=(interval,interval)', oprcode => 'interval_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1332', descr => 'less than', + oprname => '<', oprleft => 'interval', oprright => 'interval', + oprresult => 'bool', oprcom => '>(interval,interval)', + oprnegate => '>=(interval,interval)', oprcode => 'interval_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1333', descr => 'less than or equal', + oprname => '<=', oprleft => 'interval', oprright => 'interval', + oprresult => 'bool', oprcom => '>=(interval,interval)', + oprnegate => '>(interval,interval)', oprcode => 'interval_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1334', descr => 'greater than', + oprname => '>', oprleft => 'interval', oprright => 'interval', + oprresult => 'bool', oprcom => '<(interval,interval)', + oprnegate => '<=(interval,interval)', oprcode => 'interval_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1335', descr => 'greater than or equal', + oprname => '>=', oprleft => 'interval', oprright => 'interval', + oprresult => 'bool', oprcom => '<=(interval,interval)', + oprnegate => '<(interval,interval)', oprcode => 'interval_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '1336', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'interval', + oprresult => 'interval', oprcode => 'interval_um' }, +{ oid => '1337', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'interval', + oprresult => 'interval', oprcom => '+(interval,interval)', + oprcode => 'interval_pl' }, +{ oid => '1338', descr => 'subtract', + oprname => '-', oprleft => 'interval', oprright => 'interval', + oprresult => 'interval', oprcode => 'interval_mi' }, + +{ oid => '1360', descr => 'convert date and time to timestamp', + oprname => '+', oprleft => 'date', oprright => 'time', + oprresult => 'timestamp', oprcom => '+(time,date)', + oprcode => 'datetime_pl' }, +{ oid => '1361', + descr => 'convert date and time with time zone to timestamp with time zone', + oprname => '+', oprleft => 'date', oprright => 'timetz', + oprresult => 'timestamptz', oprcom => '+(timetz,date)', + oprcode => 'datetimetz_pl' }, +{ oid => '1363', descr => 'convert time and date to timestamp', + oprname => '+', oprleft => 'time', oprright => 'date', + oprresult => 'timestamp', oprcom => '+(date,time)', + oprcode => 'timedate_pl' }, +{ oid => '1366', + descr => 'convert time with time zone and date to timestamp with time zone', + oprname => '+', oprleft => 'timetz', oprright => 'date', + oprresult => 'timestamptz', oprcom => '+(date,timetz)', + oprcode => 'timetzdate_pl' }, + +{ oid => '1399', descr => 'subtract', + oprname => '-', oprleft => 'time', oprright => 'time', + oprresult => 'interval', oprcode => 'time_mi_time' }, + +# additional geometric operators - thomas 97/04/18 +{ oid => '1420', descr => 'center of', + oprname => '@@', oprkind => 'l', oprleft => '0', oprright => 'circle', + oprresult => 'point', oprcode => 'circle_center' }, +{ oid => '1500', descr => 'equal by area', + oprname => '=', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '=(circle,circle)', + oprnegate => '<>(circle,circle)', oprcode => 'circle_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1501', descr => 'not equal by area', + oprname => '<>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '<>(circle,circle)', + oprnegate => '=(circle,circle)', oprcode => 'circle_ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1502', descr => 'less than by area', + oprname => '<', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '>(circle,circle)', + oprnegate => '>=(circle,circle)', oprcode => 'circle_lt', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '1503', descr => 'greater than by area', + oprname => '>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '<(circle,circle)', + oprnegate => '<=(circle,circle)', oprcode => 'circle_gt', + oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '1504', descr => 'less than or equal by area', + oprname => '<=', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '>=(circle,circle)', + oprnegate => '>(circle,circle)', oprcode => 'circle_le', oprrest => 'areasel', + oprjoin => 'areajoinsel' }, +{ oid => '1505', descr => 'greater than or equal by area', + oprname => '>=', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '<=(circle,circle)', + oprnegate => '<(circle,circle)', oprcode => 'circle_ge', oprrest => 'areasel', + oprjoin => 'areajoinsel' }, + +{ oid => '1506', descr => 'is left of', + oprname => '<<', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_left', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '1507', descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_overleft', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '1508', descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_overright', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '1509', descr => 'is right of', + oprname => '>>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_right', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '1510', descr => 'is contained by', + oprname => '<@', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '@>(circle,circle)', + oprcode => 'circle_contained', oprrest => 'contsel', + oprjoin => 'contjoinsel' }, +{ oid => '1511', descr => 'contains', + oprname => '@>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '<@(circle,circle)', + oprcode => 'circle_contain', oprrest => 'contsel', oprjoin => 'contjoinsel' }, +{ oid => '1512', descr => 'same as', + oprname => '~=', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '~=(circle,circle)', oprcode => 'circle_same', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1513', descr => 'overlaps', + oprname => '&&', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcom => '&&(circle,circle)', + oprcode => 'circle_overlap', oprrest => 'areasel', oprjoin => 'areajoinsel' }, +{ oid => '1514', descr => 'is above', + oprname => '|>>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_above', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '1515', descr => 'is below', + oprname => '<<|', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_below', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, + +{ oid => '1516', descr => 'add', + oprname => '+', oprleft => 'circle', oprright => 'point', + oprresult => 'circle', oprcode => 'circle_add_pt' }, +{ oid => '1517', descr => 'subtract', + oprname => '-', oprleft => 'circle', oprright => 'point', + oprresult => 'circle', oprcode => 'circle_sub_pt' }, +{ oid => '1518', descr => 'multiply', + oprname => '*', oprleft => 'circle', oprright => 'point', + oprresult => 'circle', oprcode => 'circle_mul_pt' }, +{ oid => '1519', descr => 'divide', + oprname => '/', oprleft => 'circle', oprright => 'point', + oprresult => 'circle', oprcode => 'circle_div_pt' }, + +{ oid => '1520', descr => 'distance between', + oprname => '<->', oprleft => 'circle', oprright => 'circle', + oprresult => 'float8', oprcom => '<->(circle,circle)', + oprcode => 'circle_distance' }, +{ oid => '1521', descr => 'number of points', + oprname => '#', oprkind => 'l', oprleft => '0', oprright => 'polygon', + oprresult => 'int4', oprcode => 'poly_npoints' }, +{ oid => '1522', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'circle', + oprresult => 'float8', oprcom => '<->(circle,point)', oprcode => 'dist_pc' }, +{ oid => '3291', descr => 'distance between', + oprname => '<->', oprleft => 'circle', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,circle)', + oprcode => 'dist_cpoint' }, +{ oid => '3276', descr => 'distance between', + oprname => '<->', oprleft => 'point', oprright => 'polygon', + oprresult => 'float8', oprcom => '<->(polygon,point)', + oprcode => 'dist_ppoly' }, +{ oid => '3289', descr => 'distance between', + oprname => '<->', oprleft => 'polygon', oprright => 'point', + oprresult => 'float8', oprcom => '<->(point,polygon)', + oprcode => 'dist_polyp' }, +{ oid => '1523', descr => 'distance between', + oprname => '<->', oprleft => 'circle', oprright => 'polygon', + oprresult => 'float8', oprcom => '<->(polygon,circle)', + oprcode => 'dist_cpoly' }, +{ oid => '1383', descr => 'distance between', + oprname => '<->', oprleft => 'polygon', oprright => 'circle', + oprresult => 'float8', oprcom => '<->(circle,polygon)', + oprcode => 'dist_polyc' }, + +{ oid => '1525', descr => 'intersect', + oprname => '?#', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '?#(lseg,lseg)', oprcode => 'lseg_intersect' }, +{ oid => '1526', descr => 'parallel', + oprname => '?||', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '?||(lseg,lseg)', oprcode => 'lseg_parallel' }, +{ oid => '1527', descr => 'perpendicular', + oprname => '?-|', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '?-|(lseg,lseg)', oprcode => 'lseg_perp' }, +{ oid => '1528', descr => 'horizontal', + oprname => '?-', oprkind => 'l', oprleft => '0', oprright => 'lseg', + oprresult => 'bool', oprcode => 'lseg_horizontal' }, +{ oid => '1529', descr => 'vertical', + oprname => '?|', oprkind => 'l', oprleft => '0', oprright => 'lseg', + oprresult => 'bool', oprcode => 'lseg_vertical' }, +{ oid => '1535', descr => 'equal', + oprname => '=', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '=(lseg,lseg)', oprnegate => '<>(lseg,lseg)', oprcode => 'lseg_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1536', descr => 'intersection point', + oprname => '#', oprleft => 'lseg', oprright => 'lseg', oprresult => 'point', + oprcom => '#(lseg,lseg)', oprcode => 'lseg_interpt' }, +{ oid => '1537', descr => 'intersect', + oprname => '?#', oprleft => 'lseg', oprright => 'line', oprresult => 'bool', + oprcode => 'inter_sl' }, +{ oid => '1538', descr => 'intersect', + oprname => '?#', oprleft => 'lseg', oprright => 'box', oprresult => 'bool', + oprcode => 'inter_sb' }, +{ oid => '1539', descr => 'intersect', + oprname => '?#', oprleft => 'line', oprright => 'box', oprresult => 'bool', + oprcode => 'inter_lb' }, + +{ oid => '1546', descr => 'point on line', + oprname => '<@', oprleft => 'point', oprright => 'line', oprresult => 'bool', + oprcode => 'on_pl' }, +{ oid => '1547', descr => 'is contained by', + oprname => '<@', oprleft => 'point', oprright => 'lseg', oprresult => 'bool', + oprcode => 'on_ps' }, +{ oid => '1548', descr => 'lseg on line', + oprname => '<@', oprleft => 'lseg', oprright => 'line', oprresult => 'bool', + oprcode => 'on_sl' }, +{ oid => '1549', descr => 'is contained by', + oprname => '<@', oprleft => 'lseg', oprright => 'box', oprresult => 'bool', + oprcode => 'on_sb' }, + +{ oid => '1557', descr => 'closest point to A on B', + oprname => '##', oprleft => 'point', oprright => 'line', oprresult => 'point', + oprcode => 'close_pl' }, +{ oid => '1558', descr => 'closest point to A on B', + oprname => '##', oprleft => 'point', oprright => 'lseg', oprresult => 'point', + oprcode => 'close_ps' }, +{ oid => '1559', descr => 'closest point to A on B', + oprname => '##', oprleft => 'point', oprright => 'box', oprresult => 'point', + oprcode => 'close_pb' }, + +{ oid => '1567', descr => 'closest point to A on B', + oprname => '##', oprleft => 'lseg', oprright => 'box', oprresult => 'point', + oprcode => 'close_sb' }, +{ oid => '1577', descr => 'closest point to A on B', + oprname => '##', oprleft => 'line', oprright => 'lseg', oprresult => 'point', + oprcode => 'close_ls' }, +{ oid => '1578', descr => 'closest point to A on B', + oprname => '##', oprleft => 'lseg', oprright => 'lseg', oprresult => 'point', + oprcode => 'close_lseg' }, +{ oid => '1583', descr => 'multiply', + oprname => '*', oprleft => 'interval', oprright => 'float8', + oprresult => 'interval', oprcom => '*(float8,interval)', + oprcode => 'interval_mul' }, +{ oid => '1584', descr => 'multiply', + oprname => '*', oprleft => 'float8', oprright => 'interval', + oprresult => 'interval', oprcom => '*(interval,float8)', + oprcode => 'mul_d_interval' }, +{ oid => '1585', descr => 'divide', + oprname => '/', oprleft => 'interval', oprright => 'float8', + oprresult => 'interval', oprcode => 'interval_div' }, + +{ oid => '1586', descr => 'not equal', + oprname => '<>', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '<>(lseg,lseg)', oprnegate => '=(lseg,lseg)', oprcode => 'lseg_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1587', descr => 'less than by length', + oprname => '<', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '>(lseg,lseg)', oprnegate => '>=(lseg,lseg)', + oprcode => 'lseg_lt' }, +{ oid => '1588', descr => 'less than or equal by length', + oprname => '<=', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '>=(lseg,lseg)', oprnegate => '>(lseg,lseg)', + oprcode => 'lseg_le' }, +{ oid => '1589', descr => 'greater than by length', + oprname => '>', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '<(lseg,lseg)', oprnegate => '<=(lseg,lseg)', + oprcode => 'lseg_gt' }, +{ oid => '1590', descr => 'greater than or equal by length', + oprname => '>=', oprleft => 'lseg', oprright => 'lseg', oprresult => 'bool', + oprcom => '<=(lseg,lseg)', oprnegate => '<(lseg,lseg)', + oprcode => 'lseg_ge' }, + +{ oid => '1591', descr => 'distance between endpoints', + oprname => '@-@', oprkind => 'l', oprleft => '0', oprright => 'lseg', + oprresult => 'float8', oprcode => 'lseg_length' }, + +{ oid => '1611', descr => 'intersect', + oprname => '?#', oprleft => 'line', oprright => 'line', oprresult => 'bool', + oprcom => '?#(line,line)', oprcode => 'line_intersect' }, +{ oid => '1612', descr => 'parallel', + oprname => '?||', oprleft => 'line', oprright => 'line', oprresult => 'bool', + oprcom => '?||(line,line)', oprcode => 'line_parallel' }, +{ oid => '1613', descr => 'perpendicular', + oprname => '?-|', oprleft => 'line', oprright => 'line', oprresult => 'bool', + oprcom => '?-|(line,line)', oprcode => 'line_perp' }, +{ oid => '1614', descr => 'horizontal', + oprname => '?-', oprkind => 'l', oprleft => '0', oprright => 'line', + oprresult => 'bool', oprcode => 'line_horizontal' }, +{ oid => '1615', descr => 'vertical', + oprname => '?|', oprkind => 'l', oprleft => '0', oprright => 'line', + oprresult => 'bool', oprcode => 'line_vertical' }, +{ oid => '1616', descr => 'equal', + oprname => '=', oprleft => 'line', oprright => 'line', oprresult => 'bool', + oprcom => '=(line,line)', oprcode => 'line_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1617', descr => 'intersection point', + oprname => '#', oprleft => 'line', oprright => 'line', oprresult => 'point', + oprcom => '#(line,line)', oprcode => 'line_interpt' }, + +{ oid => '4161', descr => 'is above', + oprname => '|>>', oprleft => 'point', oprright => 'point', + oprresult => 'bool', oprcode => 'point_above', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '4162', descr => 'is below', + oprname => '<<|', oprleft => 'point', oprright => 'point', + oprresult => 'bool', oprcode => 'point_below', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, + +# MACADDR type +{ oid => '1220', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'macaddr', + oprright => 'macaddr', oprresult => 'bool', oprcom => '=(macaddr,macaddr)', + oprnegate => '<>(macaddr,macaddr)', oprcode => 'macaddr_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1221', descr => 'not equal', + oprname => '<>', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'bool', oprcom => '<>(macaddr,macaddr)', + oprnegate => '=(macaddr,macaddr)', oprcode => 'macaddr_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1222', descr => 'less than', + oprname => '<', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'bool', oprcom => '>(macaddr,macaddr)', + oprnegate => '>=(macaddr,macaddr)', oprcode => 'macaddr_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1223', descr => 'less than or equal', + oprname => '<=', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'bool', oprcom => '>=(macaddr,macaddr)', + oprnegate => '>(macaddr,macaddr)', oprcode => 'macaddr_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1224', descr => 'greater than', + oprname => '>', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'bool', oprcom => '<(macaddr,macaddr)', + oprnegate => '<=(macaddr,macaddr)', oprcode => 'macaddr_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1225', descr => 'greater than or equal', + oprname => '>=', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'bool', oprcom => '<=(macaddr,macaddr)', + oprnegate => '<(macaddr,macaddr)', oprcode => 'macaddr_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '3147', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'macaddr', + oprresult => 'macaddr', oprcode => 'macaddr_not' }, +{ oid => '3148', descr => 'bitwise and', + oprname => '&', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'macaddr', oprcode => 'macaddr_and' }, +{ oid => '3149', descr => 'bitwise or', + oprname => '|', oprleft => 'macaddr', oprright => 'macaddr', + oprresult => 'macaddr', oprcode => 'macaddr_or' }, + +# MACADDR8 type +{ oid => '3362', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'macaddr8', + oprright => 'macaddr8', oprresult => 'bool', oprcom => '=(macaddr8,macaddr8)', + oprnegate => '<>(macaddr8,macaddr8)', oprcode => 'macaddr8_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '3363', descr => 'not equal', + oprname => '<>', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'bool', oprcom => '<>(macaddr8,macaddr8)', + oprnegate => '=(macaddr8,macaddr8)', oprcode => 'macaddr8_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3364', descr => 'less than', + oprname => '<', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'bool', oprcom => '>(macaddr8,macaddr8)', + oprnegate => '>=(macaddr8,macaddr8)', oprcode => 'macaddr8_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3365', descr => 'less than or equal', + oprname => '<=', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'bool', oprcom => '>=(macaddr8,macaddr8)', + oprnegate => '>(macaddr8,macaddr8)', oprcode => 'macaddr8_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3366', descr => 'greater than', + oprname => '>', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'bool', oprcom => '<(macaddr8,macaddr8)', + oprnegate => '<=(macaddr8,macaddr8)', oprcode => 'macaddr8_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3367', descr => 'greater than or equal', + oprname => '>=', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'bool', oprcom => '<=(macaddr8,macaddr8)', + oprnegate => '<(macaddr8,macaddr8)', oprcode => 'macaddr8_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '3368', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'macaddr8', + oprresult => 'macaddr8', oprcode => 'macaddr8_not' }, +{ oid => '3369', descr => 'bitwise and', + oprname => '&', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'macaddr8', oprcode => 'macaddr8_and' }, +{ oid => '3370', descr => 'bitwise or', + oprname => '|', oprleft => 'macaddr8', oprright => 'macaddr8', + oprresult => 'macaddr8', oprcode => 'macaddr8_or' }, + +# INET type (these also support CIDR via implicit cast) +{ oid => '1201', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'inet', + oprright => 'inet', oprresult => 'bool', oprcom => '=(inet,inet)', + oprnegate => '<>(inet,inet)', oprcode => 'network_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1202', descr => 'not equal', + oprname => '<>', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '<>(inet,inet)', oprnegate => '=(inet,inet)', + oprcode => 'network_ne', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1203', descr => 'less than', + oprname => '<', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '>(inet,inet)', oprnegate => '>=(inet,inet)', + oprcode => 'network_lt', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '1204', descr => 'less than or equal', + oprname => '<=', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '>=(inet,inet)', oprnegate => '>(inet,inet)', + oprcode => 'network_le', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '1205', descr => 'greater than', + oprname => '>', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '<(inet,inet)', oprnegate => '<=(inet,inet)', + oprcode => 'network_gt', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '1206', descr => 'greater than or equal', + oprname => '>=', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '<=(inet,inet)', oprnegate => '<(inet,inet)', + oprcode => 'network_ge', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '931', oid_symbol => 'OID_INET_SUB_OP', descr => 'is subnet', + oprname => '<<', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '>>(inet,inet)', oprcode => 'network_sub', oprrest => 'networksel', + oprjoin => 'networkjoinsel' }, +{ oid => '932', oid_symbol => 'OID_INET_SUBEQ_OP', + descr => 'is subnet or equal', + oprname => '<<=', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '>>=(inet,inet)', oprcode => 'network_subeq', + oprrest => 'networksel', oprjoin => 'networkjoinsel' }, +{ oid => '933', oid_symbol => 'OID_INET_SUP_OP', descr => 'is supernet', + oprname => '>>', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '<<(inet,inet)', oprcode => 'network_sup', oprrest => 'networksel', + oprjoin => 'networkjoinsel' }, +{ oid => '934', oid_symbol => 'OID_INET_SUPEQ_OP', + descr => 'is supernet or equal', + oprname => '>>=', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '<<=(inet,inet)', oprcode => 'network_supeq', + oprrest => 'networksel', oprjoin => 'networkjoinsel' }, +{ oid => '3552', oid_symbol => 'OID_INET_OVERLAP_OP', + descr => 'overlaps (is subnet or supernet)', + oprname => '&&', oprleft => 'inet', oprright => 'inet', oprresult => 'bool', + oprcom => '&&(inet,inet)', oprcode => 'network_overlap', + oprrest => 'networksel', oprjoin => 'networkjoinsel' }, + +{ oid => '2634', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'inet', + oprresult => 'inet', oprcode => 'inetnot' }, +{ oid => '2635', descr => 'bitwise and', + oprname => '&', oprleft => 'inet', oprright => 'inet', oprresult => 'inet', + oprcode => 'inetand' }, +{ oid => '2636', descr => 'bitwise or', + oprname => '|', oprleft => 'inet', oprright => 'inet', oprresult => 'inet', + oprcode => 'inetor' }, +{ oid => '2637', descr => 'add', + oprname => '+', oprleft => 'inet', oprright => 'int8', oprresult => 'inet', + oprcom => '+(int8,inet)', oprcode => 'inetpl' }, +{ oid => '2638', descr => 'add', + oprname => '+', oprleft => 'int8', oprright => 'inet', oprresult => 'inet', + oprcom => '+(inet,int8)', oprcode => 'int8pl_inet' }, +{ oid => '2639', descr => 'subtract', + oprname => '-', oprleft => 'inet', oprright => 'int8', oprresult => 'inet', + oprcode => 'inetmi_int8' }, +{ oid => '2640', descr => 'subtract', + oprname => '-', oprleft => 'inet', oprright => 'inet', oprresult => 'int8', + oprcode => 'inetmi' }, + +# case-insensitive LIKE hacks +{ oid => '1625', oid_symbol => 'OID_NAME_ICLIKE_OP', + descr => 'matches LIKE expression, case-insensitive', + oprname => '~~*', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '!~~*(name,text)', oprcode => 'nameiclike', + oprrest => 'iclikesel', oprjoin => 'iclikejoinsel' }, +{ oid => '1626', descr => 'does not match LIKE expression, case-insensitive', + oprname => '!~~*', oprleft => 'name', oprright => 'text', oprresult => 'bool', + oprnegate => '~~*(name,text)', oprcode => 'nameicnlike', + oprrest => 'icnlikesel', oprjoin => 'icnlikejoinsel' }, +{ oid => '1627', oid_symbol => 'OID_TEXT_ICLIKE_OP', + descr => 'matches LIKE expression, case-insensitive', + oprname => '~~*', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '!~~*(text,text)', oprcode => 'texticlike', + oprrest => 'iclikesel', oprjoin => 'iclikejoinsel' }, +{ oid => '1628', descr => 'does not match LIKE expression, case-insensitive', + oprname => '!~~*', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprnegate => '~~*(text,text)', oprcode => 'texticnlike', + oprrest => 'icnlikesel', oprjoin => 'icnlikejoinsel' }, +{ oid => '1629', oid_symbol => 'OID_BPCHAR_ICLIKE_OP', + descr => 'matches LIKE expression, case-insensitive', + oprname => '~~*', oprleft => 'bpchar', oprright => 'text', + oprresult => 'bool', oprnegate => '!~~*(bpchar,text)', + oprcode => 'bpchariclike', oprrest => 'iclikesel', + oprjoin => 'iclikejoinsel' }, +{ oid => '1630', descr => 'does not match LIKE expression, case-insensitive', + oprname => '!~~*', oprleft => 'bpchar', oprright => 'text', + oprresult => 'bool', oprnegate => '~~*(bpchar,text)', + oprcode => 'bpcharicnlike', oprrest => 'icnlikesel', + oprjoin => 'icnlikejoinsel' }, + +# NUMERIC type - OID's 1700-1799 +{ oid => '1751', descr => 'negate', + oprname => '-', oprkind => 'l', oprleft => '0', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_uminus' }, +{ oid => '1752', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'numeric', + oprright => 'numeric', oprresult => 'bool', oprcom => '=(numeric,numeric)', + oprnegate => '<>(numeric,numeric)', oprcode => 'numeric_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1753', descr => 'not equal', + oprname => '<>', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'bool', oprcom => '<>(numeric,numeric)', + oprnegate => '=(numeric,numeric)', oprcode => 'numeric_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1754', descr => 'less than', + oprname => '<', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'bool', oprcom => '>(numeric,numeric)', + oprnegate => '>=(numeric,numeric)', oprcode => 'numeric_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1755', descr => 'less than or equal', + oprname => '<=', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'bool', oprcom => '>=(numeric,numeric)', + oprnegate => '>(numeric,numeric)', oprcode => 'numeric_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1756', descr => 'greater than', + oprname => '>', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'bool', oprcom => '<(numeric,numeric)', + oprnegate => '<=(numeric,numeric)', oprcode => 'numeric_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1757', descr => 'greater than or equal', + oprname => '>=', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'bool', oprcom => '<=(numeric,numeric)', + oprnegate => '<(numeric,numeric)', oprcode => 'numeric_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '1758', descr => 'add', + oprname => '+', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcom => '+(numeric,numeric)', + oprcode => 'numeric_add' }, +{ oid => '1759', descr => 'subtract', + oprname => '-', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_sub' }, +{ oid => '1760', descr => 'multiply', + oprname => '*', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcom => '*(numeric,numeric)', + oprcode => 'numeric_mul' }, +{ oid => '1761', descr => 'divide', + oprname => '/', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_div' }, +{ oid => '1762', descr => 'modulus', + oprname => '%', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_mod' }, +{ oid => '1038', descr => 'exponentiation', + oprname => '^', oprleft => 'numeric', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_power' }, +{ oid => '1763', descr => 'absolute value', + oprname => '@', oprkind => 'l', oprleft => '0', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_abs' }, + +{ oid => '1784', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'bit', oprright => 'bit', + oprresult => 'bool', oprcom => '=(bit,bit)', oprnegate => '<>(bit,bit)', + oprcode => 'biteq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '1785', descr => 'not equal', + oprname => '<>', oprleft => 'bit', oprright => 'bit', oprresult => 'bool', + oprcom => '<>(bit,bit)', oprnegate => '=(bit,bit)', oprcode => 'bitne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1786', descr => 'less than', + oprname => '<', oprleft => 'bit', oprright => 'bit', oprresult => 'bool', + oprcom => '>(bit,bit)', oprnegate => '>=(bit,bit)', oprcode => 'bitlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1787', descr => 'greater than', + oprname => '>', oprleft => 'bit', oprright => 'bit', oprresult => 'bool', + oprcom => '<(bit,bit)', oprnegate => '<=(bit,bit)', oprcode => 'bitgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1788', descr => 'less than or equal', + oprname => '<=', oprleft => 'bit', oprright => 'bit', oprresult => 'bool', + oprcom => '>=(bit,bit)', oprnegate => '>(bit,bit)', oprcode => 'bitle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1789', descr => 'greater than or equal', + oprname => '>=', oprleft => 'bit', oprright => 'bit', oprresult => 'bool', + oprcom => '<=(bit,bit)', oprnegate => '<(bit,bit)', oprcode => 'bitge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '1791', descr => 'bitwise and', + oprname => '&', oprleft => 'bit', oprright => 'bit', oprresult => 'bit', + oprcom => '&(bit,bit)', oprcode => 'bitand' }, +{ oid => '1792', descr => 'bitwise or', + oprname => '|', oprleft => 'bit', oprright => 'bit', oprresult => 'bit', + oprcom => '|(bit,bit)', oprcode => 'bitor' }, +{ oid => '1793', descr => 'bitwise exclusive or', + oprname => '#', oprleft => 'bit', oprright => 'bit', oprresult => 'bit', + oprcom => '#(bit,bit)', oprcode => 'bitxor' }, +{ oid => '1794', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'bit', + oprresult => 'bit', oprcode => 'bitnot' }, +{ oid => '1795', descr => 'bitwise shift left', + oprname => '<<', oprleft => 'bit', oprright => 'int4', oprresult => 'bit', + oprcode => 'bitshiftleft' }, +{ oid => '1796', descr => 'bitwise shift right', + oprname => '>>', oprleft => 'bit', oprright => 'int4', oprresult => 'bit', + oprcode => 'bitshiftright' }, +{ oid => '1797', descr => 'concatenate', + oprname => '||', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'varbit', oprcode => 'bitcat' }, + +{ oid => '1800', descr => 'add', + oprname => '+', oprleft => 'time', oprright => 'interval', + oprresult => 'time', oprcom => '+(interval,time)', + oprcode => 'time_pl_interval' }, +{ oid => '1801', descr => 'subtract', + oprname => '-', oprleft => 'time', oprright => 'interval', + oprresult => 'time', oprcode => 'time_mi_interval' }, +{ oid => '1802', descr => 'add', + oprname => '+', oprleft => 'timetz', oprright => 'interval', + oprresult => 'timetz', oprcom => '+(interval,timetz)', + oprcode => 'timetz_pl_interval' }, +{ oid => '1803', descr => 'subtract', + oprname => '-', oprleft => 'timetz', oprright => 'interval', + oprresult => 'timetz', oprcode => 'timetz_mi_interval' }, + +{ oid => '1804', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '=(varbit,varbit)', + oprnegate => '<>(varbit,varbit)', oprcode => 'varbiteq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1805', descr => 'not equal', + oprname => '<>', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '<>(varbit,varbit)', + oprnegate => '=(varbit,varbit)', oprcode => 'varbitne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '1806', descr => 'less than', + oprname => '<', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '>(varbit,varbit)', + oprnegate => '>=(varbit,varbit)', oprcode => 'varbitlt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1807', descr => 'greater than', + oprname => '>', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '<(varbit,varbit)', + oprnegate => '<=(varbit,varbit)', oprcode => 'varbitgt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1808', descr => 'less than or equal', + oprname => '<=', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '>=(varbit,varbit)', + oprnegate => '>(varbit,varbit)', oprcode => 'varbitle', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1809', descr => 'greater than or equal', + oprname => '>=', oprleft => 'varbit', oprright => 'varbit', + oprresult => 'bool', oprcom => '<=(varbit,varbit)', + oprnegate => '<(varbit,varbit)', oprcode => 'varbitge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '1849', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'time', + oprresult => 'time', oprcom => '+(time,interval)', + oprcode => 'interval_pl_time' }, + +{ oid => '1862', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int2', + oprright => 'int8', oprresult => 'bool', oprcom => '=(int8,int2)', + oprnegate => '<>(int2,int8)', oprcode => 'int28eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1863', descr => 'not equal', + oprname => '<>', oprleft => 'int2', oprright => 'int8', oprresult => 'bool', + oprcom => '<>(int8,int2)', oprnegate => '=(int2,int8)', oprcode => 'int28ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1864', descr => 'less than', + oprname => '<', oprleft => 'int2', oprright => 'int8', oprresult => 'bool', + oprcom => '>(int8,int2)', oprnegate => '>=(int2,int8)', oprcode => 'int28lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1865', descr => 'greater than', + oprname => '>', oprleft => 'int2', oprright => 'int8', oprresult => 'bool', + oprcom => '<(int8,int2)', oprnegate => '<=(int2,int8)', oprcode => 'int28gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1866', descr => 'less than or equal', + oprname => '<=', oprleft => 'int2', oprright => 'int8', oprresult => 'bool', + oprcom => '>=(int8,int2)', oprnegate => '>(int2,int8)', oprcode => 'int28le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1867', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int2', oprright => 'int8', oprresult => 'bool', + oprcom => '<=(int8,int2)', oprnegate => '<(int2,int8)', oprcode => 'int28ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '1868', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'int8', + oprright => 'int2', oprresult => 'bool', oprcom => '=(int2,int8)', + oprnegate => '<>(int8,int2)', oprcode => 'int82eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1869', descr => 'not equal', + oprname => '<>', oprleft => 'int8', oprright => 'int2', oprresult => 'bool', + oprcom => '<>(int2,int8)', oprnegate => '=(int8,int2)', oprcode => 'int82ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1870', descr => 'less than', + oprname => '<', oprleft => 'int8', oprright => 'int2', oprresult => 'bool', + oprcom => '>(int2,int8)', oprnegate => '>=(int8,int2)', oprcode => 'int82lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '1871', descr => 'greater than', + oprname => '>', oprleft => 'int8', oprright => 'int2', oprresult => 'bool', + oprcom => '<(int2,int8)', oprnegate => '<=(int8,int2)', oprcode => 'int82gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '1872', descr => 'less than or equal', + oprname => '<=', oprleft => 'int8', oprright => 'int2', oprresult => 'bool', + oprcom => '>=(int2,int8)', oprnegate => '>(int8,int2)', oprcode => 'int82le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '1873', descr => 'greater than or equal', + oprname => '>=', oprleft => 'int8', oprright => 'int2', oprresult => 'bool', + oprcom => '<=(int2,int8)', oprnegate => '<(int8,int2)', oprcode => 'int82ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +{ oid => '1874', descr => 'bitwise and', + oprname => '&', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcom => '&(int2,int2)', oprcode => 'int2and' }, +{ oid => '1875', descr => 'bitwise or', + oprname => '|', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcom => '|(int2,int2)', oprcode => 'int2or' }, +{ oid => '1876', descr => 'bitwise exclusive or', + oprname => '#', oprleft => 'int2', oprright => 'int2', oprresult => 'int2', + oprcom => '#(int2,int2)', oprcode => 'int2xor' }, +{ oid => '1877', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'int2', + oprresult => 'int2', oprcode => 'int2not' }, +{ oid => '1878', descr => 'bitwise shift left', + oprname => '<<', oprleft => 'int2', oprright => 'int4', oprresult => 'int2', + oprcode => 'int2shl' }, +{ oid => '1879', descr => 'bitwise shift right', + oprname => '>>', oprleft => 'int2', oprright => 'int4', oprresult => 'int2', + oprcode => 'int2shr' }, + +{ oid => '1880', descr => 'bitwise and', + oprname => '&', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcom => '&(int4,int4)', oprcode => 'int4and' }, +{ oid => '1881', descr => 'bitwise or', + oprname => '|', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcom => '|(int4,int4)', oprcode => 'int4or' }, +{ oid => '1882', descr => 'bitwise exclusive or', + oprname => '#', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcom => '#(int4,int4)', oprcode => 'int4xor' }, +{ oid => '1883', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'int4', + oprresult => 'int4', oprcode => 'int4not' }, +{ oid => '1884', descr => 'bitwise shift left', + oprname => '<<', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcode => 'int4shl' }, +{ oid => '1885', descr => 'bitwise shift right', + oprname => '>>', oprleft => 'int4', oprright => 'int4', oprresult => 'int4', + oprcode => 'int4shr' }, + +{ oid => '1886', descr => 'bitwise and', + oprname => '&', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcom => '&(int8,int8)', oprcode => 'int8and' }, +{ oid => '1887', descr => 'bitwise or', + oprname => '|', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcom => '|(int8,int8)', oprcode => 'int8or' }, +{ oid => '1888', descr => 'bitwise exclusive or', + oprname => '#', oprleft => 'int8', oprright => 'int8', oprresult => 'int8', + oprcom => '#(int8,int8)', oprcode => 'int8xor' }, +{ oid => '1889', descr => 'bitwise not', + oprname => '~', oprkind => 'l', oprleft => '0', oprright => 'int8', + oprresult => 'int8', oprcode => 'int8not' }, +{ oid => '1890', descr => 'bitwise shift left', + oprname => '<<', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcode => 'int8shl' }, +{ oid => '1891', descr => 'bitwise shift right', + oprname => '>>', oprleft => 'int8', oprright => 'int4', oprresult => 'int8', + oprcode => 'int8shr' }, + +{ oid => '1916', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'int8', + oprresult => 'int8', oprcode => 'int8up' }, +{ oid => '1917', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'int2', + oprresult => 'int2', oprcode => 'int2up' }, +{ oid => '1918', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'int4', + oprresult => 'int4', oprcode => 'int4up' }, +{ oid => '1919', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'float4', + oprresult => 'float4', oprcode => 'float4up' }, +{ oid => '1920', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'float8', + oprresult => 'float8', oprcode => 'float8up' }, +{ oid => '1921', descr => 'unary plus', + oprname => '+', oprkind => 'l', oprleft => '0', oprright => 'numeric', + oprresult => 'numeric', oprcode => 'numeric_uplus' }, + +# bytea operators +{ oid => '1955', oid_symbol => 'ByteaEqualOperator', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'bytea', + oprright => 'bytea', oprresult => 'bool', oprcom => '=(bytea,bytea)', + oprnegate => '<>(bytea,bytea)', oprcode => 'byteaeq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '1956', descr => 'not equal', + oprname => '<>', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprcom => '<>(bytea,bytea)', oprnegate => '=(bytea,bytea)', + oprcode => 'byteane', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '1957', oid_symbol => 'ByteaLessOperator', descr => 'less than', + oprname => '<', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprcom => '>(bytea,bytea)', oprnegate => '>=(bytea,bytea)', + oprcode => 'bytealt', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '1958', descr => 'less than or equal', + oprname => '<=', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprcom => '>=(bytea,bytea)', oprnegate => '>(bytea,bytea)', + oprcode => 'byteale', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '1959', descr => 'greater than', + oprname => '>', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprcom => '<(bytea,bytea)', oprnegate => '<=(bytea,bytea)', + oprcode => 'byteagt', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '1960', oid_symbol => 'ByteaGreaterEqualOperator', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprcom => '<=(bytea,bytea)', oprnegate => '<(bytea,bytea)', + oprcode => 'byteage', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, + +{ oid => '2016', oid_symbol => 'OID_BYTEA_LIKE_OP', + descr => 'matches LIKE expression', + oprname => '~~', oprleft => 'bytea', oprright => 'bytea', oprresult => 'bool', + oprnegate => '!~~(bytea,bytea)', oprcode => 'bytealike', oprrest => 'likesel', + oprjoin => 'likejoinsel' }, +{ oid => '2017', descr => 'does not match LIKE expression', + oprname => '!~~', oprleft => 'bytea', oprright => 'bytea', + oprresult => 'bool', oprnegate => '~~(bytea,bytea)', oprcode => 'byteanlike', + oprrest => 'nlikesel', oprjoin => 'nlikejoinsel' }, +{ oid => '2018', descr => 'concatenate', + oprname => '||', oprleft => 'bytea', oprright => 'bytea', + oprresult => 'bytea', oprcode => 'byteacat' }, + +# timestamp operators +{ oid => '2060', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'timestamp', + oprright => 'timestamp', oprresult => 'bool', + oprcom => '=(timestamp,timestamp)', oprnegate => '<>(timestamp,timestamp)', + oprcode => 'timestamp_eq', oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '2061', descr => 'not equal', + oprname => '<>', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<>(timestamp,timestamp)', + oprnegate => '=(timestamp,timestamp)', oprcode => 'timestamp_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '2062', descr => 'less than', + oprname => '<', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>(timestamp,timestamp)', + oprnegate => '>=(timestamp,timestamp)', oprcode => 'timestamp_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2063', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>=(timestamp,timestamp)', + oprnegate => '>(timestamp,timestamp)', oprcode => 'timestamp_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2064', descr => 'greater than', + oprname => '>', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<(timestamp,timestamp)', + oprnegate => '<=(timestamp,timestamp)', oprcode => 'timestamp_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2065', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<=(timestamp,timestamp)', + oprnegate => '<(timestamp,timestamp)', oprcode => 'timestamp_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2066', descr => 'add', + oprname => '+', oprleft => 'timestamp', oprright => 'interval', + oprresult => 'timestamp', oprcom => '+(interval,timestamp)', + oprcode => 'timestamp_pl_interval' }, +{ oid => '2067', descr => 'subtract', + oprname => '-', oprleft => 'timestamp', oprright => 'timestamp', + oprresult => 'interval', oprcode => 'timestamp_mi' }, +{ oid => '2068', descr => 'subtract', + oprname => '-', oprleft => 'timestamp', oprright => 'interval', + oprresult => 'timestamp', oprcode => 'timestamp_mi_interval' }, + +# character-by-character (not collation order) comparison operators for character types +{ oid => '2314', oid_symbol => 'TextPatternLessOperator', + descr => 'less than', + oprname => '~<~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '~>~(text,text)', oprnegate => '~>=~(text,text)', + oprcode => 'text_pattern_lt', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '2315', descr => 'less than or equal', + oprname => '~<=~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '~>=~(text,text)', oprnegate => '~>~(text,text)', + oprcode => 'text_pattern_le', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '2317', oid_symbol => 'TextPatternGreaterEqualOperator', + descr => 'greater than or equal', + oprname => '~>=~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '~<=~(text,text)', oprnegate => '~<~(text,text)', + oprcode => 'text_pattern_ge', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '2318', descr => 'greater than', + oprname => '~>~', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcom => '~<~(text,text)', oprnegate => '~<=~(text,text)', + oprcode => 'text_pattern_gt', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, + +{ oid => '2326', oid_symbol => 'BpcharPatternLessOperator', + descr => 'less than', + oprname => '~<~', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '~>~(bpchar,bpchar)', + oprnegate => '~>=~(bpchar,bpchar)', oprcode => 'bpchar_pattern_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2327', descr => 'less than or equal', + oprname => '~<=~', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '~>=~(bpchar,bpchar)', + oprnegate => '~>~(bpchar,bpchar)', oprcode => 'bpchar_pattern_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2329', oid_symbol => 'BpcharPatternGreaterEqualOperator', + descr => 'greater than or equal', + oprname => '~>=~', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '~<=~(bpchar,bpchar)', + oprnegate => '~<~(bpchar,bpchar)', oprcode => 'bpchar_pattern_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2330', descr => 'greater than', + oprname => '~>~', oprleft => 'bpchar', oprright => 'bpchar', + oprresult => 'bool', oprcom => '~<~(bpchar,bpchar)', + oprnegate => '~<=~(bpchar,bpchar)', oprcode => 'bpchar_pattern_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, + +# crosstype operations for date vs. timestamp and timestamptz +{ oid => '2345', descr => 'less than', + oprname => '<', oprleft => 'date', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>(timestamp,date)', + oprnegate => '>=(date,timestamp)', oprcode => 'date_lt_timestamp', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2346', descr => 'less than or equal', + oprname => '<=', oprleft => 'date', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>=(timestamp,date)', + oprnegate => '>(date,timestamp)', oprcode => 'date_le_timestamp', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2347', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'date', + oprright => 'timestamp', oprresult => 'bool', oprcom => '=(timestamp,date)', + oprnegate => '<>(date,timestamp)', oprcode => 'date_eq_timestamp', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '2348', descr => 'greater than or equal', + oprname => '>=', oprleft => 'date', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<=(timestamp,date)', + oprnegate => '<(date,timestamp)', oprcode => 'date_ge_timestamp', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2349', descr => 'greater than', + oprname => '>', oprleft => 'date', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<(timestamp,date)', + oprnegate => '<=(date,timestamp)', oprcode => 'date_gt_timestamp', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2350', descr => 'not equal', + oprname => '<>', oprleft => 'date', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<>(timestamp,date)', + oprnegate => '=(date,timestamp)', oprcode => 'date_ne_timestamp', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +{ oid => '2358', descr => 'less than', + oprname => '<', oprleft => 'date', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>(timestamptz,date)', + oprnegate => '>=(date,timestamptz)', oprcode => 'date_lt_timestamptz', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2359', descr => 'less than or equal', + oprname => '<=', oprleft => 'date', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>=(timestamptz,date)', + oprnegate => '>(date,timestamptz)', oprcode => 'date_le_timestamptz', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2360', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'date', + oprright => 'timestamptz', oprresult => 'bool', + oprcom => '=(timestamptz,date)', oprnegate => '<>(date,timestamptz)', + oprcode => 'date_eq_timestamptz', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '2361', descr => 'greater than or equal', + oprname => '>=', oprleft => 'date', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<=(timestamptz,date)', + oprnegate => '<(date,timestamptz)', oprcode => 'date_ge_timestamptz', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2362', descr => 'greater than', + oprname => '>', oprleft => 'date', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<(timestamptz,date)', + oprnegate => '<=(date,timestamptz)', oprcode => 'date_gt_timestamptz', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2363', descr => 'not equal', + oprname => '<>', oprleft => 'date', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<>(timestamptz,date)', + oprnegate => '=(date,timestamptz)', oprcode => 'date_ne_timestamptz', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +{ oid => '2371', descr => 'less than', + oprname => '<', oprleft => 'timestamp', oprright => 'date', + oprresult => 'bool', oprcom => '>(date,timestamp)', + oprnegate => '>=(timestamp,date)', oprcode => 'timestamp_lt_date', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2372', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamp', oprright => 'date', + oprresult => 'bool', oprcom => '>=(date,timestamp)', + oprnegate => '>(timestamp,date)', oprcode => 'timestamp_le_date', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2373', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'timestamp', + oprright => 'date', oprresult => 'bool', oprcom => '=(date,timestamp)', + oprnegate => '<>(timestamp,date)', oprcode => 'timestamp_eq_date', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '2374', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamp', oprright => 'date', + oprresult => 'bool', oprcom => '<=(date,timestamp)', + oprnegate => '<(timestamp,date)', oprcode => 'timestamp_ge_date', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2375', descr => 'greater than', + oprname => '>', oprleft => 'timestamp', oprright => 'date', + oprresult => 'bool', oprcom => '<(date,timestamp)', + oprnegate => '<=(timestamp,date)', oprcode => 'timestamp_gt_date', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2376', descr => 'not equal', + oprname => '<>', oprleft => 'timestamp', oprright => 'date', + oprresult => 'bool', oprcom => '<>(date,timestamp)', + oprnegate => '=(timestamp,date)', oprcode => 'timestamp_ne_date', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +{ oid => '2384', descr => 'less than', + oprname => '<', oprleft => 'timestamptz', oprright => 'date', + oprresult => 'bool', oprcom => '>(date,timestamptz)', + oprnegate => '>=(timestamptz,date)', oprcode => 'timestamptz_lt_date', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2385', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamptz', oprright => 'date', + oprresult => 'bool', oprcom => '>=(date,timestamptz)', + oprnegate => '>(timestamptz,date)', oprcode => 'timestamptz_le_date', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2386', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'timestamptz', + oprright => 'date', oprresult => 'bool', oprcom => '=(date,timestamptz)', + oprnegate => '<>(timestamptz,date)', oprcode => 'timestamptz_eq_date', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '2387', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamptz', oprright => 'date', + oprresult => 'bool', oprcom => '<=(date,timestamptz)', + oprnegate => '<(timestamptz,date)', oprcode => 'timestamptz_ge_date', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2388', descr => 'greater than', + oprname => '>', oprleft => 'timestamptz', oprright => 'date', + oprresult => 'bool', oprcom => '<(date,timestamptz)', + oprnegate => '<=(timestamptz,date)', oprcode => 'timestamptz_gt_date', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2389', descr => 'not equal', + oprname => '<>', oprleft => 'timestamptz', oprright => 'date', + oprresult => 'bool', oprcom => '<>(date,timestamptz)', + oprnegate => '=(timestamptz,date)', oprcode => 'timestamptz_ne_date', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, + +# crosstype operations for timestamp vs. timestamptz +{ oid => '2534', descr => 'less than', + oprname => '<', oprleft => 'timestamp', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>(timestamptz,timestamp)', + oprnegate => '>=(timestamp,timestamptz)', + oprcode => 'timestamp_lt_timestamptz', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '2535', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamp', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '>=(timestamptz,timestamp)', + oprnegate => '>(timestamp,timestamptz)', + oprcode => 'timestamp_le_timestamptz', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '2536', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'timestamp', + oprright => 'timestamptz', oprresult => 'bool', + oprcom => '=(timestamptz,timestamp)', + oprnegate => '<>(timestamp,timestamptz)', + oprcode => 'timestamp_eq_timestamptz', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '2537', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamp', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<=(timestamptz,timestamp)', + oprnegate => '<(timestamp,timestamptz)', + oprcode => 'timestamp_ge_timestamptz', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '2538', descr => 'greater than', + oprname => '>', oprleft => 'timestamp', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<(timestamptz,timestamp)', + oprnegate => '<=(timestamp,timestamptz)', + oprcode => 'timestamp_gt_timestamptz', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '2539', descr => 'not equal', + oprname => '<>', oprleft => 'timestamp', oprright => 'timestamptz', + oprresult => 'bool', oprcom => '<>(timestamptz,timestamp)', + oprnegate => '=(timestamp,timestamptz)', + oprcode => 'timestamp_ne_timestamptz', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, + +{ oid => '2540', descr => 'less than', + oprname => '<', oprleft => 'timestamptz', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>(timestamp,timestamptz)', + oprnegate => '>=(timestamptz,timestamp)', + oprcode => 'timestamptz_lt_timestamp', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '2541', descr => 'less than or equal', + oprname => '<=', oprleft => 'timestamptz', oprright => 'timestamp', + oprresult => 'bool', oprcom => '>=(timestamp,timestamptz)', + oprnegate => '>(timestamptz,timestamp)', + oprcode => 'timestamptz_le_timestamp', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '2542', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'timestamptz', + oprright => 'timestamp', oprresult => 'bool', + oprcom => '=(timestamp,timestamptz)', + oprnegate => '<>(timestamptz,timestamp)', + oprcode => 'timestamptz_eq_timestamp', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '2543', descr => 'greater than or equal', + oprname => '>=', oprleft => 'timestamptz', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<=(timestamp,timestamptz)', + oprnegate => '<(timestamptz,timestamp)', + oprcode => 'timestamptz_ge_timestamp', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '2544', descr => 'greater than', + oprname => '>', oprleft => 'timestamptz', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<(timestamp,timestamptz)', + oprnegate => '<=(timestamptz,timestamp)', + oprcode => 'timestamptz_gt_timestamp', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '2545', descr => 'not equal', + oprname => '<>', oprleft => 'timestamptz', oprright => 'timestamp', + oprresult => 'bool', oprcom => '<>(timestamp,timestamptz)', + oprnegate => '=(timestamptz,timestamp)', + oprcode => 'timestamptz_ne_timestamp', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, + +# formerly-missing interval + datetime operators +{ oid => '2551', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'date', + oprresult => 'timestamp', oprcom => '+(date,interval)', + oprcode => 'interval_pl_date' }, +{ oid => '2552', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'timetz', + oprresult => 'timetz', oprcom => '+(timetz,interval)', + oprcode => 'interval_pl_timetz' }, +{ oid => '2553', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'timestamp', + oprresult => 'timestamp', oprcom => '+(timestamp,interval)', + oprcode => 'interval_pl_timestamp' }, +{ oid => '2554', descr => 'add', + oprname => '+', oprleft => 'interval', oprright => 'timestamptz', + oprresult => 'timestamptz', oprcom => '+(timestamptz,interval)', + oprcode => 'interval_pl_timestamptz' }, +{ oid => '2555', descr => 'add', + oprname => '+', oprleft => 'int4', oprright => 'date', oprresult => 'date', + oprcom => '+(date,int4)', oprcode => 'integer_pl_date' }, + +# new operators for Y-direction rtree opfamilies +{ oid => '2570', descr => 'is below', + oprname => '<<|', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_below', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2571', descr => 'overlaps or is below', + oprname => '&<|', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_overbelow', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2572', descr => 'overlaps or is above', + oprname => '|&>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_overabove', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2573', descr => 'is above', + oprname => '|>>', oprleft => 'box', oprright => 'box', oprresult => 'bool', + oprcode => 'box_above', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2574', descr => 'is below', + oprname => '<<|', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_below', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2575', descr => 'overlaps or is below', + oprname => '&<|', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_overbelow', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2576', descr => 'overlaps or is above', + oprname => '|&>', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_overabove', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2577', descr => 'is above', + oprname => '|>>', oprleft => 'polygon', oprright => 'polygon', + oprresult => 'bool', oprcode => 'poly_above', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2589', descr => 'overlaps or is below', + oprname => '&<|', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_overbelow', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, +{ oid => '2590', descr => 'overlaps or is above', + oprname => '|&>', oprleft => 'circle', oprright => 'circle', + oprresult => 'bool', oprcode => 'circle_overabove', oprrest => 'positionsel', + oprjoin => 'positionjoinsel' }, + +# overlap/contains/contained for arrays +{ oid => '2750', oid_symbol => 'OID_ARRAY_OVERLAP_OP', descr => 'overlaps', + oprname => '&&', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '&&(anyarray,anyarray)', + oprcode => 'arrayoverlap', oprrest => 'arraycontsel', + oprjoin => 'arraycontjoinsel' }, +{ oid => '2751', oid_symbol => 'OID_ARRAY_CONTAINS_OP', descr => 'contains', + oprname => '@>', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '<@(anyarray,anyarray)', + oprcode => 'arraycontains', oprrest => 'arraycontsel', + oprjoin => 'arraycontjoinsel' }, +{ oid => '2752', oid_symbol => 'OID_ARRAY_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anyarray', oprright => 'anyarray', + oprresult => 'bool', oprcom => '@>(anyarray,anyarray)', + oprcode => 'arraycontained', oprrest => 'arraycontsel', + oprjoin => 'arraycontjoinsel' }, + +# capturing operators to preserve pre-8.3 behavior of text concatenation +{ oid => '2779', descr => 'concatenate', + oprname => '||', oprleft => 'text', oprright => 'anynonarray', + oprresult => 'text', oprcode => 'textanycat' }, +{ oid => '2780', descr => 'concatenate', + oprname => '||', oprleft => 'anynonarray', oprright => 'text', + oprresult => 'text', oprcode => 'anytextcat' }, + +# uuid operators +{ oid => '2972', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'uuid', + oprright => 'uuid', oprresult => 'bool', oprcom => '=(uuid,uuid)', + oprnegate => '<>(uuid,uuid)', oprcode => 'uuid_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '2973', descr => 'not equal', + oprname => '<>', oprleft => 'uuid', oprright => 'uuid', oprresult => 'bool', + oprcom => '<>(uuid,uuid)', oprnegate => '=(uuid,uuid)', oprcode => 'uuid_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '2974', descr => 'less than', + oprname => '<', oprleft => 'uuid', oprright => 'uuid', oprresult => 'bool', + oprcom => '>(uuid,uuid)', oprnegate => '>=(uuid,uuid)', oprcode => 'uuid_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2975', descr => 'greater than', + oprname => '>', oprleft => 'uuid', oprright => 'uuid', oprresult => 'bool', + oprcom => '<(uuid,uuid)', oprnegate => '<=(uuid,uuid)', oprcode => 'uuid_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2976', descr => 'less than or equal', + oprname => '<=', oprleft => 'uuid', oprright => 'uuid', oprresult => 'bool', + oprcom => '>=(uuid,uuid)', oprnegate => '>(uuid,uuid)', oprcode => 'uuid_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2977', descr => 'greater than or equal', + oprname => '>=', oprleft => 'uuid', oprright => 'uuid', oprresult => 'bool', + oprcom => '<=(uuid,uuid)', oprnegate => '<(uuid,uuid)', oprcode => 'uuid_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# pg_lsn operators +{ oid => '3222', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'pg_lsn', + oprright => 'pg_lsn', oprresult => 'bool', oprcom => '=(pg_lsn,pg_lsn)', + oprnegate => '<>(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '3223', descr => 'not equal', + oprname => '<>', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'bool', oprcom => '<>(pg_lsn,pg_lsn)', + oprnegate => '=(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '3224', descr => 'less than', + oprname => '<', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'bool', oprcom => '>(pg_lsn,pg_lsn)', + oprnegate => '>=(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3225', descr => 'greater than', + oprname => '>', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'bool', oprcom => '<(pg_lsn,pg_lsn)', + oprnegate => '<=(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3226', descr => 'less than or equal', + oprname => '<=', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'bool', oprcom => '>=(pg_lsn,pg_lsn)', + oprnegate => '>(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3227', descr => 'greater than or equal', + oprname => '>=', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'bool', oprcom => '<=(pg_lsn,pg_lsn)', + oprnegate => '<(pg_lsn,pg_lsn)', oprcode => 'pg_lsn_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '3228', descr => 'minus', + oprname => '-', oprleft => 'pg_lsn', oprright => 'pg_lsn', + oprresult => 'numeric', oprcode => 'pg_lsn_mi' }, +{ oid => '5025', descr => 'add', + oprname => '+', oprleft => 'pg_lsn', oprright => 'numeric', + oprresult => 'pg_lsn', oprcom => '+(numeric,pg_lsn)', + oprcode => 'pg_lsn_pli' }, +{ oid => '5026', descr => 'add', + oprname => '+', oprleft => 'numeric', oprright => 'pg_lsn', + oprresult => 'pg_lsn', oprcom => '+(pg_lsn,numeric)', + oprcode => 'numeric_pl_pg_lsn' }, +{ oid => '5027', descr => 'subtract', + oprname => '-', oprleft => 'pg_lsn', oprright => 'numeric', + oprresult => 'pg_lsn', oprcode => 'pg_lsn_mii' }, + +# enum operators +{ oid => '3516', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'anyenum', + oprright => 'anyenum', oprresult => 'bool', oprcom => '=(anyenum,anyenum)', + oprnegate => '<>(anyenum,anyenum)', oprcode => 'enum_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '3517', descr => 'not equal', + oprname => '<>', oprleft => 'anyenum', oprright => 'anyenum', + oprresult => 'bool', oprcom => '<>(anyenum,anyenum)', + oprnegate => '=(anyenum,anyenum)', oprcode => 'enum_ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '3518', descr => 'less than', + oprname => '<', oprleft => 'anyenum', oprright => 'anyenum', + oprresult => 'bool', oprcom => '>(anyenum,anyenum)', + oprnegate => '>=(anyenum,anyenum)', oprcode => 'enum_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3519', descr => 'greater than', + oprname => '>', oprleft => 'anyenum', oprright => 'anyenum', + oprresult => 'bool', oprcom => '<(anyenum,anyenum)', + oprnegate => '<=(anyenum,anyenum)', oprcode => 'enum_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3520', descr => 'less than or equal', + oprname => '<=', oprleft => 'anyenum', oprright => 'anyenum', + oprresult => 'bool', oprcom => '>=(anyenum,anyenum)', + oprnegate => '>(anyenum,anyenum)', oprcode => 'enum_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3521', descr => 'greater than or equal', + oprname => '>=', oprleft => 'anyenum', oprright => 'anyenum', + oprresult => 'bool', oprcom => '<=(anyenum,anyenum)', + oprnegate => '<(anyenum,anyenum)', oprcode => 'enum_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# tsearch operations +{ oid => '3627', descr => 'less than', + oprname => '<', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'bool', oprcom => '>(tsvector,tsvector)', + oprnegate => '>=(tsvector,tsvector)', oprcode => 'tsvector_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3628', descr => 'less than or equal', + oprname => '<=', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'bool', oprcom => '>=(tsvector,tsvector)', + oprnegate => '>(tsvector,tsvector)', oprcode => 'tsvector_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3629', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'tsvector', + oprright => 'tsvector', oprresult => 'bool', oprcom => '=(tsvector,tsvector)', + oprnegate => '<>(tsvector,tsvector)', oprcode => 'tsvector_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '3630', descr => 'not equal', + oprname => '<>', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'bool', oprcom => '<>(tsvector,tsvector)', + oprnegate => '=(tsvector,tsvector)', oprcode => 'tsvector_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3631', descr => 'greater than or equal', + oprname => '>=', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'bool', oprcom => '<=(tsvector,tsvector)', + oprnegate => '<(tsvector,tsvector)', oprcode => 'tsvector_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '3632', descr => 'greater than', + oprname => '>', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'bool', oprcom => '<(tsvector,tsvector)', + oprnegate => '<=(tsvector,tsvector)', oprcode => 'tsvector_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3633', descr => 'concatenate', + oprname => '||', oprleft => 'tsvector', oprright => 'tsvector', + oprresult => 'tsvector', oprcode => 'tsvector_concat' }, +{ oid => '3636', descr => 'text search match', + oprname => '@@', oprleft => 'tsvector', oprright => 'tsquery', + oprresult => 'bool', oprcom => '@@(tsquery,tsvector)', + oprcode => 'ts_match_vq', oprrest => 'tsmatchsel', + oprjoin => 'tsmatchjoinsel' }, +{ oid => '3637', descr => 'text search match', + oprname => '@@', oprleft => 'tsquery', oprright => 'tsvector', + oprresult => 'bool', oprcom => '@@(tsvector,tsquery)', + oprcode => 'ts_match_qv', oprrest => 'tsmatchsel', + oprjoin => 'tsmatchjoinsel' }, +{ oid => '3660', descr => 'deprecated, use @@ instead', + oprname => '@@@', oprleft => 'tsvector', oprright => 'tsquery', + oprresult => 'bool', oprcom => '@@@(tsquery,tsvector)', + oprcode => 'ts_match_vq', oprrest => 'tsmatchsel', + oprjoin => 'tsmatchjoinsel' }, +{ oid => '3661', descr => 'deprecated, use @@ instead', + oprname => '@@@', oprleft => 'tsquery', oprright => 'tsvector', + oprresult => 'bool', oprcom => '@@@(tsvector,tsquery)', + oprcode => 'ts_match_qv', oprrest => 'tsmatchsel', + oprjoin => 'tsmatchjoinsel' }, +{ oid => '3674', descr => 'less than', + oprname => '<', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '>(tsquery,tsquery)', + oprnegate => '>=(tsquery,tsquery)', oprcode => 'tsquery_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3675', descr => 'less than or equal', + oprname => '<=', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '>=(tsquery,tsquery)', + oprnegate => '>(tsquery,tsquery)', oprcode => 'tsquery_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3676', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprleft => 'tsquery', + oprright => 'tsquery', oprresult => 'bool', oprcom => '=(tsquery,tsquery)', + oprnegate => '<>(tsquery,tsquery)', oprcode => 'tsquery_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '3677', descr => 'not equal', + oprname => '<>', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '<>(tsquery,tsquery)', + oprnegate => '=(tsquery,tsquery)', oprcode => 'tsquery_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3678', descr => 'greater than or equal', + oprname => '>=', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '<=(tsquery,tsquery)', + oprnegate => '<(tsquery,tsquery)', oprcode => 'tsquery_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, +{ oid => '3679', descr => 'greater than', + oprname => '>', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '<(tsquery,tsquery)', + oprnegate => '<=(tsquery,tsquery)', oprcode => 'tsquery_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3680', descr => 'AND-concatenate', + oprname => '&&', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'tsquery', oprcode => 'tsquery_and' }, +{ oid => '3681', descr => 'OR-concatenate', + oprname => '||', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'tsquery', oprcode => 'tsquery_or' }, +{ oid => '5005', descr => 'phrase-concatenate', + oprname => '<->', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'tsquery', oprcode => 'tsquery_phrase(tsquery,tsquery)' }, +{ oid => '3682', descr => 'NOT tsquery', + oprname => '!!', oprkind => 'l', oprleft => '0', oprright => 'tsquery', + oprresult => 'tsquery', oprcode => 'tsquery_not' }, +{ oid => '3693', descr => 'contains', + oprname => '@>', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '<@(tsquery,tsquery)', + oprcode => 'tsq_mcontains', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3694', descr => 'is contained by', + oprname => '<@', oprleft => 'tsquery', oprright => 'tsquery', + oprresult => 'bool', oprcom => '@>(tsquery,tsquery)', + oprcode => 'tsq_mcontained', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3762', descr => 'text search match', + oprname => '@@', oprleft => 'text', oprright => 'text', oprresult => 'bool', + oprcode => 'ts_match_tt', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3763', descr => 'text search match', + oprname => '@@', oprleft => 'text', oprright => 'tsquery', + oprresult => 'bool', oprcode => 'ts_match_tq', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, + +# generic record comparison operators +{ oid => '2988', oid_symbol => 'RECORD_EQ_OP', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'record', + oprright => 'record', oprresult => 'bool', oprcom => '=(record,record)', + oprnegate => '<>(record,record)', oprcode => 'record_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '2989', descr => 'not equal', + oprname => '<>', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '<>(record,record)', + oprnegate => '=(record,record)', oprcode => 'record_ne', oprrest => 'neqsel', + oprjoin => 'neqjoinsel' }, +{ oid => '2990', oid_symbol => 'RECORD_LT_OP', descr => 'less than', + oprname => '<', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '>(record,record)', + oprnegate => '>=(record,record)', oprcode => 'record_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2991', oid_symbol => 'RECORD_GT_OP', descr => 'greater than', + oprname => '>', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '<(record,record)', + oprnegate => '<=(record,record)', oprcode => 'record_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2992', descr => 'less than or equal', + oprname => '<=', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '>=(record,record)', + oprnegate => '>(record,record)', oprcode => 'record_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2993', descr => 'greater than or equal', + oprname => '>=', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '<=(record,record)', + oprnegate => '<(record,record)', oprcode => 'record_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# byte-oriented tests for identical rows and fast sorting +{ oid => '3188', descr => 'identical', + oprname => '*=', oprcanmerge => 't', oprleft => 'record', + oprright => 'record', oprresult => 'bool', oprcom => '*=(record,record)', + oprnegate => '*<>(record,record)', oprcode => 'record_image_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '3189', descr => 'not identical', + oprname => '*<>', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '*<>(record,record)', + oprnegate => '*=(record,record)', oprcode => 'record_image_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3190', descr => 'less than', + oprname => '*<', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '*>(record,record)', + oprnegate => '*>=(record,record)', oprcode => 'record_image_lt', + oprrest => 'scalarltsel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3191', descr => 'greater than', + oprname => '*>', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '*<(record,record)', + oprnegate => '*<=(record,record)', oprcode => 'record_image_gt', + oprrest => 'scalargtsel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3192', descr => 'less than or equal', + oprname => '*<=', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '*>=(record,record)', + oprnegate => '*>(record,record)', oprcode => 'record_image_le', + oprrest => 'scalarlesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3193', descr => 'greater than or equal', + oprname => '*>=', oprleft => 'record', oprright => 'record', + oprresult => 'bool', oprcom => '*<=(record,record)', + oprnegate => '*<(record,record)', oprcode => 'record_image_ge', + oprrest => 'scalargesel', oprjoin => 'scalargejoinsel' }, + +# generic range type operators +{ oid => '3882', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'anyrange', + oprright => 'anyrange', oprresult => 'bool', oprcom => '=(anyrange,anyrange)', + oprnegate => '<>(anyrange,anyrange)', oprcode => 'range_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '3883', descr => 'not equal', + oprname => '<>', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<>(anyrange,anyrange)', + oprnegate => '=(anyrange,anyrange)', oprcode => 'range_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3884', oid_symbol => 'OID_RANGE_LESS_OP', descr => 'less than', + oprname => '<', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '>(anyrange,anyrange)', + oprnegate => '>=(anyrange,anyrange)', oprcode => 'range_lt', + oprrest => 'rangesel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3885', oid_symbol => 'OID_RANGE_LESS_EQUAL_OP', + descr => 'less than or equal', + oprname => '<=', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '>=(anyrange,anyrange)', + oprnegate => '>(anyrange,anyrange)', oprcode => 'range_le', + oprrest => 'rangesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '3886', oid_symbol => 'OID_RANGE_GREATER_EQUAL_OP', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<=(anyrange,anyrange)', + oprnegate => '<(anyrange,anyrange)', oprcode => 'range_ge', + oprrest => 'rangesel', oprjoin => 'scalargejoinsel' }, +{ oid => '3887', oid_symbol => 'OID_RANGE_GREATER_OP', + descr => 'greater than', + oprname => '>', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<(anyrange,anyrange)', + oprnegate => '<=(anyrange,anyrange)', oprcode => 'range_gt', + oprrest => 'rangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '3888', oid_symbol => 'OID_RANGE_OVERLAP_OP', descr => 'overlaps', + oprname => '&&', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '&&(anyrange,anyrange)', + oprcode => 'range_overlaps', oprrest => 'rangesel', + oprjoin => 'areajoinsel' }, +{ oid => '3889', oid_symbol => 'OID_RANGE_CONTAINS_ELEM_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anyrange', oprright => 'anyelement', + oprresult => 'bool', oprcom => '<@(anyelement,anyrange)', + oprcode => 'range_contains_elem', oprrest => 'rangesel', + oprjoin => 'contjoinsel' }, +{ oid => '3890', oid_symbol => 'OID_RANGE_CONTAINS_OP', descr => 'contains', + oprname => '@>', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<@(anyrange,anyrange)', + oprcode => 'range_contains', oprrest => 'rangesel', + oprjoin => 'contjoinsel' }, +{ oid => '3891', oid_symbol => 'OID_RANGE_ELEM_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anyelement', oprright => 'anyrange', + oprresult => 'bool', oprcom => '@>(anyrange,anyelement)', + oprcode => 'elem_contained_by_range', oprrest => 'rangesel', + oprjoin => 'contjoinsel' }, +{ oid => '3892', oid_symbol => 'OID_RANGE_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '@>(anyrange,anyrange)', + oprcode => 'range_contained_by', oprrest => 'rangesel', + oprjoin => 'contjoinsel' }, +{ oid => '3893', oid_symbol => 'OID_RANGE_LEFT_OP', descr => 'is left of', + oprname => '<<', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '>>(anyrange,anyrange)', + oprcode => 'range_before', oprrest => 'rangesel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '3894', oid_symbol => 'OID_RANGE_RIGHT_OP', descr => 'is right of', + oprname => '>>', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<<(anyrange,anyrange)', + oprcode => 'range_after', oprrest => 'rangesel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '3895', oid_symbol => 'OID_RANGE_OVERLAPS_LEFT_OP', + descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcode => 'range_overleft', oprrest => 'rangesel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '3896', oid_symbol => 'OID_RANGE_OVERLAPS_RIGHT_OP', + descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcode => 'range_overright', oprrest => 'rangesel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '3897', descr => 'is adjacent to', + oprname => '-|-', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '-|-(anyrange,anyrange)', + oprcode => 'range_adjacent', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3898', descr => 'range union', + oprname => '+', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'anyrange', oprcom => '+(anyrange,anyrange)', + oprcode => 'range_union' }, +{ oid => '3899', descr => 'range difference', + oprname => '-', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'anyrange', oprcode => 'range_minus' }, +{ oid => '3900', descr => 'range intersection', + oprname => '*', oprleft => 'anyrange', oprright => 'anyrange', + oprresult => 'anyrange', oprcom => '*(anyrange,anyrange)', + oprcode => 'range_intersect' }, +{ oid => '3962', descr => 'get json object field', + oprname => '->', oprleft => 'json', oprright => 'text', oprresult => 'json', + oprcode => 'json_object_field' }, +{ oid => '3963', descr => 'get json object field as text', + oprname => '->>', oprleft => 'json', oprright => 'text', oprresult => 'text', + oprcode => 'json_object_field_text' }, +{ oid => '3964', descr => 'get json array element', + oprname => '->', oprleft => 'json', oprright => 'int4', oprresult => 'json', + oprcode => 'json_array_element' }, +{ oid => '3965', descr => 'get json array element as text', + oprname => '->>', oprleft => 'json', oprright => 'int4', oprresult => 'text', + oprcode => 'json_array_element_text' }, +{ oid => '3966', descr => 'get value from json with path elements', + oprname => '#>', oprleft => 'json', oprright => '_text', oprresult => 'json', + oprcode => 'json_extract_path' }, +{ oid => '3967', descr => 'get value from json as text with path elements', + oprname => '#>>', oprleft => 'json', oprright => '_text', oprresult => 'text', + oprcode => 'json_extract_path_text' }, +{ oid => '3211', descr => 'get jsonb object field', + oprname => '->', oprleft => 'jsonb', oprright => 'text', oprresult => 'jsonb', + oprcode => 'jsonb_object_field' }, +{ oid => '3477', descr => 'get jsonb object field as text', + oprname => '->>', oprleft => 'jsonb', oprright => 'text', oprresult => 'text', + oprcode => 'jsonb_object_field_text' }, +{ oid => '3212', descr => 'get jsonb array element', + oprname => '->', oprleft => 'jsonb', oprright => 'int4', oprresult => 'jsonb', + oprcode => 'jsonb_array_element' }, +{ oid => '3481', descr => 'get jsonb array element as text', + oprname => '->>', oprleft => 'jsonb', oprright => 'int4', oprresult => 'text', + oprcode => 'jsonb_array_element_text' }, +{ oid => '3213', descr => 'get value from jsonb with path elements', + oprname => '#>', oprleft => 'jsonb', oprright => '_text', + oprresult => 'jsonb', oprcode => 'jsonb_extract_path' }, +{ oid => '3206', descr => 'get value from jsonb as text with path elements', + oprname => '#>>', oprleft => 'jsonb', oprright => '_text', + oprresult => 'text', oprcode => 'jsonb_extract_path_text' }, +{ oid => '3240', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', oprleft => 'jsonb', + oprright => 'jsonb', oprresult => 'bool', oprcom => '=(jsonb,jsonb)', + oprnegate => '<>(jsonb,jsonb)', oprcode => 'jsonb_eq', oprrest => 'eqsel', + oprjoin => 'eqjoinsel' }, +{ oid => '3241', descr => 'not equal', + oprname => '<>', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '<>(jsonb,jsonb)', oprnegate => '=(jsonb,jsonb)', + oprcode => 'jsonb_ne', oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '3242', descr => 'less than', + oprname => '<', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '>(jsonb,jsonb)', oprnegate => '>=(jsonb,jsonb)', + oprcode => 'jsonb_lt', oprrest => 'scalarltsel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '3243', descr => 'greater than', + oprname => '>', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '<(jsonb,jsonb)', oprnegate => '<=(jsonb,jsonb)', + oprcode => 'jsonb_gt', oprrest => 'scalargtsel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '3244', descr => 'less than or equal', + oprname => '<=', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '>=(jsonb,jsonb)', oprnegate => '>(jsonb,jsonb)', + oprcode => 'jsonb_le', oprrest => 'scalarlesel', + oprjoin => 'scalarlejoinsel' }, +{ oid => '3245', descr => 'greater than or equal', + oprname => '>=', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '<=(jsonb,jsonb)', oprnegate => '<(jsonb,jsonb)', + oprcode => 'jsonb_ge', oprrest => 'scalargesel', + oprjoin => 'scalargejoinsel' }, +{ oid => '3246', descr => 'contains', + oprname => '@>', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '<@(jsonb,jsonb)', oprcode => 'jsonb_contains', + oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, +{ oid => '3247', descr => 'key exists', + oprname => '?', oprleft => 'jsonb', oprright => 'text', oprresult => 'bool', + oprcode => 'jsonb_exists', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3248', descr => 'any key exists', + oprname => '?|', oprleft => 'jsonb', oprright => '_text', oprresult => 'bool', + oprcode => 'jsonb_exists_any', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3249', descr => 'all keys exist', + oprname => '?&', oprleft => 'jsonb', oprright => '_text', oprresult => 'bool', + oprcode => 'jsonb_exists_all', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '3250', descr => 'is contained by', + oprname => '<@', oprleft => 'jsonb', oprright => 'jsonb', oprresult => 'bool', + oprcom => '@>(jsonb,jsonb)', oprcode => 'jsonb_contained', + oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, +{ oid => '3284', descr => 'concatenate', + oprname => '||', oprleft => 'jsonb', oprright => 'jsonb', + oprresult => 'jsonb', oprcode => 'jsonb_concat' }, +{ oid => '3285', descr => 'delete object field', + oprname => '-', oprleft => 'jsonb', oprright => 'text', oprresult => 'jsonb', + oprcode => 'jsonb_delete(jsonb,text)' }, +{ oid => '3398', descr => 'delete object fields', + oprname => '-', oprleft => 'jsonb', oprright => '_text', oprresult => 'jsonb', + oprcode => 'jsonb_delete(jsonb,_text)' }, +{ oid => '3286', descr => 'delete array element', + oprname => '-', oprleft => 'jsonb', oprright => 'int4', oprresult => 'jsonb', + oprcode => 'jsonb_delete(jsonb,int4)' }, +{ oid => '3287', descr => 'delete path', + oprname => '#-', oprleft => 'jsonb', oprright => '_text', + oprresult => 'jsonb', oprcode => 'jsonb_delete_path' }, +{ oid => '4012', descr => 'jsonpath exists', + oprname => '@?', oprleft => 'jsonb', oprright => 'jsonpath', + oprresult => 'bool', oprcode => 'jsonb_path_exists_opr(jsonb,jsonpath)', + oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, +{ oid => '4013', descr => 'jsonpath match', + oprname => '@@', oprleft => 'jsonb', oprright => 'jsonpath', + oprresult => 'bool', oprcode => 'jsonb_path_match_opr(jsonb,jsonpath)', + oprrest => 'matchingsel', oprjoin => 'matchingjoinsel' }, +{ oid => '2860', descr => 'equal', + oprname => '=', oprcanmerge => 't', oprcanhash => 't', + oprleft => 'anymultirange', oprright => 'anymultirange', oprresult => 'bool', + oprcom => '=(anymultirange,anymultirange)', + oprnegate => '<>(anymultirange,anymultirange)', oprcode => 'multirange_eq', + oprrest => 'eqsel', oprjoin => 'eqjoinsel' }, +{ oid => '2861', descr => 'not equal', + oprname => '<>', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<>(anymultirange,anymultirange)', + oprnegate => '=(anymultirange,anymultirange)', oprcode => 'multirange_ne', + oprrest => 'neqsel', oprjoin => 'neqjoinsel' }, +{ oid => '2862', oid_symbol => 'OID_MULTIRANGE_LESS_OP', descr => 'less than', + oprname => '<', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '>(anymultirange,anymultirange)', + oprnegate => '>=(anymultirange,anymultirange)', oprcode => 'multirange_lt', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2863', oid_symbol => 'OID_MULTIRANGE_LESS_EQUAL_OP', + descr => 'less than or equal', + oprname => '<=', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '>=(anymultirange,anymultirange)', + oprnegate => '>(anymultirange,anymultirange)', oprcode => 'multirange_le', + oprrest => 'multirangesel', oprjoin => 'scalarlejoinsel' }, +{ oid => '2864', oid_symbol => 'OID_MULTIRANGE_GREATER_EQUAL_OP', + descr => 'greater than or equal', + oprname => '>=', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<=(anymultirange,anymultirange)', + oprnegate => '<(anymultirange,anymultirange)', oprcode => 'multirange_ge', + oprrest => 'multirangesel', oprjoin => 'scalargejoinsel' }, +{ oid => '2865', oid_symbol => 'OID_MULTIRANGE_GREATER_OP', + descr => 'greater than', + oprname => '>', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<(anymultirange,anymultirange)', + oprnegate => '<=(anymultirange,anymultirange)', oprcode => 'multirange_gt', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '2866', oid_symbol => 'OID_RANGE_OVERLAPS_MULTIRANGE_OP', + descr => 'overlaps', + oprname => '&&', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '&&(anymultirange,anyrange)', + oprcode => 'range_overlaps_multirange', oprrest => 'multirangesel', + oprjoin => 'areajoinsel' }, +{ oid => '2867', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RANGE_OP', + descr => 'overlaps', + oprname => '&&', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '&&(anyrange,anymultirange)', + oprcode => 'multirange_overlaps_range', oprrest => 'multirangesel', + oprjoin => 'areajoinsel' }, +{ oid => '2868', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_MULTIRANGE_OP', + descr => 'overlaps', + oprname => '&&', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '&&(anymultirange,anymultirange)', + oprcode => 'multirange_overlaps_multirange', oprrest => 'multirangesel', + oprjoin => 'areajoinsel' }, +{ oid => '2869', oid_symbol => 'OID_MULTIRANGE_CONTAINS_ELEM_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anymultirange', oprright => 'anyelement', + oprresult => 'bool', oprcom => '<@(anyelement,anymultirange)', + oprcode => 'multirange_contains_elem', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2870', oid_symbol => 'OID_MULTIRANGE_CONTAINS_RANGE_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<@(anyrange,anymultirange)', + oprcode => 'multirange_contains_range', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2871', oid_symbol => 'OID_MULTIRANGE_CONTAINS_MULTIRANGE_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<@(anymultirange,anymultirange)', + oprcode => 'multirange_contains_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2872', oid_symbol => 'OID_MULTIRANGE_ELEM_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anyelement', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '@>(anymultirange,anyelement)', + oprcode => 'elem_contained_by_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2873', oid_symbol => 'OID_MULTIRANGE_RANGE_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '@>(anymultirange,anyrange)', + oprcode => 'range_contained_by_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2874', oid_symbol => 'OID_MULTIRANGE_MULTIRANGE_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '@>(anymultirange,anymultirange)', + oprcode => 'multirange_contained_by_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '4539', oid_symbol => 'OID_RANGE_CONTAINS_MULTIRANGE_OP', + descr => 'contains', + oprname => '@>', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<@(anymultirange,anyrange)', + oprcode => 'range_contains_multirange', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '4540', oid_symbol => 'OID_RANGE_MULTIRANGE_CONTAINED_OP', + descr => 'is contained by', + oprname => '<@', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '@>(anyrange,anymultirange)', + oprcode => 'multirange_contained_by_range', oprrest => 'multirangesel', + oprjoin => 'contjoinsel' }, +{ oid => '2875', oid_symbol => 'OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP', + descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcode => 'range_overleft_multirange', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2876', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_LEFT_RANGE_OP', + descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcode => 'multirange_overleft_range', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, +{ oid => '2877', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_LEFT_MULTIRANGE_OP', + descr => 'overlaps or is left of', + oprname => '&<', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcode => 'multirange_overleft_multirange', + oprrest => 'multirangesel', oprjoin => 'scalarltjoinsel' }, +{ oid => '3585', oid_symbol => 'OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP', + descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcode => 'range_overright_multirange', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '4035', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RIGHT_RANGE_OP', + descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcode => 'multirange_overright_range', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '4142', oid_symbol => 'OID_MULTIRANGE_OVERLAPS_RIGHT_MULTIRANGE_OP', + descr => 'overlaps or is right of', + oprname => '&>', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcode => 'multirange_overright_multirange', + oprrest => 'multirangesel', oprjoin => 'scalargtjoinsel' }, +{ oid => '4179', oid_symbol => 'OID_RANGE_ADJACENT_MULTIRANGE_OP', + descr => 'is adjacent to', + oprname => '-|-', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '-|-(anymultirange,anyrange)', + oprcode => 'range_adjacent_multirange', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '4180', oid_symbol => 'OID_MULTIRANGE_ADJACENT_RANGE_OP', + descr => 'is adjacent to', + oprname => '-|-', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '-|-(anyrange,anymultirange)', + oprcode => 'multirange_adjacent_range', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '4198', oid_symbol => 'OID_MULTIRANGE_ADJACENT_MULTIRANGE_OP', + descr => 'is adjacent to', + oprname => '-|-', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '-|-(anymultirange,anymultirange)', + oprcode => 'multirange_adjacent_multirange', oprrest => 'matchingsel', + oprjoin => 'matchingjoinsel' }, +{ oid => '4392', descr => 'multirange union', + oprname => '+', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'anymultirange', oprcom => '+(anymultirange,anymultirange)', + oprcode => 'multirange_union' }, +{ oid => '4393', descr => 'multirange minus', + oprname => '-', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'anymultirange', oprcode => 'multirange_minus' }, +{ oid => '4394', descr => 'multirange intersect', + oprname => '*', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'anymultirange', oprcom => '*(anymultirange,anymultirange)', + oprcode => 'multirange_intersect' }, +{ oid => '4395', oid_symbol => 'OID_RANGE_LEFT_MULTIRANGE_OP', + descr => 'is left of', + oprname => '<<', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '>>(anymultirange,anyrange)', + oprcode => 'range_before_multirange', oprrest => 'multirangesel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '4396', oid_symbol => 'OID_MULTIRANGE_LEFT_RANGE_OP', + descr => 'is left of', + oprname => '<<', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '>>(anyrange,anymultirange)', + oprcode => 'multirange_before_range', oprrest => 'multirangesel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '4397', oid_symbol => 'OID_MULTIRANGE_LEFT_MULTIRANGE_OP', + descr => 'is left of', + oprname => '<<', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '>>(anymultirange,anymultirange)', + oprcode => 'multirange_before_multirange', oprrest => 'multirangesel', + oprjoin => 'scalarltjoinsel' }, +{ oid => '4398', oid_symbol => 'OID_RANGE_RIGHT_MULTIRANGE_OP', + descr => 'is right of', + oprname => '>>', oprleft => 'anyrange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<<(anymultirange,anyrange)', + oprcode => 'range_after_multirange', oprrest => 'multirangesel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '4399', oid_symbol => 'OID_MULTIRANGE_RIGHT_RANGE_OP', + descr => 'is right of', + oprname => '>>', oprleft => 'anymultirange', oprright => 'anyrange', + oprresult => 'bool', oprcom => '<<(anyrange,anymultirange)', + oprcode => 'multirange_after_range', oprrest => 'multirangesel', + oprjoin => 'scalargtjoinsel' }, +{ oid => '4400', oid_symbol => 'OID_MULTIRANGE_RIGHT_MULTIRANGE_OP', + descr => 'is right of', + oprname => '>>', oprleft => 'anymultirange', oprright => 'anymultirange', + oprresult => 'bool', oprcom => '<<(anymultirange,anymultirange)', + oprcode => 'multirange_after_multirange', oprrest => 'multirangesel', + oprjoin => 'scalargtjoinsel' }, + +] diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h new file mode 100644 index 0000000..51263f5 --- /dev/null +++ b/src/include/catalog/pg_operator.h @@ -0,0 +1,107 @@ +/*------------------------------------------------------------------------- + * + * pg_operator.h + * definition of the "operator" system catalog (pg_operator) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_operator.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPERATOR_H +#define PG_OPERATOR_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_operator_d.h" +#include "nodes/pg_list.h" + +/* ---------------- + * pg_operator definition. cpp turns this into + * typedef struct FormData_pg_operator + * ---------------- + */ +CATALOG(pg_operator,2617,OperatorRelationId) +{ + Oid oid; /* oid */ + + /* name of operator */ + NameData oprname; + + /* OID of namespace containing this oper */ + Oid oprnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* operator owner */ + Oid oprowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* 'l' for prefix or 'b' for infix */ + char oprkind BKI_DEFAULT(b); + + /* can be used in merge join? */ + bool oprcanmerge BKI_DEFAULT(f); + + /* can be used in hash join? */ + bool oprcanhash BKI_DEFAULT(f); + + /* left arg type, or 0 if prefix operator */ + Oid oprleft BKI_LOOKUP_OPT(pg_type); + + /* right arg type */ + Oid oprright BKI_LOOKUP(pg_type); + + /* result datatype; can be 0 in a "shell" operator */ + Oid oprresult BKI_LOOKUP_OPT(pg_type); + + /* OID of commutator oper, or 0 if none */ + Oid oprcom BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); + + /* OID of negator oper, or 0 if none */ + Oid oprnegate BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_operator); + + /* OID of underlying function; can be 0 in a "shell" operator */ + regproc oprcode BKI_LOOKUP_OPT(pg_proc); + + /* OID of restriction estimator, or 0 */ + regproc oprrest BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* OID of join estimator, or 0 */ + regproc oprjoin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); +} FormData_pg_operator; + +/* ---------------- + * Form_pg_operator corresponds to a pointer to a tuple with + * the format of pg_operator relation. + * ---------------- + */ +typedef FormData_pg_operator *Form_pg_operator; + +DECLARE_UNIQUE_INDEX_PKEY(pg_operator_oid_index, 2688, OperatorOidIndexId, on pg_operator using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index, 2689, OperatorNameNspIndexId, on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops)); + + +extern ObjectAddress OperatorCreate(const char *operatorName, + Oid operatorNamespace, + Oid leftTypeId, + Oid rightTypeId, + Oid procedureId, + List *commutatorName, + List *negatorName, + Oid restrictionId, + Oid joinId, + bool canMerge, + bool canHash); + +extern ObjectAddress makeOperatorDependencies(HeapTuple tuple, + bool makeExtensionDep, + bool isUpdate); + +extern void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete); + +#endif /* PG_OPERATOR_H */ diff --git a/src/include/catalog/pg_opfamily.dat b/src/include/catalog/pg_opfamily.dat new file mode 100644 index 0000000..f2eaa9b --- /dev/null +++ b/src/include/catalog/pg_opfamily.dat @@ -0,0 +1,308 @@ +#---------------------------------------------------------------------- +# +# pg_opfamily.dat +# Initial contents of the pg_opfamily system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_opfamily.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '397', + opfmethod => 'btree', opfname => 'array_ops' }, +{ oid => '627', + opfmethod => 'hash', opfname => 'array_ops' }, +{ oid => '423', + opfmethod => 'btree', opfname => 'bit_ops' }, +{ oid => '424', oid_symbol => 'BOOL_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bool_ops' }, +{ oid => '426', oid_symbol => 'BPCHAR_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bpchar_ops' }, +{ oid => '427', + opfmethod => 'hash', opfname => 'bpchar_ops' }, +{ oid => '428', oid_symbol => 'BYTEA_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bytea_ops' }, +{ oid => '429', + opfmethod => 'btree', opfname => 'char_ops' }, +{ oid => '431', + opfmethod => 'hash', opfname => 'char_ops' }, +{ oid => '434', + opfmethod => 'btree', opfname => 'datetime_ops' }, +{ oid => '435', + opfmethod => 'hash', opfname => 'date_ops' }, +{ oid => '1970', + opfmethod => 'btree', opfname => 'float_ops' }, +{ oid => '1971', + opfmethod => 'hash', opfname => 'float_ops' }, +{ oid => '1974', oid_symbol => 'NETWORK_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'network_ops' }, +{ oid => '1975', + opfmethod => 'hash', opfname => 'network_ops' }, +{ oid => '3550', + opfmethod => 'gist', opfname => 'network_ops' }, +{ oid => '3794', + opfmethod => 'spgist', opfname => 'network_ops' }, +{ oid => '1976', oid_symbol => 'INTEGER_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'integer_ops' }, +{ oid => '1977', + opfmethod => 'hash', opfname => 'integer_ops' }, +{ oid => '1982', oid_symbol => 'INTERVAL_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'interval_ops' }, +{ oid => '1983', + opfmethod => 'hash', opfname => 'interval_ops' }, +{ oid => '1984', + opfmethod => 'btree', opfname => 'macaddr_ops' }, +{ oid => '1985', + opfmethod => 'hash', opfname => 'macaddr_ops' }, +{ oid => '3371', + opfmethod => 'btree', opfname => 'macaddr8_ops' }, +{ oid => '3372', + opfmethod => 'hash', opfname => 'macaddr8_ops' }, +{ oid => '1988', + opfmethod => 'btree', opfname => 'numeric_ops' }, +{ oid => '1998', + opfmethod => 'hash', opfname => 'numeric_ops' }, +{ oid => '1989', oid_symbol => 'OID_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'oid_ops' }, +{ oid => '1990', + opfmethod => 'hash', opfname => 'oid_ops' }, +{ oid => '1991', + opfmethod => 'btree', opfname => 'oidvector_ops' }, +{ oid => '1992', + opfmethod => 'hash', opfname => 'oidvector_ops' }, +{ oid => '2994', + opfmethod => 'btree', opfname => 'record_ops' }, +{ oid => '6194', + opfmethod => 'hash', opfname => 'record_ops' }, +{ oid => '3194', + opfmethod => 'btree', opfname => 'record_image_ops' }, +{ oid => '1994', oid_symbol => 'TEXT_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'text_ops' }, +{ oid => '1995', + opfmethod => 'hash', opfname => 'text_ops' }, +{ oid => '1996', + opfmethod => 'btree', opfname => 'time_ops' }, +{ oid => '1997', + opfmethod => 'hash', opfname => 'time_ops' }, +{ oid => '1999', + opfmethod => 'hash', opfname => 'timestamptz_ops' }, +{ oid => '2000', + opfmethod => 'btree', opfname => 'timetz_ops' }, +{ oid => '2001', + opfmethod => 'hash', opfname => 'timetz_ops' }, +{ oid => '2002', + opfmethod => 'btree', opfname => 'varbit_ops' }, +{ oid => '2040', + opfmethod => 'hash', opfname => 'timestamp_ops' }, +{ oid => '2095', oid_symbol => 'TEXT_PATTERN_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'text_pattern_ops' }, +{ oid => '2097', oid_symbol => 'BPCHAR_PATTERN_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bpchar_pattern_ops' }, +{ oid => '2099', + opfmethod => 'btree', opfname => 'money_ops' }, +{ oid => '2222', oid_symbol => 'BOOL_HASH_FAM_OID', + opfmethod => 'hash', opfname => 'bool_ops' }, +{ oid => '2223', + opfmethod => 'hash', opfname => 'bytea_ops' }, +{ oid => '2789', + opfmethod => 'btree', opfname => 'tid_ops' }, +{ oid => '2225', + opfmethod => 'hash', opfname => 'xid_ops' }, +{ oid => '5032', + opfmethod => 'hash', opfname => 'xid8_ops' }, +{ oid => '5067', + opfmethod => 'btree', opfname => 'xid8_ops' }, +{ oid => '2226', + opfmethod => 'hash', opfname => 'cid_ops' }, +{ oid => '2227', + opfmethod => 'hash', opfname => 'tid_ops' }, +{ oid => '2229', + opfmethod => 'hash', opfname => 'text_pattern_ops' }, +{ oid => '2231', + opfmethod => 'hash', opfname => 'bpchar_pattern_ops' }, +{ oid => '2235', + opfmethod => 'hash', opfname => 'aclitem_ops' }, +{ oid => '2593', + opfmethod => 'gist', opfname => 'box_ops' }, +{ oid => '2594', + opfmethod => 'gist', opfname => 'poly_ops' }, +{ oid => '2595', + opfmethod => 'gist', opfname => 'circle_ops' }, +{ oid => '1029', + opfmethod => 'gist', opfname => 'point_ops' }, +{ oid => '2745', + opfmethod => 'gin', opfname => 'array_ops' }, +{ oid => '2968', + opfmethod => 'btree', opfname => 'uuid_ops' }, +{ oid => '2969', + opfmethod => 'hash', opfname => 'uuid_ops' }, +{ oid => '3253', + opfmethod => 'btree', opfname => 'pg_lsn_ops' }, +{ oid => '3254', + opfmethod => 'hash', opfname => 'pg_lsn_ops' }, +{ oid => '3522', + opfmethod => 'btree', opfname => 'enum_ops' }, +{ oid => '3523', + opfmethod => 'hash', opfname => 'enum_ops' }, +{ oid => '3626', + opfmethod => 'btree', opfname => 'tsvector_ops' }, +{ oid => '3655', + opfmethod => 'gist', opfname => 'tsvector_ops' }, +{ oid => '3659', + opfmethod => 'gin', opfname => 'tsvector_ops' }, +{ oid => '3683', + opfmethod => 'btree', opfname => 'tsquery_ops' }, +{ oid => '3702', + opfmethod => 'gist', opfname => 'tsquery_ops' }, +{ oid => '3901', + opfmethod => 'btree', opfname => 'range_ops' }, +{ oid => '3903', + opfmethod => 'hash', opfname => 'range_ops' }, +{ oid => '3919', + opfmethod => 'gist', opfname => 'range_ops' }, +{ oid => '3474', + opfmethod => 'spgist', opfname => 'range_ops' }, +{ oid => '4015', + opfmethod => 'spgist', opfname => 'quad_point_ops' }, +{ oid => '4016', + opfmethod => 'spgist', opfname => 'kd_point_ops' }, +{ oid => '4017', oid_symbol => 'TEXT_SPGIST_FAM_OID', + opfmethod => 'spgist', opfname => 'text_ops' }, +{ oid => '4033', + opfmethod => 'btree', opfname => 'jsonb_ops' }, +{ oid => '4034', + opfmethod => 'hash', opfname => 'jsonb_ops' }, +{ oid => '4036', + opfmethod => 'gin', opfname => 'jsonb_ops' }, +{ oid => '4037', + opfmethod => 'gin', opfname => 'jsonb_path_ops' }, +{ oid => '4054', + opfmethod => 'brin', opfname => 'integer_minmax_ops' }, +{ oid => '4602', + opfmethod => 'brin', opfname => 'integer_minmax_multi_ops' }, +{ oid => '4572', + opfmethod => 'brin', opfname => 'integer_bloom_ops' }, +{ oid => '4055', + opfmethod => 'brin', opfname => 'numeric_minmax_ops' }, +{ oid => '4603', + opfmethod => 'brin', opfname => 'numeric_minmax_multi_ops' }, +{ oid => '4056', + opfmethod => 'brin', opfname => 'text_minmax_ops' }, +{ oid => '4573', + opfmethod => 'brin', opfname => 'text_bloom_ops' }, +{ oid => '4574', + opfmethod => 'brin', opfname => 'numeric_bloom_ops' }, +{ oid => '4058', + opfmethod => 'brin', opfname => 'timetz_minmax_ops' }, +{ oid => '4604', + opfmethod => 'brin', opfname => 'timetz_minmax_multi_ops' }, +{ oid => '4575', + opfmethod => 'brin', opfname => 'timetz_bloom_ops' }, +{ oid => '4059', + opfmethod => 'brin', opfname => 'datetime_minmax_ops' }, +{ oid => '4605', + opfmethod => 'brin', opfname => 'datetime_minmax_multi_ops' }, +{ oid => '4576', + opfmethod => 'brin', opfname => 'datetime_bloom_ops' }, +{ oid => '4062', + opfmethod => 'brin', opfname => 'char_minmax_ops' }, +{ oid => '4577', + opfmethod => 'brin', opfname => 'char_bloom_ops' }, +{ oid => '4064', + opfmethod => 'brin', opfname => 'bytea_minmax_ops' }, +{ oid => '4578', + opfmethod => 'brin', opfname => 'bytea_bloom_ops' }, +{ oid => '4065', + opfmethod => 'brin', opfname => 'name_minmax_ops' }, +{ oid => '4579', + opfmethod => 'brin', opfname => 'name_bloom_ops' }, +{ oid => '4068', + opfmethod => 'brin', opfname => 'oid_minmax_ops' }, +{ oid => '4606', + opfmethod => 'brin', opfname => 'oid_minmax_multi_ops' }, +{ oid => '4580', + opfmethod => 'brin', opfname => 'oid_bloom_ops' }, +{ oid => '4069', + opfmethod => 'brin', opfname => 'tid_minmax_ops' }, +{ oid => '4581', + opfmethod => 'brin', opfname => 'tid_bloom_ops' }, +{ oid => '4607', + opfmethod => 'brin', opfname => 'tid_minmax_multi_ops' }, +{ oid => '4070', + opfmethod => 'brin', opfname => 'float_minmax_ops' }, +{ oid => '4608', + opfmethod => 'brin', opfname => 'float_minmax_multi_ops' }, +{ oid => '4582', + opfmethod => 'brin', opfname => 'float_bloom_ops' }, +{ oid => '4074', + opfmethod => 'brin', opfname => 'macaddr_minmax_ops' }, +{ oid => '4609', + opfmethod => 'brin', opfname => 'macaddr_minmax_multi_ops' }, +{ oid => '4583', + opfmethod => 'brin', opfname => 'macaddr_bloom_ops' }, +{ oid => '4109', + opfmethod => 'brin', opfname => 'macaddr8_minmax_ops' }, +{ oid => '4610', + opfmethod => 'brin', opfname => 'macaddr8_minmax_multi_ops' }, +{ oid => '4584', + opfmethod => 'brin', opfname => 'macaddr8_bloom_ops' }, +{ oid => '4075', + opfmethod => 'brin', opfname => 'network_minmax_ops' }, +{ oid => '4611', + opfmethod => 'brin', opfname => 'network_minmax_multi_ops' }, +{ oid => '4102', + opfmethod => 'brin', opfname => 'network_inclusion_ops' }, +{ oid => '4585', + opfmethod => 'brin', opfname => 'network_bloom_ops' }, +{ oid => '4076', + opfmethod => 'brin', opfname => 'bpchar_minmax_ops' }, +{ oid => '4586', + opfmethod => 'brin', opfname => 'bpchar_bloom_ops' }, +{ oid => '4077', + opfmethod => 'brin', opfname => 'time_minmax_ops' }, +{ oid => '4612', + opfmethod => 'brin', opfname => 'time_minmax_multi_ops' }, +{ oid => '4587', + opfmethod => 'brin', opfname => 'time_bloom_ops' }, +{ oid => '4078', + opfmethod => 'brin', opfname => 'interval_minmax_ops' }, +{ oid => '4613', + opfmethod => 'brin', opfname => 'interval_minmax_multi_ops' }, +{ oid => '4588', + opfmethod => 'brin', opfname => 'interval_bloom_ops' }, +{ oid => '4079', + opfmethod => 'brin', opfname => 'bit_minmax_ops' }, +{ oid => '4080', + opfmethod => 'brin', opfname => 'varbit_minmax_ops' }, +{ oid => '4081', + opfmethod => 'brin', opfname => 'uuid_minmax_ops' }, +{ oid => '4614', + opfmethod => 'brin', opfname => 'uuid_minmax_multi_ops' }, +{ oid => '4589', + opfmethod => 'brin', opfname => 'uuid_bloom_ops' }, +{ oid => '4103', + opfmethod => 'brin', opfname => 'range_inclusion_ops' }, +{ oid => '4082', + opfmethod => 'brin', opfname => 'pg_lsn_minmax_ops' }, +{ oid => '4615', + opfmethod => 'brin', opfname => 'pg_lsn_minmax_multi_ops' }, +{ oid => '4590', + opfmethod => 'brin', opfname => 'pg_lsn_bloom_ops' }, +{ oid => '4104', + opfmethod => 'brin', opfname => 'box_inclusion_ops' }, +{ oid => '5000', + opfmethod => 'spgist', opfname => 'box_ops' }, +{ oid => '5008', + opfmethod => 'spgist', opfname => 'poly_ops' }, +{ oid => '4199', + opfmethod => 'btree', opfname => 'multirange_ops' }, +{ oid => '4225', + opfmethod => 'hash', opfname => 'multirange_ops' }, +{ oid => '6158', + opfmethod => 'gist', opfname => 'multirange_ops' }, + +] diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h new file mode 100644 index 0000000..8dc9ce0 --- /dev/null +++ b/src/include/catalog/pg_opfamily.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * pg_opfamily.h + * definition of the "operator family" system catalog (pg_opfamily) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_opfamily.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_OPFAMILY_H +#define PG_OPFAMILY_H + +#include "catalog/genbki.h" +#include "catalog/pg_opfamily_d.h" + +/* ---------------- + * pg_opfamily definition. cpp turns this into + * typedef struct FormData_pg_opfamily + * ---------------- + */ +CATALOG(pg_opfamily,2753,OperatorFamilyRelationId) +{ + Oid oid; /* oid */ + + /* index access method opfamily is for */ + Oid opfmethod BKI_LOOKUP(pg_am); + + /* name of this opfamily */ + NameData opfname; + + /* namespace of this opfamily */ + Oid opfnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* opfamily owner */ + Oid opfowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); +} FormData_pg_opfamily; + +/* ---------------- + * Form_pg_opfamily corresponds to a pointer to a tuple with + * the format of pg_opfamily relation. + * ---------------- + */ +typedef FormData_pg_opfamily *Form_pg_opfamily; + +DECLARE_UNIQUE_INDEX(pg_opfamily_am_name_nsp_index, 2754, OpfamilyAmNameNspIndexId, on pg_opfamily using btree(opfmethod oid_ops, opfname name_ops, opfnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_opfamily_oid_index, 2755, OpfamilyOidIndexId, on pg_opfamily using btree(oid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +#define IsBooleanOpfamily(opfamily) \ + ((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID) + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_OPFAMILY_H */ diff --git a/src/include/catalog/pg_parameter_acl.h b/src/include/catalog/pg_parameter_acl.h new file mode 100644 index 0000000..4bd52c2 --- /dev/null +++ b/src/include/catalog/pg_parameter_acl.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * pg_parameter_acl.h + * definition of the "configuration parameter ACL" system catalog + * (pg_parameter_acl). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_parameter_acl.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PARAMETER_ACL_H +#define PG_PARAMETER_ACL_H + +#include "catalog/genbki.h" +#include "catalog/pg_parameter_acl_d.h" + +/* ---------------- + * pg_parameter_acl definition. cpp turns this into + * typedef struct FormData_pg_parameter_acl + * ---------------- + */ +CATALOG(pg_parameter_acl,6243,ParameterAclRelationId) BKI_SHARED_RELATION +{ + Oid oid; /* oid */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* name of parameter */ + text parname BKI_FORCE_NOT_NULL; + + /* access permissions */ + aclitem paracl[1] BKI_DEFAULT(_null_); +#endif +} FormData_pg_parameter_acl; + + +/* ---------------- + * Form_pg_parameter_acl corresponds to a pointer to a tuple with + * the format of pg_parameter_acl relation. + * ---------------- + */ +typedef FormData_pg_parameter_acl * Form_pg_parameter_acl; + +DECLARE_TOAST_WITH_MACRO(pg_parameter_acl, 6244, 6245, PgParameterAclToastTable, PgParameterAclToastIndex); + +DECLARE_UNIQUE_INDEX(pg_parameter_acl_parname_index, 6246, ParameterAclParnameIndexId, on pg_parameter_acl using btree(parname text_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_parameter_acl_oid_index, 6247, ParameterAclOidIndexId, on pg_parameter_acl using btree(oid oid_ops)); + + +extern Oid ParameterAclLookup(const char *parameter, bool missing_ok); +extern Oid ParameterAclCreate(const char *parameter); + +#endif /* PG_PARAMETER_ACL_H */ diff --git a/src/include/catalog/pg_partitioned_table.h b/src/include/catalog/pg_partitioned_table.h new file mode 100644 index 0000000..9b78f84 --- /dev/null +++ b/src/include/catalog/pg_partitioned_table.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * pg_partitioned_table.h + * definition of the "partitioned table" system catalog + * (pg_partitioned_table) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_partitioned_table.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PARTITIONED_TABLE_H +#define PG_PARTITIONED_TABLE_H + +#include "catalog/genbki.h" +#include "catalog/pg_partitioned_table_d.h" + +/* ---------------- + * pg_partitioned_table definition. cpp turns this into + * typedef struct FormData_pg_partitioned_table + * ---------------- + */ +CATALOG(pg_partitioned_table,3350,PartitionedRelationId) +{ + Oid partrelid BKI_LOOKUP(pg_class); /* partitioned table oid */ + char partstrat; /* partitioning strategy */ + int16 partnatts; /* number of partition key columns */ + Oid partdefid BKI_LOOKUP_OPT(pg_class); /* default partition oid; + * 0 if there isn't one */ + + /* + * variable-length fields start here, but we allow direct access to + * partattrs via the C struct. That's because the first variable-length + * field of a heap tuple can be reliably accessed using its C struct + * offset, as previous fields are all non-nullable fixed-length fields. + */ + int2vector partattrs BKI_FORCE_NOT_NULL; /* each member of the array is + * the attribute number of a + * partition key column, or 0 + * if the column is actually + * an expression */ + +#ifdef CATALOG_VARLEN + oidvector partclass BKI_LOOKUP(pg_opclass) BKI_FORCE_NOT_NULL; /* operator class to + * compare keys */ + oidvector partcollation BKI_LOOKUP_OPT(pg_collation) BKI_FORCE_NOT_NULL; /* user-specified + * collation for keys */ + pg_node_tree partexprs; /* list of expressions in the partition key; + * one item for each zero entry in partattrs[] */ +#endif +} FormData_pg_partitioned_table; + +/* ---------------- + * Form_pg_partitioned_table corresponds to a pointer to a tuple with + * the format of pg_partitioned_table relation. + * ---------------- + */ +typedef FormData_pg_partitioned_table *Form_pg_partitioned_table; + +DECLARE_TOAST(pg_partitioned_table, 4165, 4166); + +DECLARE_UNIQUE_INDEX_PKEY(pg_partitioned_table_partrelid_index, 3351, PartitionedRelidIndexId, on pg_partitioned_table using btree(partrelid oid_ops)); + +/* partattrs can contain zero (InvalidAttrNumber) to represent expressions */ +DECLARE_ARRAY_FOREIGN_KEY_OPT((partrelid, partattrs), pg_attribute, (attrelid, attnum)); + +#endif /* PG_PARTITIONED_TABLE_H */ diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h new file mode 100644 index 0000000..56b0ea1 --- /dev/null +++ b/src/include/catalog/pg_policy.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * pg_policy.h + * definition of the "policy" system catalog (pg_policy) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_policy.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_POLICY_H +#define PG_POLICY_H + +#include "catalog/genbki.h" +#include "catalog/pg_policy_d.h" + +/* ---------------- + * pg_policy definition. cpp turns this into + * typedef struct FormData_pg_policy + * ---------------- + */ +CATALOG(pg_policy,3256,PolicyRelationId) +{ + Oid oid; /* oid */ + NameData polname; /* Policy name. */ + Oid polrelid BKI_LOOKUP(pg_class); /* Oid of the relation with + * policy. */ + char polcmd; /* One of ACL_*_CHR, or '*' for all */ + bool polpermissive; /* restrictive or permissive policy */ + +#ifdef CATALOG_VARLEN + /* Roles to which the policy is applied; zero means PUBLIC */ + Oid polroles[1] BKI_LOOKUP_OPT(pg_authid) BKI_FORCE_NOT_NULL; + pg_node_tree polqual; /* Policy quals. */ + pg_node_tree polwithcheck; /* WITH CHECK quals. */ +#endif +} FormData_pg_policy; + +/* ---------------- + * Form_pg_policy corresponds to a pointer to a row with + * the format of pg_policy relation. + * ---------------- + */ +typedef FormData_pg_policy *Form_pg_policy; + +DECLARE_TOAST(pg_policy, 4167, 4168); + +DECLARE_UNIQUE_INDEX_PKEY(pg_policy_oid_index, 3257, PolicyOidIndexId, on pg_policy using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_policy_polrelid_polname_index, 3258, PolicyPolrelidPolnameIndexId, on pg_policy using btree(polrelid oid_ops, polname name_ops)); + +#endif /* PG_POLICY_H */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat new file mode 100644 index 0000000..8de8834 --- /dev/null +++ b/src/include/catalog/pg_proc.dat @@ -0,0 +1,11815 @@ +#---------------------------------------------------------------------- +# +# pg_proc.dat +# Initial contents of the pg_proc system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_proc.dat +# +#---------------------------------------------------------------------- + +[ + +# Note: every entry in pg_proc.dat is expected to have a 'descr' comment, +# except for functions that implement pg_operator.dat operators and don't +# have a good reason to be called directly rather than via the operator. +# (If you do expect such a function to be used directly, you should +# duplicate the operator's comment.) initdb will supply suitable default +# comments for functions referenced by pg_operator. + +# Try to follow the style of existing functions' comments. +# Some recommended conventions: +# +# "I/O" for typinput, typoutput, typreceive, typsend functions +# "I/O typmod" for typmodin, typmodout functions +# "aggregate transition function" for aggtransfn functions, unless +# they are reasonably useful in their own right +# "aggregate final function" for aggfinalfn functions (likewise) +# "convert srctypename to desttypename" for cast functions +# "less-equal-greater" for B-tree comparison functions + +# Note: pronargs is computed when this file is read, so it does not need +# to be specified in entries here. See AddDefaultValues() in Catalog.pm. + +# Once upon a time these entries were ordered by OID. Lately it's often +# been the custom to insert new entries adjacent to related older entries. +# Try to do one or the other though, don't just insert entries at random. + +# OIDS 1 - 99 + +{ oid => '1242', descr => 'I/O', + proname => 'boolin', prorettype => 'bool', proargtypes => 'cstring', + prosrc => 'boolin' }, +{ oid => '1243', descr => 'I/O', + proname => 'boolout', prorettype => 'cstring', proargtypes => 'bool', + prosrc => 'boolout' }, +{ oid => '1244', descr => 'I/O', + proname => 'byteain', prorettype => 'bytea', proargtypes => 'cstring', + prosrc => 'byteain' }, +{ oid => '31', descr => 'I/O', + proname => 'byteaout', prorettype => 'cstring', proargtypes => 'bytea', + prosrc => 'byteaout' }, +{ oid => '1245', descr => 'I/O', + proname => 'charin', prorettype => 'char', proargtypes => 'cstring', + prosrc => 'charin' }, +{ oid => '33', descr => 'I/O', + proname => 'charout', prorettype => 'cstring', proargtypes => 'char', + prosrc => 'charout' }, +{ oid => '34', descr => 'I/O', + proname => 'namein', prorettype => 'name', proargtypes => 'cstring', + prosrc => 'namein' }, +{ oid => '35', descr => 'I/O', + proname => 'nameout', prorettype => 'cstring', proargtypes => 'name', + prosrc => 'nameout' }, +{ oid => '38', descr => 'I/O', + proname => 'int2in', prorettype => 'int2', proargtypes => 'cstring', + prosrc => 'int2in' }, +{ oid => '39', descr => 'I/O', + proname => 'int2out', prorettype => 'cstring', proargtypes => 'int2', + prosrc => 'int2out' }, +{ oid => '40', descr => 'I/O', + proname => 'int2vectorin', prorettype => 'int2vector', + proargtypes => 'cstring', prosrc => 'int2vectorin' }, +{ oid => '41', descr => 'I/O', + proname => 'int2vectorout', prorettype => 'cstring', + proargtypes => 'int2vector', prosrc => 'int2vectorout' }, +{ oid => '42', descr => 'I/O', + proname => 'int4in', prorettype => 'int4', proargtypes => 'cstring', + prosrc => 'int4in' }, +{ oid => '43', descr => 'I/O', + proname => 'int4out', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'int4out' }, +{ oid => '44', descr => 'I/O', + proname => 'regprocin', provolatile => 's', prorettype => 'regproc', + proargtypes => 'cstring', prosrc => 'regprocin' }, +{ oid => '45', descr => 'I/O', + proname => 'regprocout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regproc', prosrc => 'regprocout' }, +{ oid => '3494', descr => 'convert proname to regproc', + proname => 'to_regproc', provolatile => 's', prorettype => 'regproc', + proargtypes => 'text', prosrc => 'to_regproc' }, +{ oid => '3479', descr => 'convert proname to regprocedure', + proname => 'to_regprocedure', provolatile => 's', + prorettype => 'regprocedure', proargtypes => 'text', + prosrc => 'to_regprocedure' }, +{ oid => '46', descr => 'I/O', + proname => 'textin', prorettype => 'text', proargtypes => 'cstring', + prosrc => 'textin' }, +{ oid => '47', descr => 'I/O', + proname => 'textout', prorettype => 'cstring', proargtypes => 'text', + prosrc => 'textout' }, +{ oid => '48', descr => 'I/O', + proname => 'tidin', prorettype => 'tid', proargtypes => 'cstring', + prosrc => 'tidin' }, +{ oid => '49', descr => 'I/O', + proname => 'tidout', prorettype => 'cstring', proargtypes => 'tid', + prosrc => 'tidout' }, +{ oid => '50', descr => 'I/O', + proname => 'xidin', prorettype => 'xid', proargtypes => 'cstring', + prosrc => 'xidin' }, +{ oid => '51', descr => 'I/O', + proname => 'xidout', prorettype => 'cstring', proargtypes => 'xid', + prosrc => 'xidout' }, +{ oid => '5070', descr => 'I/O', + proname => 'xid8in', prorettype => 'xid8', proargtypes => 'cstring', + prosrc => 'xid8in' }, +{ oid => '5081', descr => 'I/O', + proname => 'xid8out', prorettype => 'cstring', proargtypes => 'xid8', + prosrc => 'xid8out' }, +{ oid => '5082', descr => 'I/O', + proname => 'xid8recv', prorettype => 'xid8', proargtypes => 'internal', + prosrc => 'xid8recv' }, +{ oid => '5083', descr => 'I/O', + proname => 'xid8send', prorettype => 'bytea', proargtypes => 'xid8', + prosrc => 'xid8send' }, +{ oid => '52', descr => 'I/O', + proname => 'cidin', prorettype => 'cid', proargtypes => 'cstring', + prosrc => 'cidin' }, +{ oid => '53', descr => 'I/O', + proname => 'cidout', prorettype => 'cstring', proargtypes => 'cid', + prosrc => 'cidout' }, +{ oid => '54', descr => 'I/O', + proname => 'oidvectorin', prorettype => 'oidvector', proargtypes => 'cstring', + prosrc => 'oidvectorin' }, +{ oid => '55', descr => 'I/O', + proname => 'oidvectorout', prorettype => 'cstring', + proargtypes => 'oidvector', prosrc => 'oidvectorout' }, +{ oid => '56', + proname => 'boollt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boollt' }, +{ oid => '57', + proname => 'boolgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boolgt' }, +{ oid => '60', + proname => 'booleq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'booleq' }, +{ oid => '61', + proname => 'chareq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'chareq' }, +{ oid => '62', + proname => 'nameeq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'nameeq' }, +{ oid => '63', + proname => 'int2eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2eq' }, +{ oid => '64', + proname => 'int2lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2lt' }, +{ oid => '65', + proname => 'int4eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4eq' }, +{ oid => '66', + proname => 'int4lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4lt' }, +{ oid => '67', + proname => 'texteq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'texteq' }, +{ oid => '3696', + proname => 'starts_with', prosupport => 'text_starts_with_support', + proleakproof => 't', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'text_starts_with' }, +{ oid => '6242', descr => 'planner support for text_starts_with', + proname => 'text_starts_with_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'text_starts_with_support' }, +{ oid => '68', + proname => 'xideq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid xid', prosrc => 'xideq' }, +{ oid => '3308', + proname => 'xidneq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid xid', prosrc => 'xidneq' }, +{ oid => '5084', + proname => 'xid8eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8eq' }, +{ oid => '5085', + proname => 'xid8ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8ne' }, +{ oid => '5034', + proname => 'xid8lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8lt' }, +{ oid => '5035', + proname => 'xid8gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8gt' }, +{ oid => '5036', + proname => 'xid8le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8le' }, +{ oid => '5037', + proname => 'xid8ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid8 xid8', prosrc => 'xid8ge' }, +{ oid => '5096', descr => 'less-equal-greater', + proname => 'xid8cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'xid8 xid8', prosrc => 'xid8cmp' }, +{ oid => '5071', descr => 'convert xid8 to xid', + proname => 'xid', prorettype => 'xid', proargtypes => 'xid8', + prosrc => 'xid8toxid' }, +{ oid => '5097', descr => 'larger of two', + proname => 'xid8_larger', prorettype => 'xid8', proargtypes => 'xid8 xid8', + prosrc => 'xid8_larger' }, +{ oid => '5098', descr => 'smaller of two', + proname => 'xid8_smaller', prorettype => 'xid8', proargtypes => 'xid8 xid8', + prosrc => 'xid8_smaller' }, +{ oid => '69', + proname => 'cideq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'cid cid', prosrc => 'cideq' }, +{ oid => '70', + proname => 'charne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'charne' }, +{ oid => '1246', + proname => 'charlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'charlt' }, +{ oid => '72', + proname => 'charle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'charle' }, +{ oid => '73', + proname => 'chargt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'chargt' }, +{ oid => '74', + proname => 'charge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'char char', prosrc => 'charge' }, +{ oid => '77', descr => 'convert char to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'char', + prosrc => 'chartoi4' }, +{ oid => '78', descr => 'convert int4 to char', + proname => 'char', prorettype => 'char', proargtypes => 'int4', + prosrc => 'i4tochar' }, + +{ oid => '79', + proname => 'nameregexeq', prosupport => 'textregexeq_support', + prorettype => 'bool', proargtypes => 'name text', prosrc => 'nameregexeq' }, +{ oid => '1252', + proname => 'nameregexne', prorettype => 'bool', proargtypes => 'name text', + prosrc => 'nameregexne' }, +{ oid => '1254', + proname => 'textregexeq', prosupport => 'textregexeq_support', + prorettype => 'bool', proargtypes => 'text text', prosrc => 'textregexeq' }, +{ oid => '1256', + proname => 'textregexne', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'textregexne' }, +{ oid => '1364', descr => 'planner support for textregexeq', + proname => 'textregexeq_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'textregexeq_support' }, + +{ oid => '1257', descr => 'length', + proname => 'textlen', prorettype => 'int4', proargtypes => 'text', + prosrc => 'textlen' }, +{ oid => '1258', + proname => 'textcat', prorettype => 'text', proargtypes => 'text text', + prosrc => 'textcat' }, + +{ oid => '84', + proname => 'boolne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boolne' }, +{ oid => '89', descr => 'PostgreSQL version string', + proname => 'version', provolatile => 's', prorettype => 'text', + proargtypes => '', prosrc => 'pgsql_version' }, + +{ oid => '86', descr => 'I/O', + proname => 'pg_ddl_command_in', prorettype => 'pg_ddl_command', + proargtypes => 'cstring', prosrc => 'pg_ddl_command_in' }, +{ oid => '87', descr => 'I/O', + proname => 'pg_ddl_command_out', prorettype => 'cstring', + proargtypes => 'pg_ddl_command', prosrc => 'pg_ddl_command_out' }, +{ oid => '88', descr => 'I/O', + proname => 'pg_ddl_command_recv', prorettype => 'pg_ddl_command', + proargtypes => 'internal', prosrc => 'pg_ddl_command_recv' }, +{ oid => '90', descr => 'I/O', + proname => 'pg_ddl_command_send', prorettype => 'bytea', + proargtypes => 'pg_ddl_command', prosrc => 'pg_ddl_command_send' }, + +# OIDS 100 - 199 + +{ oid => '101', descr => 'restriction selectivity of = and related operators', + proname => 'eqsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'eqsel' }, +{ oid => '102', + descr => 'restriction selectivity of <> and related operators', + proname => 'neqsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'neqsel' }, +{ oid => '103', + descr => 'restriction selectivity of < and related operators on scalar datatypes', + proname => 'scalarltsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'scalarltsel' }, +{ oid => '104', + descr => 'restriction selectivity of > and related operators on scalar datatypes', + proname => 'scalargtsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'scalargtsel' }, +{ oid => '105', descr => 'join selectivity of = and related operators', + proname => 'eqjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', prosrc => 'eqjoinsel' }, +{ oid => '106', descr => 'join selectivity of <> and related operators', + proname => 'neqjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'neqjoinsel' }, +{ oid => '107', + descr => 'join selectivity of < and related operators on scalar datatypes', + proname => 'scalarltjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'scalarltjoinsel' }, +{ oid => '108', + descr => 'join selectivity of > and related operators on scalar datatypes', + proname => 'scalargtjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'scalargtjoinsel' }, + +{ oid => '336', + descr => 'restriction selectivity of <= and related operators on scalar datatypes', + proname => 'scalarlesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'scalarlesel' }, +{ oid => '337', + descr => 'restriction selectivity of >= and related operators on scalar datatypes', + proname => 'scalargesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'scalargesel' }, +{ oid => '386', + descr => 'join selectivity of <= and related operators on scalar datatypes', + proname => 'scalarlejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'scalarlejoinsel' }, +{ oid => '398', + descr => 'join selectivity of >= and related operators on scalar datatypes', + proname => 'scalargejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'scalargejoinsel' }, + +{ oid => '109', descr => 'I/O', + proname => 'unknownin', prorettype => 'unknown', proargtypes => 'cstring', + prosrc => 'unknownin' }, +{ oid => '110', descr => 'I/O', + proname => 'unknownout', prorettype => 'cstring', proargtypes => 'unknown', + prosrc => 'unknownout' }, + +{ oid => '115', + proname => 'box_above_eq', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_above_eq' }, +{ oid => '116', + proname => 'box_below_eq', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_below_eq' }, + +{ oid => '117', descr => 'I/O', + proname => 'point_in', prorettype => 'point', proargtypes => 'cstring', + prosrc => 'point_in' }, +{ oid => '118', descr => 'I/O', + proname => 'point_out', prorettype => 'cstring', proargtypes => 'point', + prosrc => 'point_out' }, +{ oid => '119', descr => 'I/O', + proname => 'lseg_in', prorettype => 'lseg', proargtypes => 'cstring', + prosrc => 'lseg_in' }, +{ oid => '120', descr => 'I/O', + proname => 'lseg_out', prorettype => 'cstring', proargtypes => 'lseg', + prosrc => 'lseg_out' }, +{ oid => '121', descr => 'I/O', + proname => 'path_in', prorettype => 'path', proargtypes => 'cstring', + prosrc => 'path_in' }, +{ oid => '122', descr => 'I/O', + proname => 'path_out', prorettype => 'cstring', proargtypes => 'path', + prosrc => 'path_out' }, +{ oid => '123', descr => 'I/O', + proname => 'box_in', prorettype => 'box', proargtypes => 'cstring', + prosrc => 'box_in' }, +{ oid => '124', descr => 'I/O', + proname => 'box_out', prorettype => 'cstring', proargtypes => 'box', + prosrc => 'box_out' }, +{ oid => '125', + proname => 'box_overlap', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_overlap' }, +{ oid => '126', + proname => 'box_ge', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_ge' }, +{ oid => '127', + proname => 'box_gt', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_gt' }, +{ oid => '128', + proname => 'box_eq', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_eq' }, +{ oid => '129', + proname => 'box_lt', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_lt' }, +{ oid => '130', + proname => 'box_le', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_le' }, +{ oid => '131', + proname => 'point_above', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_above' }, +{ oid => '132', + proname => 'point_left', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_left' }, +{ oid => '133', + proname => 'point_right', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_right' }, +{ oid => '134', + proname => 'point_below', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_below' }, +{ oid => '135', + proname => 'point_eq', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_eq' }, +{ oid => '136', + proname => 'on_pb', prorettype => 'bool', proargtypes => 'point box', + prosrc => 'on_pb' }, +{ oid => '137', + proname => 'on_ppath', prorettype => 'bool', proargtypes => 'point path', + prosrc => 'on_ppath' }, +{ oid => '138', + proname => 'box_center', prorettype => 'point', proargtypes => 'box', + prosrc => 'box_center' }, +{ oid => '139', + descr => 'restriction selectivity for area-comparison operators', + proname => 'areasel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'areasel' }, +{ oid => '140', descr => 'join selectivity for area-comparison operators', + proname => 'areajoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'areajoinsel' }, +{ oid => '141', + proname => 'int4mul', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4mul' }, +{ oid => '144', + proname => 'int4ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4ne' }, +{ oid => '145', + proname => 'int2ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2ne' }, +{ oid => '146', + proname => 'int2gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2gt' }, +{ oid => '147', + proname => 'int4gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4gt' }, +{ oid => '148', + proname => 'int2le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2le' }, +{ oid => '149', + proname => 'int4le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4le' }, +{ oid => '150', + proname => 'int4ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int4', prosrc => 'int4ge' }, +{ oid => '151', + proname => 'int2ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int2', prosrc => 'int2ge' }, +{ oid => '152', + proname => 'int2mul', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2mul' }, +{ oid => '153', + proname => 'int2div', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2div' }, +{ oid => '154', + proname => 'int4div', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4div' }, +{ oid => '155', + proname => 'int2mod', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2mod' }, +{ oid => '156', + proname => 'int4mod', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4mod' }, +{ oid => '157', + proname => 'textne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'textne' }, +{ oid => '158', + proname => 'int24eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24eq' }, +{ oid => '159', + proname => 'int42eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42eq' }, +{ oid => '160', + proname => 'int24lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24lt' }, +{ oid => '161', + proname => 'int42lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42lt' }, +{ oid => '162', + proname => 'int24gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24gt' }, +{ oid => '163', + proname => 'int42gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42gt' }, +{ oid => '164', + proname => 'int24ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24ne' }, +{ oid => '165', + proname => 'int42ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42ne' }, +{ oid => '166', + proname => 'int24le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24le' }, +{ oid => '167', + proname => 'int42le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42le' }, +{ oid => '168', + proname => 'int24ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int4', prosrc => 'int24ge' }, +{ oid => '169', + proname => 'int42ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int2', prosrc => 'int42ge' }, +{ oid => '170', + proname => 'int24mul', prorettype => 'int4', proargtypes => 'int2 int4', + prosrc => 'int24mul' }, +{ oid => '171', + proname => 'int42mul', prorettype => 'int4', proargtypes => 'int4 int2', + prosrc => 'int42mul' }, +{ oid => '172', + proname => 'int24div', prorettype => 'int4', proargtypes => 'int2 int4', + prosrc => 'int24div' }, +{ oid => '173', + proname => 'int42div', prorettype => 'int4', proargtypes => 'int4 int2', + prosrc => 'int42div' }, +{ oid => '176', + proname => 'int2pl', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2pl' }, +{ oid => '177', + proname => 'int4pl', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4pl' }, +{ oid => '178', + proname => 'int24pl', prorettype => 'int4', proargtypes => 'int2 int4', + prosrc => 'int24pl' }, +{ oid => '179', + proname => 'int42pl', prorettype => 'int4', proargtypes => 'int4 int2', + prosrc => 'int42pl' }, +{ oid => '180', + proname => 'int2mi', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2mi' }, +{ oid => '181', + proname => 'int4mi', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4mi' }, +{ oid => '182', + proname => 'int24mi', prorettype => 'int4', proargtypes => 'int2 int4', + prosrc => 'int24mi' }, +{ oid => '183', + proname => 'int42mi', prorettype => 'int4', proargtypes => 'int4 int2', + prosrc => 'int42mi' }, +{ oid => '184', + proname => 'oideq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oideq' }, +{ oid => '185', + proname => 'oidne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oidne' }, +{ oid => '186', + proname => 'box_same', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_same' }, +{ oid => '187', + proname => 'box_contain', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_contain' }, +{ oid => '188', + proname => 'box_left', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_left' }, +{ oid => '189', + proname => 'box_overleft', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_overleft' }, +{ oid => '190', + proname => 'box_overright', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_overright' }, +{ oid => '191', + proname => 'box_right', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_right' }, +{ oid => '192', + proname => 'box_contained', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_contained' }, +{ oid => '193', + proname => 'box_contain_pt', prorettype => 'bool', proargtypes => 'box point', + prosrc => 'box_contain_pt' }, + +{ oid => '195', descr => 'I/O', + proname => 'pg_node_tree_in', prorettype => 'pg_node_tree', + proargtypes => 'cstring', prosrc => 'pg_node_tree_in' }, +{ oid => '196', descr => 'I/O', + proname => 'pg_node_tree_out', prorettype => 'cstring', + proargtypes => 'pg_node_tree', prosrc => 'pg_node_tree_out' }, +{ oid => '197', descr => 'I/O', + proname => 'pg_node_tree_recv', provolatile => 's', + prorettype => 'pg_node_tree', proargtypes => 'internal', + prosrc => 'pg_node_tree_recv' }, +{ oid => '198', descr => 'I/O', + proname => 'pg_node_tree_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'pg_node_tree', prosrc => 'pg_node_tree_send' }, + +# OIDS 200 - 299 + +{ oid => '200', descr => 'I/O', + proname => 'float4in', prorettype => 'float4', proargtypes => 'cstring', + prosrc => 'float4in' }, +{ oid => '201', descr => 'I/O', + proname => 'float4out', prorettype => 'cstring', proargtypes => 'float4', + prosrc => 'float4out' }, +{ oid => '202', + proname => 'float4mul', prorettype => 'float4', + proargtypes => 'float4 float4', prosrc => 'float4mul' }, +{ oid => '203', + proname => 'float4div', prorettype => 'float4', + proargtypes => 'float4 float4', prosrc => 'float4div' }, +{ oid => '204', + proname => 'float4pl', prorettype => 'float4', proargtypes => 'float4 float4', + prosrc => 'float4pl' }, +{ oid => '205', + proname => 'float4mi', prorettype => 'float4', proargtypes => 'float4 float4', + prosrc => 'float4mi' }, +{ oid => '206', + proname => 'float4um', prorettype => 'float4', proargtypes => 'float4', + prosrc => 'float4um' }, +{ oid => '207', + proname => 'float4abs', prorettype => 'float4', proargtypes => 'float4', + prosrc => 'float4abs' }, +{ oid => '208', descr => 'aggregate transition function', + proname => 'float4_accum', prorettype => '_float8', + proargtypes => '_float8 float4', prosrc => 'float4_accum' }, +{ oid => '209', descr => 'larger of two', + proname => 'float4larger', prorettype => 'float4', + proargtypes => 'float4 float4', prosrc => 'float4larger' }, +{ oid => '211', descr => 'smaller of two', + proname => 'float4smaller', prorettype => 'float4', + proargtypes => 'float4 float4', prosrc => 'float4smaller' }, + +{ oid => '212', + proname => 'int4um', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4um' }, +{ oid => '213', + proname => 'int2um', prorettype => 'int2', proargtypes => 'int2', + prosrc => 'int2um' }, + +{ oid => '214', descr => 'I/O', + proname => 'float8in', prorettype => 'float8', proargtypes => 'cstring', + prosrc => 'float8in' }, +{ oid => '215', descr => 'I/O', + proname => 'float8out', prorettype => 'cstring', proargtypes => 'float8', + prosrc => 'float8out' }, +{ oid => '216', + proname => 'float8mul', prorettype => 'float8', + proargtypes => 'float8 float8', prosrc => 'float8mul' }, +{ oid => '217', + proname => 'float8div', prorettype => 'float8', + proargtypes => 'float8 float8', prosrc => 'float8div' }, +{ oid => '218', + proname => 'float8pl', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'float8pl' }, +{ oid => '219', + proname => 'float8mi', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'float8mi' }, +{ oid => '220', + proname => 'float8um', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'float8um' }, +{ oid => '221', + proname => 'float8abs', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'float8abs' }, +{ oid => '222', descr => 'aggregate transition function', + proname => 'float8_accum', prorettype => '_float8', + proargtypes => '_float8 float8', prosrc => 'float8_accum' }, +{ oid => '276', descr => 'aggregate combine function', + proname => 'float8_combine', prorettype => '_float8', + proargtypes => '_float8 _float8', prosrc => 'float8_combine' }, +{ oid => '223', descr => 'larger of two', + proname => 'float8larger', prorettype => 'float8', + proargtypes => 'float8 float8', prosrc => 'float8larger' }, +{ oid => '224', descr => 'smaller of two', + proname => 'float8smaller', prorettype => 'float8', + proargtypes => 'float8 float8', prosrc => 'float8smaller' }, + +{ oid => '225', + proname => 'lseg_center', prorettype => 'point', proargtypes => 'lseg', + prosrc => 'lseg_center' }, +{ oid => '227', + proname => 'poly_center', prorettype => 'point', proargtypes => 'polygon', + prosrc => 'poly_center' }, + +{ oid => '228', descr => 'round to nearest integer', + proname => 'dround', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dround' }, +{ oid => '229', descr => 'truncate to integer', + proname => 'dtrunc', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dtrunc' }, +{ oid => '2308', descr => 'nearest integer >= value', + proname => 'ceil', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dceil' }, +{ oid => '2320', descr => 'nearest integer >= value', + proname => 'ceiling', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dceil' }, +{ oid => '2309', descr => 'nearest integer <= value', + proname => 'floor', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dfloor' }, +{ oid => '2310', descr => 'sign of value', + proname => 'sign', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsign' }, +{ oid => '230', + proname => 'dsqrt', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsqrt' }, +{ oid => '231', + proname => 'dcbrt', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcbrt' }, +{ oid => '232', + proname => 'dpow', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'dpow' }, +{ oid => '233', descr => 'natural exponential (e^x)', + proname => 'dexp', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dexp' }, +{ oid => '234', descr => 'natural logarithm', + proname => 'dlog1', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dlog1' }, +{ oid => '235', descr => 'convert int2 to float8', + proname => 'float8', proleakproof => 't', prorettype => 'float8', + proargtypes => 'int2', prosrc => 'i2tod' }, +{ oid => '236', descr => 'convert int2 to float4', + proname => 'float4', proleakproof => 't', prorettype => 'float4', + proargtypes => 'int2', prosrc => 'i2tof' }, +{ oid => '237', descr => 'convert float8 to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'float8', + prosrc => 'dtoi2' }, +{ oid => '238', descr => 'convert float4 to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'float4', + prosrc => 'ftoi2' }, +{ oid => '239', + proname => 'line_distance', prorettype => 'float8', + proargtypes => 'line line', prosrc => 'line_distance' }, + +{ oid => '240', + proname => 'nameeqtext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'nameeqtext' }, +{ oid => '241', + proname => 'namelttext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namelttext' }, +{ oid => '242', + proname => 'nameletext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'nameletext' }, +{ oid => '243', + proname => 'namegetext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namegetext' }, +{ oid => '244', + proname => 'namegttext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namegttext' }, +{ oid => '245', + proname => 'namenetext', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namenetext' }, +{ oid => '246', descr => 'less-equal-greater', + proname => 'btnametextcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'name text', prosrc => 'btnametextcmp' }, +{ oid => '247', + proname => 'texteqname', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'texteqname' }, +{ oid => '248', + proname => 'textltname', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'textltname' }, +{ oid => '249', + proname => 'textlename', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'textlename' }, +{ oid => '250', + proname => 'textgename', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'textgename' }, +{ oid => '251', + proname => 'textgtname', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'textgtname' }, +{ oid => '252', + proname => 'textnename', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text name', prosrc => 'textnename' }, +{ oid => '253', descr => 'less-equal-greater', + proname => 'bttextnamecmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'text name', prosrc => 'bttextnamecmp' }, + +{ oid => '266', descr => 'concatenate name and oid', + proname => 'nameconcatoid', prorettype => 'name', proargtypes => 'name oid', + prosrc => 'nameconcatoid' }, + +{ oid => '274', + descr => 'current date and time - increments during transactions', + proname => 'timeofday', provolatile => 'v', prorettype => 'text', + proargtypes => '', prosrc => 'timeofday' }, + +{ oid => '277', + proname => 'inter_sl', prorettype => 'bool', proargtypes => 'lseg line', + prosrc => 'inter_sl' }, +{ oid => '278', + proname => 'inter_lb', prorettype => 'bool', proargtypes => 'line box', + prosrc => 'inter_lb' }, + +{ oid => '279', + proname => 'float48mul', prorettype => 'float8', + proargtypes => 'float4 float8', prosrc => 'float48mul' }, +{ oid => '280', + proname => 'float48div', prorettype => 'float8', + proargtypes => 'float4 float8', prosrc => 'float48div' }, +{ oid => '281', + proname => 'float48pl', prorettype => 'float8', + proargtypes => 'float4 float8', prosrc => 'float48pl' }, +{ oid => '282', + proname => 'float48mi', prorettype => 'float8', + proargtypes => 'float4 float8', prosrc => 'float48mi' }, +{ oid => '283', + proname => 'float84mul', prorettype => 'float8', + proargtypes => 'float8 float4', prosrc => 'float84mul' }, +{ oid => '284', + proname => 'float84div', prorettype => 'float8', + proargtypes => 'float8 float4', prosrc => 'float84div' }, +{ oid => '285', + proname => 'float84pl', prorettype => 'float8', + proargtypes => 'float8 float4', prosrc => 'float84pl' }, +{ oid => '286', + proname => 'float84mi', prorettype => 'float8', + proargtypes => 'float8 float4', prosrc => 'float84mi' }, + +{ oid => '287', + proname => 'float4eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4eq' }, +{ oid => '288', + proname => 'float4ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4ne' }, +{ oid => '289', + proname => 'float4lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4lt' }, +{ oid => '290', + proname => 'float4le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4le' }, +{ oid => '291', + proname => 'float4gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4gt' }, +{ oid => '292', + proname => 'float4ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float4', prosrc => 'float4ge' }, + +{ oid => '293', + proname => 'float8eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8eq' }, +{ oid => '294', + proname => 'float8ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8ne' }, +{ oid => '295', + proname => 'float8lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8lt' }, +{ oid => '296', + proname => 'float8le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8le' }, +{ oid => '297', + proname => 'float8gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8gt' }, +{ oid => '298', + proname => 'float8ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float8', prosrc => 'float8ge' }, + +{ oid => '299', + proname => 'float48eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48eq' }, + +# OIDS 300 - 399 + +{ oid => '300', + proname => 'float48ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48ne' }, +{ oid => '301', + proname => 'float48lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48lt' }, +{ oid => '302', + proname => 'float48le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48le' }, +{ oid => '303', + proname => 'float48gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48gt' }, +{ oid => '304', + proname => 'float48ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float4 float8', prosrc => 'float48ge' }, +{ oid => '305', + proname => 'float84eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84eq' }, +{ oid => '306', + proname => 'float84ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84ne' }, +{ oid => '307', + proname => 'float84lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84lt' }, +{ oid => '308', + proname => 'float84le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84le' }, +{ oid => '309', + proname => 'float84gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84gt' }, +{ oid => '310', + proname => 'float84ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'float8 float4', prosrc => 'float84ge' }, +{ oid => '320', descr => 'bucket number of operand in equal-width histogram', + proname => 'width_bucket', prorettype => 'int4', + proargtypes => 'float8 float8 float8 int4', prosrc => 'width_bucket_float8' }, + +{ oid => '311', descr => 'convert float4 to float8', + proname => 'float8', proleakproof => 't', prorettype => 'float8', + proargtypes => 'float4', prosrc => 'ftod' }, +{ oid => '312', descr => 'convert float8 to float4', + proname => 'float4', prorettype => 'float4', proargtypes => 'float8', + prosrc => 'dtof' }, +{ oid => '313', descr => 'convert int2 to int4', + proname => 'int4', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int2', prosrc => 'i2toi4' }, +{ oid => '314', descr => 'convert int4 to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'int4', + prosrc => 'i4toi2' }, +{ oid => '316', descr => 'convert int4 to float8', + proname => 'float8', proleakproof => 't', prorettype => 'float8', + proargtypes => 'int4', prosrc => 'i4tod' }, +{ oid => '317', descr => 'convert float8 to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'float8', + prosrc => 'dtoi4' }, +{ oid => '318', descr => 'convert int4 to float4', + proname => 'float4', proleakproof => 't', prorettype => 'float4', + proargtypes => 'int4', prosrc => 'i4tof' }, +{ oid => '319', descr => 'convert float4 to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'float4', + prosrc => 'ftoi4' }, + +# Table access method handlers +{ oid => '3', descr => 'row-oriented heap table access method handler', + proname => 'heap_tableam_handler', provolatile => 'v', + prorettype => 'table_am_handler', proargtypes => 'internal', + prosrc => 'heap_tableam_handler' }, + +# Index access method handlers +{ oid => '330', descr => 'btree index access method handler', + proname => 'bthandler', provolatile => 'v', prorettype => 'index_am_handler', + proargtypes => 'internal', prosrc => 'bthandler' }, +{ oid => '331', descr => 'hash index access method handler', + proname => 'hashhandler', provolatile => 'v', + prorettype => 'index_am_handler', proargtypes => 'internal', + prosrc => 'hashhandler' }, +{ oid => '332', descr => 'gist index access method handler', + proname => 'gisthandler', provolatile => 'v', + prorettype => 'index_am_handler', proargtypes => 'internal', + prosrc => 'gisthandler' }, +{ oid => '333', descr => 'gin index access method handler', + proname => 'ginhandler', provolatile => 'v', prorettype => 'index_am_handler', + proargtypes => 'internal', prosrc => 'ginhandler' }, +{ oid => '334', descr => 'spgist index access method handler', + proname => 'spghandler', provolatile => 'v', prorettype => 'index_am_handler', + proargtypes => 'internal', prosrc => 'spghandler' }, +{ oid => '335', descr => 'brin index access method handler', + proname => 'brinhandler', provolatile => 'v', + prorettype => 'index_am_handler', proargtypes => 'internal', + prosrc => 'brinhandler' }, +{ oid => '3952', descr => 'brin: standalone scan new table pages', + proname => 'brin_summarize_new_values', provolatile => 'v', + proparallel => 'u', prorettype => 'int4', proargtypes => 'regclass', + prosrc => 'brin_summarize_new_values' }, +{ oid => '3999', descr => 'brin: standalone scan new table pages', + proname => 'brin_summarize_range', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'regclass int8', + prosrc => 'brin_summarize_range' }, +{ oid => '4014', descr => 'brin: desummarize page range', + proname => 'brin_desummarize_range', provolatile => 'v', proparallel => 'u', + prorettype => 'void', proargtypes => 'regclass int8', + prosrc => 'brin_desummarize_range' }, + +{ oid => '338', descr => 'validate an operator class', + proname => 'amvalidate', provolatile => 'v', prorettype => 'bool', + proargtypes => 'oid', prosrc => 'amvalidate' }, + +{ oid => '636', descr => 'test property of an index access method', + proname => 'pg_indexam_has_property', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text', + prosrc => 'pg_indexam_has_property' }, +{ oid => '637', descr => 'test property of an index', + proname => 'pg_index_has_property', provolatile => 's', prorettype => 'bool', + proargtypes => 'regclass text', prosrc => 'pg_index_has_property' }, +{ oid => '638', descr => 'test property of an index column', + proname => 'pg_index_column_has_property', provolatile => 's', + prorettype => 'bool', proargtypes => 'regclass int4 text', + prosrc => 'pg_index_column_has_property' }, +{ oid => '676', descr => 'return name of given index build phase', + proname => 'pg_indexam_progress_phasename', prorettype => 'text', + proargtypes => 'oid int8', prosrc => 'pg_indexam_progress_phasename' }, + +{ oid => '339', + proname => 'poly_same', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_same' }, +{ oid => '340', + proname => 'poly_contain', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_contain' }, +{ oid => '341', + proname => 'poly_left', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_left' }, +{ oid => '342', + proname => 'poly_overleft', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_overleft' }, +{ oid => '343', + proname => 'poly_overright', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_overright' }, +{ oid => '344', + proname => 'poly_right', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_right' }, +{ oid => '345', + proname => 'poly_contained', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_contained' }, +{ oid => '346', + proname => 'poly_overlap', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_overlap' }, +{ oid => '347', descr => 'I/O', + proname => 'poly_in', prorettype => 'polygon', proargtypes => 'cstring', + prosrc => 'poly_in' }, +{ oid => '348', descr => 'I/O', + proname => 'poly_out', prorettype => 'cstring', proargtypes => 'polygon', + prosrc => 'poly_out' }, + +{ oid => '350', descr => 'less-equal-greater', + proname => 'btint2cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int2 int2', prosrc => 'btint2cmp' }, +{ oid => '3129', descr => 'sort support', + proname => 'btint2sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btint2sortsupport' }, +{ oid => '351', descr => 'less-equal-greater', + proname => 'btint4cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int4 int4', prosrc => 'btint4cmp' }, +{ oid => '3130', descr => 'sort support', + proname => 'btint4sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btint4sortsupport' }, +{ oid => '842', descr => 'less-equal-greater', + proname => 'btint8cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int8 int8', prosrc => 'btint8cmp' }, +{ oid => '3131', descr => 'sort support', + proname => 'btint8sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btint8sortsupport' }, +{ oid => '354', descr => 'less-equal-greater', + proname => 'btfloat4cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'float4 float4', prosrc => 'btfloat4cmp' }, +{ oid => '3132', descr => 'sort support', + proname => 'btfloat4sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btfloat4sortsupport' }, +{ oid => '355', descr => 'less-equal-greater', + proname => 'btfloat8cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'float8 float8', prosrc => 'btfloat8cmp' }, +{ oid => '3133', descr => 'sort support', + proname => 'btfloat8sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btfloat8sortsupport' }, +{ oid => '356', descr => 'less-equal-greater', + proname => 'btoidcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'oid oid', prosrc => 'btoidcmp' }, +{ oid => '3134', descr => 'sort support', + proname => 'btoidsortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btoidsortsupport' }, +{ oid => '404', descr => 'less-equal-greater', + proname => 'btoidvectorcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'oidvector oidvector', prosrc => 'btoidvectorcmp' }, +{ oid => '358', descr => 'less-equal-greater', + proname => 'btcharcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'char char', prosrc => 'btcharcmp' }, +{ oid => '359', descr => 'less-equal-greater', + proname => 'btnamecmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'name name', prosrc => 'btnamecmp' }, +{ oid => '3135', descr => 'sort support', + proname => 'btnamesortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btnamesortsupport' }, +{ oid => '360', descr => 'less-equal-greater', + proname => 'bttextcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'text text', prosrc => 'bttextcmp' }, +{ oid => '3255', descr => 'sort support', + proname => 'bttextsortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'bttextsortsupport' }, +{ oid => '5050', descr => 'equal image', + proname => 'btvarstrequalimage', prorettype => 'bool', proargtypes => 'oid', + prosrc => 'btvarstrequalimage' }, +{ oid => '377', descr => 'less-equal-greater', + proname => 'cash_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'money money', prosrc => 'cash_cmp' }, +{ oid => '382', descr => 'less-equal-greater', + proname => 'btarraycmp', prorettype => 'int4', + proargtypes => 'anyarray anyarray', prosrc => 'btarraycmp' }, +{ oid => '4126', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int8 int8 int8 bool bool', prosrc => 'in_range_int8_int8' }, +{ oid => '4127', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int4 int4 int8 bool bool', prosrc => 'in_range_int4_int8' }, +{ oid => '4128', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int4 int4 int4 bool bool', prosrc => 'in_range_int4_int4' }, +{ oid => '4129', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int4 int4 int2 bool bool', prosrc => 'in_range_int4_int2' }, +{ oid => '4130', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int2 int2 int8 bool bool', prosrc => 'in_range_int2_int8' }, +{ oid => '4131', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int2 int2 int4 bool bool', prosrc => 'in_range_int2_int4' }, +{ oid => '4132', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'int2 int2 int2 bool bool', prosrc => 'in_range_int2_int2' }, +{ oid => '4139', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'float8 float8 float8 bool bool', + prosrc => 'in_range_float8_float8' }, +{ oid => '4140', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'float4 float4 float8 bool bool', + prosrc => 'in_range_float4_float8' }, +{ oid => '4141', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'numeric numeric numeric bool bool', + prosrc => 'in_range_numeric_numeric' }, + +{ oid => '361', + proname => 'lseg_distance', prorettype => 'float8', + proargtypes => 'lseg lseg', prosrc => 'lseg_distance' }, +{ oid => '362', + proname => 'lseg_interpt', prorettype => 'point', proargtypes => 'lseg lseg', + prosrc => 'lseg_interpt' }, +{ oid => '363', + proname => 'dist_ps', prorettype => 'float8', proargtypes => 'point lseg', + prosrc => 'dist_ps' }, +{ oid => '380', + proname => 'dist_sp', prorettype => 'float8', proargtypes => 'lseg point', + prosrc => 'dist_sp' }, +{ oid => '364', + proname => 'dist_pb', prorettype => 'float8', proargtypes => 'point box', + prosrc => 'dist_pb' }, +{ oid => '357', + proname => 'dist_bp', prorettype => 'float8', proargtypes => 'box point', + prosrc => 'dist_bp' }, +{ oid => '365', + proname => 'dist_sb', prorettype => 'float8', proargtypes => 'lseg box', + prosrc => 'dist_sb' }, +{ oid => '381', + proname => 'dist_bs', prorettype => 'float8', proargtypes => 'box lseg', + prosrc => 'dist_bs' }, +{ oid => '366', + proname => 'close_ps', prorettype => 'point', proargtypes => 'point lseg', + prosrc => 'close_ps' }, +{ oid => '367', + proname => 'close_pb', prorettype => 'point', proargtypes => 'point box', + prosrc => 'close_pb' }, +{ oid => '368', + proname => 'close_sb', prorettype => 'point', proargtypes => 'lseg box', + prosrc => 'close_sb' }, +{ oid => '369', + proname => 'on_ps', prorettype => 'bool', proargtypes => 'point lseg', + prosrc => 'on_ps' }, +{ oid => '370', + proname => 'path_distance', prorettype => 'float8', + proargtypes => 'path path', prosrc => 'path_distance' }, +{ oid => '371', + proname => 'dist_ppath', prorettype => 'float8', proargtypes => 'point path', + prosrc => 'dist_ppath' }, +{ oid => '421', + proname => 'dist_pathp', prorettype => 'float8', proargtypes => 'path point', + prosrc => 'dist_pathp' }, +{ oid => '372', + proname => 'on_sb', prorettype => 'bool', proargtypes => 'lseg box', + prosrc => 'on_sb' }, +{ oid => '373', + proname => 'inter_sb', prorettype => 'bool', proargtypes => 'lseg box', + prosrc => 'inter_sb' }, + +# OIDS 400 - 499 + +{ oid => '401', descr => 'convert char(n) to text', + proname => 'text', prorettype => 'text', proargtypes => 'bpchar', + prosrc => 'rtrim1' }, +{ oid => '406', descr => 'convert name to text', + proname => 'text', proleakproof => 't', prorettype => 'text', + proargtypes => 'name', prosrc => 'name_text' }, +{ oid => '407', descr => 'convert text to name', + proname => 'name', proleakproof => 't', prorettype => 'name', + proargtypes => 'text', prosrc => 'text_name' }, +{ oid => '408', descr => 'convert name to char(n)', + proname => 'bpchar', prorettype => 'bpchar', proargtypes => 'name', + prosrc => 'name_bpchar' }, +{ oid => '409', descr => 'convert char(n) to name', + proname => 'name', proleakproof => 't', prorettype => 'name', + proargtypes => 'bpchar', prosrc => 'bpchar_name' }, + +{ oid => '449', descr => 'hash', + proname => 'hashint2', prorettype => 'int4', proargtypes => 'int2', + prosrc => 'hashint2' }, +{ oid => '441', descr => 'hash', + proname => 'hashint2extended', prorettype => 'int8', + proargtypes => 'int2 int8', prosrc => 'hashint2extended' }, +{ oid => '450', descr => 'hash', + proname => 'hashint4', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'hashint4' }, +{ oid => '425', descr => 'hash', + proname => 'hashint4extended', prorettype => 'int8', + proargtypes => 'int4 int8', prosrc => 'hashint4extended' }, +{ oid => '949', descr => 'hash', + proname => 'hashint8', prorettype => 'int4', proargtypes => 'int8', + prosrc => 'hashint8' }, +{ oid => '442', descr => 'hash', + proname => 'hashint8extended', prorettype => 'int8', + proargtypes => 'int8 int8', prosrc => 'hashint8extended' }, +{ oid => '451', descr => 'hash', + proname => 'hashfloat4', prorettype => 'int4', proargtypes => 'float4', + prosrc => 'hashfloat4' }, +{ oid => '443', descr => 'hash', + proname => 'hashfloat4extended', prorettype => 'int8', + proargtypes => 'float4 int8', prosrc => 'hashfloat4extended' }, +{ oid => '452', descr => 'hash', + proname => 'hashfloat8', prorettype => 'int4', proargtypes => 'float8', + prosrc => 'hashfloat8' }, +{ oid => '444', descr => 'hash', + proname => 'hashfloat8extended', prorettype => 'int8', + proargtypes => 'float8 int8', prosrc => 'hashfloat8extended' }, +{ oid => '453', descr => 'hash', + proname => 'hashoid', prorettype => 'int4', proargtypes => 'oid', + prosrc => 'hashoid' }, +{ oid => '445', descr => 'hash', + proname => 'hashoidextended', prorettype => 'int8', proargtypes => 'oid int8', + prosrc => 'hashoidextended' }, +{ oid => '454', descr => 'hash', + proname => 'hashchar', prorettype => 'int4', proargtypes => 'char', + prosrc => 'hashchar' }, +{ oid => '446', descr => 'hash', + proname => 'hashcharextended', prorettype => 'int8', + proargtypes => 'char int8', prosrc => 'hashcharextended' }, +{ oid => '455', descr => 'hash', + proname => 'hashname', prorettype => 'int4', proargtypes => 'name', + prosrc => 'hashname' }, +{ oid => '447', descr => 'hash', + proname => 'hashnameextended', prorettype => 'int8', + proargtypes => 'name int8', prosrc => 'hashnameextended' }, +{ oid => '400', descr => 'hash', + proname => 'hashtext', prorettype => 'int4', proargtypes => 'text', + prosrc => 'hashtext' }, +{ oid => '448', descr => 'hash', + proname => 'hashtextextended', prorettype => 'int8', + proargtypes => 'text int8', prosrc => 'hashtextextended' }, +{ oid => '456', descr => 'hash', + proname => 'hashvarlena', prorettype => 'int4', proargtypes => 'internal', + prosrc => 'hashvarlena' }, +{ oid => '772', descr => 'hash', + proname => 'hashvarlenaextended', prorettype => 'int8', + proargtypes => 'internal int8', prosrc => 'hashvarlenaextended' }, +{ oid => '457', descr => 'hash', + proname => 'hashoidvector', prorettype => 'int4', proargtypes => 'oidvector', + prosrc => 'hashoidvector' }, +{ oid => '776', descr => 'hash', + proname => 'hashoidvectorextended', prorettype => 'int8', + proargtypes => 'oidvector int8', prosrc => 'hashoidvectorextended' }, +{ oid => '329', descr => 'hash', + proname => 'hash_aclitem', prorettype => 'int4', proargtypes => 'aclitem', + prosrc => 'hash_aclitem' }, +{ oid => '777', descr => 'hash', + proname => 'hash_aclitem_extended', prorettype => 'int8', + proargtypes => 'aclitem int8', prosrc => 'hash_aclitem_extended' }, +{ oid => '399', descr => 'hash', + proname => 'hashmacaddr', prorettype => 'int4', proargtypes => 'macaddr', + prosrc => 'hashmacaddr' }, +{ oid => '778', descr => 'hash', + proname => 'hashmacaddrextended', prorettype => 'int8', + proargtypes => 'macaddr int8', prosrc => 'hashmacaddrextended' }, +{ oid => '422', descr => 'hash', + proname => 'hashinet', prorettype => 'int4', proargtypes => 'inet', + prosrc => 'hashinet' }, +{ oid => '779', descr => 'hash', + proname => 'hashinetextended', prorettype => 'int8', + proargtypes => 'inet int8', prosrc => 'hashinetextended' }, +{ oid => '432', descr => 'hash', + proname => 'hash_numeric', prorettype => 'int4', proargtypes => 'numeric', + prosrc => 'hash_numeric' }, +{ oid => '780', descr => 'hash', + proname => 'hash_numeric_extended', prorettype => 'int8', + proargtypes => 'numeric int8', prosrc => 'hash_numeric_extended' }, +{ oid => '328', descr => 'hash', + proname => 'hashmacaddr8', prorettype => 'int4', proargtypes => 'macaddr8', + prosrc => 'hashmacaddr8' }, +{ oid => '781', descr => 'hash', + proname => 'hashmacaddr8extended', prorettype => 'int8', + proargtypes => 'macaddr8 int8', prosrc => 'hashmacaddr8extended' }, + +{ oid => '438', descr => 'count the number of NULL arguments', + proname => 'num_nulls', provariadic => 'any', proisstrict => 'f', + prorettype => 'int4', proargtypes => 'any', proallargtypes => '{any}', + proargmodes => '{v}', prosrc => 'pg_num_nulls' }, +{ oid => '440', descr => 'count the number of non-NULL arguments', + proname => 'num_nonnulls', provariadic => 'any', proisstrict => 'f', + prorettype => 'int4', proargtypes => 'any', proallargtypes => '{any}', + proargmodes => '{v}', prosrc => 'pg_num_nonnulls' }, + +{ oid => '458', descr => 'larger of two', + proname => 'text_larger', proleakproof => 't', prorettype => 'text', + proargtypes => 'text text', prosrc => 'text_larger' }, +{ oid => '459', descr => 'smaller of two', + proname => 'text_smaller', proleakproof => 't', prorettype => 'text', + proargtypes => 'text text', prosrc => 'text_smaller' }, + +{ oid => '460', descr => 'I/O', + proname => 'int8in', prorettype => 'int8', proargtypes => 'cstring', + prosrc => 'int8in' }, +{ oid => '461', descr => 'I/O', + proname => 'int8out', prorettype => 'cstring', proargtypes => 'int8', + prosrc => 'int8out' }, +{ oid => '462', + proname => 'int8um', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8um' }, +{ oid => '463', + proname => 'int8pl', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8pl' }, +{ oid => '464', + proname => 'int8mi', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8mi' }, +{ oid => '465', + proname => 'int8mul', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8mul' }, +{ oid => '466', + proname => 'int8div', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8div' }, +{ oid => '467', + proname => 'int8eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8eq' }, +{ oid => '468', + proname => 'int8ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8ne' }, +{ oid => '469', + proname => 'int8lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8lt' }, +{ oid => '470', + proname => 'int8gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8gt' }, +{ oid => '471', + proname => 'int8le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8le' }, +{ oid => '472', + proname => 'int8ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int8', prosrc => 'int8ge' }, + +{ oid => '474', + proname => 'int84eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84eq' }, +{ oid => '475', + proname => 'int84ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84ne' }, +{ oid => '476', + proname => 'int84lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84lt' }, +{ oid => '477', + proname => 'int84gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84gt' }, +{ oid => '478', + proname => 'int84le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84le' }, +{ oid => '479', + proname => 'int84ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int4', prosrc => 'int84ge' }, + +{ oid => '480', descr => 'convert int8 to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'int8', + prosrc => 'int84' }, +{ oid => '481', descr => 'convert int4 to int8', + proname => 'int8', proleakproof => 't', prorettype => 'int8', + proargtypes => 'int4', prosrc => 'int48' }, +{ oid => '482', descr => 'convert int8 to float8', + proname => 'float8', proleakproof => 't', prorettype => 'float8', + proargtypes => 'int8', prosrc => 'i8tod' }, +{ oid => '483', descr => 'convert float8 to int8', + proname => 'int8', prorettype => 'int8', proargtypes => 'float8', + prosrc => 'dtoi8' }, + +# OIDS 500 - 599 + +# OIDS 600 - 699 + +{ oid => '626', descr => 'hash', + proname => 'hash_array', prorettype => 'int4', proargtypes => 'anyarray', + prosrc => 'hash_array' }, +{ oid => '782', descr => 'hash', + proname => 'hash_array_extended', prorettype => 'int8', + proargtypes => 'anyarray int8', prosrc => 'hash_array_extended' }, + +{ oid => '652', descr => 'convert int8 to float4', + proname => 'float4', proleakproof => 't', prorettype => 'float4', + proargtypes => 'int8', prosrc => 'i8tof' }, +{ oid => '653', descr => 'convert float4 to int8', + proname => 'int8', prorettype => 'int8', proargtypes => 'float4', + prosrc => 'ftoi8' }, + +{ oid => '714', descr => 'convert int8 to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'int8', + prosrc => 'int82' }, +{ oid => '754', descr => 'convert int2 to int8', + proname => 'int8', proleakproof => 't', prorettype => 'int8', + proargtypes => 'int2', prosrc => 'int28' }, + +{ oid => '655', + proname => 'namelt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'namelt' }, +{ oid => '656', + proname => 'namele', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'namele' }, +{ oid => '657', + proname => 'namegt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'namegt' }, +{ oid => '658', + proname => 'namege', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'namege' }, +{ oid => '659', + proname => 'namene', proleakproof => 't', prorettype => 'bool', + proargtypes => 'name name', prosrc => 'namene' }, + +{ oid => '668', descr => 'adjust char() to typmod length', + proname => 'bpchar', prorettype => 'bpchar', + proargtypes => 'bpchar int4 bool', prosrc => 'bpchar' }, +{ oid => '3097', descr => 'planner support for varchar length coercion', + proname => 'varchar_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'varchar_support' }, +{ oid => '669', descr => 'adjust varchar() to typmod length', + proname => 'varchar', prosupport => 'varchar_support', + prorettype => 'varchar', proargtypes => 'varchar int4 bool', + prosrc => 'varchar' }, + +{ oid => '619', + proname => 'oidvectorne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectorne' }, +{ oid => '677', + proname => 'oidvectorlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectorlt' }, +{ oid => '678', + proname => 'oidvectorle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectorle' }, +{ oid => '679', + proname => 'oidvectoreq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectoreq' }, +{ oid => '680', + proname => 'oidvectorge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectorge' }, +{ oid => '681', + proname => 'oidvectorgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oidvector oidvector', prosrc => 'oidvectorgt' }, + +# OIDS 700 - 799 +{ oid => '710', descr => 'deprecated, use current_user instead', + proname => 'getpgusername', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'current_user' }, +{ oid => '716', + proname => 'oidlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oidlt' }, +{ oid => '717', + proname => 'oidle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oidle' }, + +{ oid => '720', descr => 'octet length', + proname => 'octet_length', prorettype => 'int4', proargtypes => 'bytea', + prosrc => 'byteaoctetlen' }, +{ oid => '721', descr => 'get byte', + proname => 'get_byte', prorettype => 'int4', proargtypes => 'bytea int4', + prosrc => 'byteaGetByte' }, +{ oid => '722', descr => 'set byte', + proname => 'set_byte', prorettype => 'bytea', + proargtypes => 'bytea int4 int4', prosrc => 'byteaSetByte' }, +{ oid => '723', descr => 'get bit', + proname => 'get_bit', prorettype => 'int4', proargtypes => 'bytea int8', + prosrc => 'byteaGetBit' }, +{ oid => '724', descr => 'set bit', + proname => 'set_bit', prorettype => 'bytea', proargtypes => 'bytea int8 int4', + prosrc => 'byteaSetBit' }, +{ oid => '749', descr => 'substitute portion of string', + proname => 'overlay', prorettype => 'bytea', + proargtypes => 'bytea bytea int4 int4', prosrc => 'byteaoverlay' }, +{ oid => '752', descr => 'substitute portion of string', + proname => 'overlay', prorettype => 'bytea', + proargtypes => 'bytea bytea int4', prosrc => 'byteaoverlay_no_len' }, +{ oid => '6163', descr => 'number of set bits', + proname => 'bit_count', prorettype => 'int8', proargtypes => 'bytea', + prosrc => 'bytea_bit_count' }, + +{ oid => '725', + proname => 'dist_pl', prorettype => 'float8', proargtypes => 'point line', + prosrc => 'dist_pl' }, +{ oid => '702', + proname => 'dist_lp', prorettype => 'float8', proargtypes => 'line point', + prosrc => 'dist_lp' }, +{ oid => '727', + proname => 'dist_sl', prorettype => 'float8', proargtypes => 'lseg line', + prosrc => 'dist_sl' }, +{ oid => '704', + proname => 'dist_ls', prorettype => 'float8', proargtypes => 'line lseg', + prosrc => 'dist_ls' }, + +{ oid => '728', + proname => 'dist_cpoly', prorettype => 'float8', + proargtypes => 'circle polygon', prosrc => 'dist_cpoly' }, +{ oid => '785', + proname => 'dist_polyc', prorettype => 'float8', + proargtypes => 'polygon circle', prosrc => 'dist_polyc' }, +{ oid => '729', + proname => 'poly_distance', prorettype => 'float8', + proargtypes => 'polygon polygon', prosrc => 'poly_distance' }, +{ oid => '3275', + proname => 'dist_ppoly', prorettype => 'float8', + proargtypes => 'point polygon', prosrc => 'dist_ppoly' }, +{ oid => '3292', + proname => 'dist_polyp', prorettype => 'float8', + proargtypes => 'polygon point', prosrc => 'dist_polyp' }, +{ oid => '3290', + proname => 'dist_cpoint', prorettype => 'float8', + proargtypes => 'circle point', prosrc => 'dist_cpoint' }, + +{ oid => '740', + proname => 'text_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_lt' }, +{ oid => '741', + proname => 'text_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_le' }, +{ oid => '742', + proname => 'text_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_gt' }, +{ oid => '743', + proname => 'text_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_ge' }, + +{ oid => '745', descr => 'current user name', + proname => 'current_user', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'current_user' }, +{ oid => '746', descr => 'session user name', + proname => 'session_user', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'session_user' }, + +{ oid => '744', + proname => 'array_eq', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_eq' }, +{ oid => '390', + proname => 'array_ne', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_ne' }, +{ oid => '391', + proname => 'array_lt', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_lt' }, +{ oid => '392', + proname => 'array_gt', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_gt' }, +{ oid => '393', + proname => 'array_le', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_le' }, +{ oid => '396', + proname => 'array_ge', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'array_ge' }, +{ oid => '747', descr => 'array dimensions', + proname => 'array_dims', prorettype => 'text', proargtypes => 'anyarray', + prosrc => 'array_dims' }, +{ oid => '748', descr => 'number of array dimensions', + proname => 'array_ndims', prorettype => 'int4', proargtypes => 'anyarray', + prosrc => 'array_ndims' }, +{ oid => '750', descr => 'I/O', + proname => 'array_in', provolatile => 's', prorettype => 'anyarray', + proargtypes => 'cstring oid int4', prosrc => 'array_in' }, +{ oid => '751', descr => 'I/O', + proname => 'array_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyarray', prosrc => 'array_out' }, +{ oid => '2091', descr => 'array lower dimension', + proname => 'array_lower', prorettype => 'int4', + proargtypes => 'anyarray int4', prosrc => 'array_lower' }, +{ oid => '2092', descr => 'array upper dimension', + proname => 'array_upper', prorettype => 'int4', + proargtypes => 'anyarray int4', prosrc => 'array_upper' }, +{ oid => '2176', descr => 'array length', + proname => 'array_length', prorettype => 'int4', + proargtypes => 'anyarray int4', prosrc => 'array_length' }, +{ oid => '3179', descr => 'array cardinality', + proname => 'cardinality', prorettype => 'int4', proargtypes => 'anyarray', + prosrc => 'array_cardinality' }, +{ oid => '378', descr => 'append element onto end of array', + proname => 'array_append', proisstrict => 'f', + prorettype => 'anycompatiblearray', + proargtypes => 'anycompatiblearray anycompatible', prosrc => 'array_append' }, +{ oid => '379', descr => 'prepend element onto front of array', + proname => 'array_prepend', proisstrict => 'f', + prorettype => 'anycompatiblearray', + proargtypes => 'anycompatible anycompatiblearray', + prosrc => 'array_prepend' }, +{ oid => '383', + proname => 'array_cat', proisstrict => 'f', + prorettype => 'anycompatiblearray', + proargtypes => 'anycompatiblearray anycompatiblearray', + prosrc => 'array_cat' }, +{ oid => '394', descr => 'split delimited text', + proname => 'string_to_array', proisstrict => 'f', prorettype => '_text', + proargtypes => 'text text', prosrc => 'text_to_array' }, +{ oid => '376', descr => 'split delimited text, with null string', + proname => 'string_to_array', proisstrict => 'f', prorettype => '_text', + proargtypes => 'text text text', prosrc => 'text_to_array_null' }, +{ oid => '6160', descr => 'split delimited text', + proname => 'string_to_table', prorows => '1000', proisstrict => 'f', + proretset => 't', prorettype => 'text', proargtypes => 'text text', + prosrc => 'text_to_table' }, +{ oid => '6161', descr => 'split delimited text, with null string', + proname => 'string_to_table', prorows => '1000', proisstrict => 'f', + proretset => 't', prorettype => 'text', proargtypes => 'text text text', + prosrc => 'text_to_table_null' }, +{ oid => '395', + descr => 'concatenate array elements, using delimiter, into text', + proname => 'array_to_string', provolatile => 's', prorettype => 'text', + proargtypes => 'anyarray text', prosrc => 'array_to_text' }, +{ oid => '384', + descr => 'concatenate array elements, using delimiter and null string, into text', + proname => 'array_to_string', proisstrict => 'f', provolatile => 's', + prorettype => 'text', proargtypes => 'anyarray text text', + prosrc => 'array_to_text_null' }, +{ oid => '515', descr => 'larger of two', + proname => 'array_larger', prorettype => 'anyarray', + proargtypes => 'anyarray anyarray', prosrc => 'array_larger' }, +{ oid => '516', descr => 'smaller of two', + proname => 'array_smaller', prorettype => 'anyarray', + proargtypes => 'anyarray anyarray', prosrc => 'array_smaller' }, +{ oid => '3277', descr => 'returns an offset of value in array', + proname => 'array_position', proisstrict => 'f', prorettype => 'int4', + proargtypes => 'anycompatiblearray anycompatible', + prosrc => 'array_position' }, +{ oid => '3278', + descr => 'returns an offset of value in array with start index', + proname => 'array_position', proisstrict => 'f', prorettype => 'int4', + proargtypes => 'anycompatiblearray anycompatible int4', + prosrc => 'array_position_start' }, +{ oid => '3279', + descr => 'returns an array of offsets of some value in array', + proname => 'array_positions', proisstrict => 'f', prorettype => '_int4', + proargtypes => 'anycompatiblearray anycompatible', + prosrc => 'array_positions' }, +{ oid => '1191', descr => 'array subscripts generator', + proname => 'generate_subscripts', prorows => '1000', proretset => 't', + prorettype => 'int4', proargtypes => 'anyarray int4 bool', + prosrc => 'generate_subscripts' }, +{ oid => '1192', descr => 'array subscripts generator', + proname => 'generate_subscripts', prorows => '1000', proretset => 't', + prorettype => 'int4', proargtypes => 'anyarray int4', + prosrc => 'generate_subscripts_nodir' }, +{ oid => '1193', descr => 'array constructor with value', + proname => 'array_fill', proisstrict => 'f', prorettype => 'anyarray', + proargtypes => 'anyelement _int4', prosrc => 'array_fill' }, +{ oid => '1286', descr => 'array constructor with value', + proname => 'array_fill', proisstrict => 'f', prorettype => 'anyarray', + proargtypes => 'anyelement _int4 _int4', + prosrc => 'array_fill_with_lower_bounds' }, +{ oid => '2331', descr => 'expand array to set of rows', + proname => 'unnest', prorows => '100', prosupport => 'array_unnest_support', + proretset => 't', prorettype => 'anyelement', proargtypes => 'anyarray', + prosrc => 'array_unnest' }, +{ oid => '3996', descr => 'planner support for array_unnest', + proname => 'array_unnest_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'array_unnest_support' }, +{ oid => '3167', + descr => 'remove any occurrences of an element from an array', + proname => 'array_remove', proisstrict => 'f', + prorettype => 'anycompatiblearray', + proargtypes => 'anycompatiblearray anycompatible', prosrc => 'array_remove' }, +{ oid => '3168', descr => 'replace any occurrences of an element in an array', + proname => 'array_replace', proisstrict => 'f', + prorettype => 'anycompatiblearray', + proargtypes => 'anycompatiblearray anycompatible anycompatible', + prosrc => 'array_replace' }, +{ oid => '2333', descr => 'aggregate transition function', + proname => 'array_agg_transfn', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal anynonarray', prosrc => 'array_agg_transfn' }, +{ oid => '2334', descr => 'aggregate final function', + proname => 'array_agg_finalfn', proisstrict => 'f', prorettype => 'anyarray', + proargtypes => 'internal anynonarray', prosrc => 'array_agg_finalfn' }, +{ oid => '2335', descr => 'concatenate aggregate input into an array', + proname => 'array_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'anynonarray', + prosrc => 'aggregate_dummy' }, +{ oid => '4051', descr => 'aggregate transition function', + proname => 'array_agg_array_transfn', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal anyarray', + prosrc => 'array_agg_array_transfn' }, +{ oid => '4052', descr => 'aggregate final function', + proname => 'array_agg_array_finalfn', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'internal anyarray', + prosrc => 'array_agg_array_finalfn' }, +{ oid => '4053', descr => 'concatenate aggregate input into an array', + proname => 'array_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'anyarray', + prosrc => 'aggregate_dummy' }, +{ oid => '3218', + descr => 'bucket number of operand given a sorted array of bucket lower bounds', + proname => 'width_bucket', prorettype => 'int4', + proargtypes => 'anycompatible anycompatiblearray', + prosrc => 'width_bucket_array' }, +{ oid => '6172', descr => 'remove last N elements of array', + proname => 'trim_array', prorettype => 'anyarray', + proargtypes => 'anyarray int4', prosrc => 'trim_array' }, +{ oid => '3816', descr => 'array typanalyze', + proname => 'array_typanalyze', provolatile => 's', prorettype => 'bool', + proargtypes => 'internal', prosrc => 'array_typanalyze' }, +{ oid => '3817', + descr => 'restriction selectivity for array-containment operators', + proname => 'arraycontsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'arraycontsel' }, +{ oid => '3818', descr => 'join selectivity for array-containment operators', + proname => 'arraycontjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'arraycontjoinsel' }, + +{ oid => '764', descr => 'large object import', + proname => 'lo_import', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'text', prosrc => 'be_lo_import' }, +{ oid => '767', descr => 'large object import', + proname => 'lo_import', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'text oid', + prosrc => 'be_lo_import_with_oid' }, +{ oid => '765', descr => 'large object export', + proname => 'lo_export', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'oid text', prosrc => 'be_lo_export' }, + +{ oid => '766', descr => 'increment', + proname => 'int4inc', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4inc' }, +{ oid => '768', descr => 'larger of two', + proname => 'int4larger', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4larger' }, +{ oid => '769', descr => 'smaller of two', + proname => 'int4smaller', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4smaller' }, +{ oid => '770', descr => 'larger of two', + proname => 'int2larger', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2larger' }, +{ oid => '771', descr => 'smaller of two', + proname => 'int2smaller', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2smaller' }, + +# OIDS 800 - 899 + +{ oid => '846', + proname => 'cash_mul_flt4', prorettype => 'money', + proargtypes => 'money float4', prosrc => 'cash_mul_flt4' }, +{ oid => '847', + proname => 'cash_div_flt4', prorettype => 'money', + proargtypes => 'money float4', prosrc => 'cash_div_flt4' }, +{ oid => '848', + proname => 'flt4_mul_cash', prorettype => 'money', + proargtypes => 'float4 money', prosrc => 'flt4_mul_cash' }, + +{ oid => '849', descr => 'position of substring', + proname => 'position', prorettype => 'int4', proargtypes => 'text text', + prosrc => 'textpos' }, +{ oid => '850', + proname => 'textlike', prosupport => 'textlike_support', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'textlike' }, +{ oid => '1023', descr => 'planner support for textlike', + proname => 'textlike_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'textlike_support' }, +{ oid => '851', + proname => 'textnlike', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'textnlike' }, + +{ oid => '852', + proname => 'int48eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48eq' }, +{ oid => '853', + proname => 'int48ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48ne' }, +{ oid => '854', + proname => 'int48lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48lt' }, +{ oid => '855', + proname => 'int48gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48gt' }, +{ oid => '856', + proname => 'int48le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48le' }, +{ oid => '857', + proname => 'int48ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4 int8', prosrc => 'int48ge' }, + +{ oid => '858', + proname => 'namelike', prosupport => 'textlike_support', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namelike' }, +{ oid => '859', + proname => 'namenlike', prorettype => 'bool', proargtypes => 'name text', + prosrc => 'namenlike' }, + +{ oid => '860', descr => 'convert char to char(n)', + proname => 'bpchar', prorettype => 'bpchar', proargtypes => 'char', + prosrc => 'char_bpchar' }, + +{ oid => '861', descr => 'name of the current database', + proname => 'current_database', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'current_database' }, +{ oid => '817', descr => 'get the currently executing query', + proname => 'current_query', proisstrict => 'f', provolatile => 'v', + proparallel => 'r', prorettype => 'text', proargtypes => '', + prosrc => 'current_query' }, + +{ oid => '3399', + proname => 'int8_mul_cash', prorettype => 'money', + proargtypes => 'int8 money', prosrc => 'int8_mul_cash' }, +{ oid => '862', + proname => 'int4_mul_cash', prorettype => 'money', + proargtypes => 'int4 money', prosrc => 'int4_mul_cash' }, +{ oid => '863', + proname => 'int2_mul_cash', prorettype => 'money', + proargtypes => 'int2 money', prosrc => 'int2_mul_cash' }, +{ oid => '3344', + proname => 'cash_mul_int8', prorettype => 'money', + proargtypes => 'money int8', prosrc => 'cash_mul_int8' }, +{ oid => '3345', + proname => 'cash_div_int8', prorettype => 'money', + proargtypes => 'money int8', prosrc => 'cash_div_int8' }, +{ oid => '864', + proname => 'cash_mul_int4', prorettype => 'money', + proargtypes => 'money int4', prosrc => 'cash_mul_int4' }, +{ oid => '865', + proname => 'cash_div_int4', prorettype => 'money', + proargtypes => 'money int4', prosrc => 'cash_div_int4' }, +{ oid => '866', + proname => 'cash_mul_int2', prorettype => 'money', + proargtypes => 'money int2', prosrc => 'cash_mul_int2' }, +{ oid => '867', + proname => 'cash_div_int2', prorettype => 'money', + proargtypes => 'money int2', prosrc => 'cash_div_int2' }, + +{ oid => '886', descr => 'I/O', + proname => 'cash_in', provolatile => 's', prorettype => 'money', + proargtypes => 'cstring', prosrc => 'cash_in' }, +{ oid => '887', descr => 'I/O', + proname => 'cash_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'money', prosrc => 'cash_out' }, +{ oid => '888', + proname => 'cash_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_eq' }, +{ oid => '889', + proname => 'cash_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_ne' }, +{ oid => '890', + proname => 'cash_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_lt' }, +{ oid => '891', + proname => 'cash_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_le' }, +{ oid => '892', + proname => 'cash_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_gt' }, +{ oid => '893', + proname => 'cash_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'money money', prosrc => 'cash_ge' }, +{ oid => '894', + proname => 'cash_pl', prorettype => 'money', proargtypes => 'money money', + prosrc => 'cash_pl' }, +{ oid => '895', + proname => 'cash_mi', prorettype => 'money', proargtypes => 'money money', + prosrc => 'cash_mi' }, +{ oid => '896', + proname => 'cash_mul_flt8', prorettype => 'money', + proargtypes => 'money float8', prosrc => 'cash_mul_flt8' }, +{ oid => '897', + proname => 'cash_div_flt8', prorettype => 'money', + proargtypes => 'money float8', prosrc => 'cash_div_flt8' }, +{ oid => '898', descr => 'larger of two', + proname => 'cashlarger', prorettype => 'money', proargtypes => 'money money', + prosrc => 'cashlarger' }, +{ oid => '899', descr => 'smaller of two', + proname => 'cashsmaller', prorettype => 'money', proargtypes => 'money money', + prosrc => 'cashsmaller' }, +{ oid => '919', + proname => 'flt8_mul_cash', prorettype => 'money', + proargtypes => 'float8 money', prosrc => 'flt8_mul_cash' }, +{ oid => '935', descr => 'output money amount as words', + proname => 'cash_words', prorettype => 'text', proargtypes => 'money', + prosrc => 'cash_words' }, +{ oid => '3822', + proname => 'cash_div_cash', prorettype => 'float8', + proargtypes => 'money money', prosrc => 'cash_div_cash' }, +{ oid => '3823', descr => 'convert money to numeric', + proname => 'numeric', provolatile => 's', prorettype => 'numeric', + proargtypes => 'money', prosrc => 'cash_numeric' }, +{ oid => '3824', descr => 'convert numeric to money', + proname => 'money', provolatile => 's', prorettype => 'money', + proargtypes => 'numeric', prosrc => 'numeric_cash' }, +{ oid => '3811', descr => 'convert int4 to money', + proname => 'money', provolatile => 's', prorettype => 'money', + proargtypes => 'int4', prosrc => 'int4_cash' }, +{ oid => '3812', descr => 'convert int8 to money', + proname => 'money', provolatile => 's', prorettype => 'money', + proargtypes => 'int8', prosrc => 'int8_cash' }, + +# OIDS 900 - 999 + +{ oid => '940', descr => 'modulus', + proname => 'mod', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2mod' }, +{ oid => '941', descr => 'modulus', + proname => 'mod', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4mod' }, + +{ oid => '945', + proname => 'int8mod', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8mod' }, +{ oid => '947', descr => 'modulus', + proname => 'mod', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8mod' }, + +{ oid => '5044', descr => 'greatest common divisor', + proname => 'gcd', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4gcd' }, +{ oid => '5045', descr => 'greatest common divisor', + proname => 'gcd', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8gcd' }, + +{ oid => '5046', descr => 'least common multiple', + proname => 'lcm', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4lcm' }, +{ oid => '5047', descr => 'least common multiple', + proname => 'lcm', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8lcm' }, + +{ oid => '944', descr => 'convert text to char', + proname => 'char', prorettype => 'char', proargtypes => 'text', + prosrc => 'text_char' }, +{ oid => '946', descr => 'convert char to text', + proname => 'text', prorettype => 'text', proargtypes => 'char', + prosrc => 'char_text' }, + +{ oid => '952', descr => 'large object open', + proname => 'lo_open', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'oid int4', prosrc => 'be_lo_open' }, +{ oid => '953', descr => 'large object close', + proname => 'lo_close', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4', prosrc => 'be_lo_close' }, +{ oid => '954', descr => 'large object read', + proname => 'loread', provolatile => 'v', proparallel => 'u', + prorettype => 'bytea', proargtypes => 'int4 int4', prosrc => 'be_loread' }, +{ oid => '955', descr => 'large object write', + proname => 'lowrite', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4 bytea', prosrc => 'be_lowrite' }, +{ oid => '956', descr => 'large object seek', + proname => 'lo_lseek', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4 int4 int4', + prosrc => 'be_lo_lseek' }, +{ oid => '3170', descr => 'large object seek (64 bit)', + proname => 'lo_lseek64', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'int4 int8 int4', + prosrc => 'be_lo_lseek64' }, +{ oid => '957', descr => 'large object create', + proname => 'lo_creat', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'int4', prosrc => 'be_lo_creat' }, +{ oid => '715', descr => 'large object create', + proname => 'lo_create', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'oid', prosrc => 'be_lo_create' }, +{ oid => '958', descr => 'large object position', + proname => 'lo_tell', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4', prosrc => 'be_lo_tell' }, +{ oid => '3171', descr => 'large object position (64 bit)', + proname => 'lo_tell64', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'int4', prosrc => 'be_lo_tell64' }, +{ oid => '1004', descr => 'truncate large object', + proname => 'lo_truncate', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'be_lo_truncate' }, +{ oid => '3172', descr => 'truncate large object (64 bit)', + proname => 'lo_truncate64', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'int4 int8', + prosrc => 'be_lo_truncate64' }, + +{ oid => '3457', descr => 'create new large object with given content', + proname => 'lo_from_bytea', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'oid bytea', + prosrc => 'be_lo_from_bytea' }, +{ oid => '3458', descr => 'read entire large object', + proname => 'lo_get', provolatile => 'v', proparallel => 'u', + prorettype => 'bytea', proargtypes => 'oid', prosrc => 'be_lo_get' }, +{ oid => '3459', descr => 'read large object from offset for length', + proname => 'lo_get', provolatile => 'v', proparallel => 'u', + prorettype => 'bytea', proargtypes => 'oid int8 int4', + prosrc => 'be_lo_get_fragment' }, +{ oid => '3460', descr => 'write data at offset', + proname => 'lo_put', provolatile => 'v', proparallel => 'u', + prorettype => 'void', proargtypes => 'oid int8 bytea', + prosrc => 'be_lo_put' }, + +{ oid => '959', + proname => 'on_pl', prorettype => 'bool', proargtypes => 'point line', + prosrc => 'on_pl' }, +{ oid => '960', + proname => 'on_sl', prorettype => 'bool', proargtypes => 'lseg line', + prosrc => 'on_sl' }, +{ oid => '961', + proname => 'close_pl', prorettype => 'point', proargtypes => 'point line', + prosrc => 'close_pl' }, + +{ oid => '964', descr => 'large object unlink (delete)', + proname => 'lo_unlink', provolatile => 'v', proparallel => 'u', + prorettype => 'int4', proargtypes => 'oid', prosrc => 'be_lo_unlink' }, + +{ oid => '973', + proname => 'path_inter', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_inter' }, +{ oid => '975', descr => 'box area', + proname => 'area', prorettype => 'float8', proargtypes => 'box', + prosrc => 'box_area' }, +{ oid => '976', descr => 'box width', + proname => 'width', prorettype => 'float8', proargtypes => 'box', + prosrc => 'box_width' }, +{ oid => '977', descr => 'box height', + proname => 'height', prorettype => 'float8', proargtypes => 'box', + prosrc => 'box_height' }, +{ oid => '978', + proname => 'box_distance', prorettype => 'float8', proargtypes => 'box box', + prosrc => 'box_distance' }, +{ oid => '979', descr => 'area of a closed path', + proname => 'area', prorettype => 'float8', proargtypes => 'path', + prosrc => 'path_area' }, +{ oid => '980', + proname => 'box_intersect', prorettype => 'box', proargtypes => 'box box', + prosrc => 'box_intersect' }, +{ oid => '4067', descr => 'bounding box of two boxes', + proname => 'bound_box', prorettype => 'box', proargtypes => 'box box', + prosrc => 'boxes_bound_box' }, +{ oid => '981', descr => 'box diagonal', + proname => 'diagonal', prorettype => 'lseg', proargtypes => 'box', + prosrc => 'box_diagonal' }, +{ oid => '982', + proname => 'path_n_lt', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_n_lt' }, +{ oid => '983', + proname => 'path_n_gt', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_n_gt' }, +{ oid => '984', + proname => 'path_n_eq', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_n_eq' }, +{ oid => '985', + proname => 'path_n_le', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_n_le' }, +{ oid => '986', + proname => 'path_n_ge', prorettype => 'bool', proargtypes => 'path path', + prosrc => 'path_n_ge' }, +{ oid => '987', + proname => 'path_length', prorettype => 'float8', proargtypes => 'path', + prosrc => 'path_length' }, +{ oid => '988', + proname => 'point_ne', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_ne' }, +{ oid => '989', + proname => 'point_vert', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_vert' }, +{ oid => '990', + proname => 'point_horiz', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_horiz' }, +{ oid => '991', + proname => 'point_distance', prorettype => 'float8', + proargtypes => 'point point', prosrc => 'point_distance' }, +{ oid => '992', descr => 'slope between points', + proname => 'slope', prorettype => 'float8', proargtypes => 'point point', + prosrc => 'point_slope' }, +{ oid => '993', descr => 'convert points to line segment', + proname => 'lseg', prorettype => 'lseg', proargtypes => 'point point', + prosrc => 'lseg_construct' }, +{ oid => '994', + proname => 'lseg_intersect', prorettype => 'bool', proargtypes => 'lseg lseg', + prosrc => 'lseg_intersect' }, +{ oid => '995', + proname => 'lseg_parallel', prorettype => 'bool', proargtypes => 'lseg lseg', + prosrc => 'lseg_parallel' }, +{ oid => '996', + proname => 'lseg_perp', prorettype => 'bool', proargtypes => 'lseg lseg', + prosrc => 'lseg_perp' }, +{ oid => '997', + proname => 'lseg_vertical', prorettype => 'bool', proargtypes => 'lseg', + prosrc => 'lseg_vertical' }, +{ oid => '998', + proname => 'lseg_horizontal', prorettype => 'bool', proargtypes => 'lseg', + prosrc => 'lseg_horizontal' }, +{ oid => '999', + proname => 'lseg_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_eq' }, + +# OIDS 1000 - 1999 + +{ oid => '1026', descr => 'adjust timestamp to new time zone', + proname => 'timezone', prorettype => 'timestamp', + proargtypes => 'interval timestamptz', prosrc => 'timestamptz_izone' }, + +{ oid => '1031', descr => 'I/O', + proname => 'aclitemin', provolatile => 's', prorettype => 'aclitem', + proargtypes => 'cstring', prosrc => 'aclitemin' }, +{ oid => '1032', descr => 'I/O', + proname => 'aclitemout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'aclitem', prosrc => 'aclitemout' }, +{ oid => '1035', descr => 'add/update ACL item', + proname => 'aclinsert', prorettype => '_aclitem', + proargtypes => '_aclitem aclitem', prosrc => 'aclinsert' }, +{ oid => '1036', descr => 'remove ACL item', + proname => 'aclremove', prorettype => '_aclitem', + proargtypes => '_aclitem aclitem', prosrc => 'aclremove' }, +{ oid => '1037', descr => 'contains', + proname => 'aclcontains', prorettype => 'bool', + proargtypes => '_aclitem aclitem', prosrc => 'aclcontains' }, +{ oid => '1062', + proname => 'aclitemeq', prorettype => 'bool', + proargtypes => 'aclitem aclitem', prosrc => 'aclitem_eq' }, +{ oid => '1365', descr => 'make ACL item', + proname => 'makeaclitem', prorettype => 'aclitem', + proargtypes => 'oid oid text bool', prosrc => 'makeaclitem' }, +{ oid => '3943', + descr => 'show hardwired default privileges, primarily for use by the information schema', + proname => 'acldefault', prorettype => '_aclitem', proargtypes => 'char oid', + prosrc => 'acldefault_sql' }, +{ oid => '1689', + descr => 'convert ACL item array to table, primarily for use by information schema', + proname => 'aclexplode', prorows => '10', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => '_aclitem', + proallargtypes => '{_aclitem,oid,oid,text,bool}', + proargmodes => '{i,o,o,o,o}', + proargnames => '{acl,grantor,grantee,privilege_type,is_grantable}', + prosrc => 'aclexplode' }, +{ oid => '1044', descr => 'I/O', + proname => 'bpcharin', prorettype => 'bpchar', + proargtypes => 'cstring oid int4', prosrc => 'bpcharin' }, +{ oid => '1045', descr => 'I/O', + proname => 'bpcharout', prorettype => 'cstring', proargtypes => 'bpchar', + prosrc => 'bpcharout' }, +{ oid => '2913', descr => 'I/O typmod', + proname => 'bpchartypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'bpchartypmodin' }, +{ oid => '2914', descr => 'I/O typmod', + proname => 'bpchartypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'bpchartypmodout' }, +{ oid => '1046', descr => 'I/O', + proname => 'varcharin', prorettype => 'varchar', + proargtypes => 'cstring oid int4', prosrc => 'varcharin' }, +{ oid => '1047', descr => 'I/O', + proname => 'varcharout', prorettype => 'cstring', proargtypes => 'varchar', + prosrc => 'varcharout' }, +{ oid => '2915', descr => 'I/O typmod', + proname => 'varchartypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'varchartypmodin' }, +{ oid => '2916', descr => 'I/O typmod', + proname => 'varchartypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'varchartypmodout' }, +{ oid => '1048', + proname => 'bpchareq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchareq' }, +{ oid => '1049', + proname => 'bpcharlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpcharlt' }, +{ oid => '1050', + proname => 'bpcharle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpcharle' }, +{ oid => '1051', + proname => 'bpchargt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchargt' }, +{ oid => '1052', + proname => 'bpcharge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpcharge' }, +{ oid => '1053', + proname => 'bpcharne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpcharne' }, +{ oid => '1063', descr => 'larger of two', + proname => 'bpchar_larger', proleakproof => 't', prorettype => 'bpchar', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_larger' }, +{ oid => '1064', descr => 'smaller of two', + proname => 'bpchar_smaller', proleakproof => 't', prorettype => 'bpchar', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_smaller' }, +{ oid => '1078', descr => 'less-equal-greater', + proname => 'bpcharcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bpchar bpchar', prosrc => 'bpcharcmp' }, +{ oid => '3328', descr => 'sort support', + proname => 'bpchar_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'bpchar_sortsupport' }, +{ oid => '1080', descr => 'hash', + proname => 'hashbpchar', prorettype => 'int4', proargtypes => 'bpchar', + prosrc => 'hashbpchar' }, +{ oid => '972', descr => 'hash', + proname => 'hashbpcharextended', prorettype => 'int8', + proargtypes => 'bpchar int8', prosrc => 'hashbpcharextended' }, +{ oid => '1081', descr => 'format a type oid and atttypmod to canonical SQL', + proname => 'format_type', proisstrict => 'f', provolatile => 's', + prorettype => 'text', proargtypes => 'oid int4', prosrc => 'format_type' }, +{ oid => '1084', descr => 'I/O', + proname => 'date_in', provolatile => 's', prorettype => 'date', + proargtypes => 'cstring', prosrc => 'date_in' }, +{ oid => '1085', descr => 'I/O', + proname => 'date_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'date', prosrc => 'date_out' }, +{ oid => '1086', + proname => 'date_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_eq' }, +{ oid => '1087', + proname => 'date_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_lt' }, +{ oid => '1088', + proname => 'date_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_le' }, +{ oid => '1089', + proname => 'date_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_gt' }, +{ oid => '1090', + proname => 'date_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_ge' }, +{ oid => '1091', + proname => 'date_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'date date', prosrc => 'date_ne' }, +{ oid => '1092', descr => 'less-equal-greater', + proname => 'date_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'date date', prosrc => 'date_cmp' }, +{ oid => '3136', descr => 'sort support', + proname => 'date_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'date_sortsupport' }, +{ oid => '4133', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'date date interval bool bool', + prosrc => 'in_range_date_interval' }, + +# OIDS 1100 - 1199 + +{ oid => '1102', + proname => 'time_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_lt' }, +{ oid => '1103', + proname => 'time_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_le' }, +{ oid => '1104', + proname => 'time_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_gt' }, +{ oid => '1105', + proname => 'time_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_ge' }, +{ oid => '1106', + proname => 'time_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_ne' }, +{ oid => '1107', descr => 'less-equal-greater', + proname => 'time_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'time time', prosrc => 'time_cmp' }, +{ oid => '1138', descr => 'larger of two', + proname => 'date_larger', prorettype => 'date', proargtypes => 'date date', + prosrc => 'date_larger' }, +{ oid => '1139', descr => 'smaller of two', + proname => 'date_smaller', prorettype => 'date', proargtypes => 'date date', + prosrc => 'date_smaller' }, +{ oid => '1140', + proname => 'date_mi', prorettype => 'int4', proargtypes => 'date date', + prosrc => 'date_mi' }, +{ oid => '1141', + proname => 'date_pli', prorettype => 'date', proargtypes => 'date int4', + prosrc => 'date_pli' }, +{ oid => '1142', + proname => 'date_mii', prorettype => 'date', proargtypes => 'date int4', + prosrc => 'date_mii' }, +{ oid => '1143', descr => 'I/O', + proname => 'time_in', provolatile => 's', prorettype => 'time', + proargtypes => 'cstring oid int4', prosrc => 'time_in' }, +{ oid => '1144', descr => 'I/O', + proname => 'time_out', prorettype => 'cstring', proargtypes => 'time', + prosrc => 'time_out' }, +{ oid => '2909', descr => 'I/O typmod', + proname => 'timetypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'timetypmodin' }, +{ oid => '2910', descr => 'I/O typmod', + proname => 'timetypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'timetypmodout' }, +{ oid => '1145', + proname => 'time_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'time time', prosrc => 'time_eq' }, + +{ oid => '1146', + proname => 'circle_add_pt', prorettype => 'circle', + proargtypes => 'circle point', prosrc => 'circle_add_pt' }, +{ oid => '1147', + proname => 'circle_sub_pt', prorettype => 'circle', + proargtypes => 'circle point', prosrc => 'circle_sub_pt' }, +{ oid => '1148', + proname => 'circle_mul_pt', prorettype => 'circle', + proargtypes => 'circle point', prosrc => 'circle_mul_pt' }, +{ oid => '1149', + proname => 'circle_div_pt', prorettype => 'circle', + proargtypes => 'circle point', prosrc => 'circle_div_pt' }, + +{ oid => '1150', descr => 'I/O', + proname => 'timestamptz_in', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'cstring oid int4', prosrc => 'timestamptz_in' }, +{ oid => '1151', descr => 'I/O', + proname => 'timestamptz_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'timestamptz', prosrc => 'timestamptz_out' }, +{ oid => '2907', descr => 'I/O typmod', + proname => 'timestamptztypmodin', prorettype => 'int4', + proargtypes => '_cstring', prosrc => 'timestamptztypmodin' }, +{ oid => '2908', descr => 'I/O typmod', + proname => 'timestamptztypmodout', prorettype => 'cstring', + proargtypes => 'int4', prosrc => 'timestamptztypmodout' }, +{ oid => '1152', + proname => 'timestamptz_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_eq' }, +{ oid => '1153', + proname => 'timestamptz_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_ne' }, +{ oid => '1154', + proname => 'timestamptz_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_lt' }, +{ oid => '1155', + proname => 'timestamptz_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_le' }, +{ oid => '1156', + proname => 'timestamptz_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_ge' }, +{ oid => '1157', + proname => 'timestamptz_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_gt' }, +{ oid => '1158', descr => 'convert UNIX epoch to timestamptz', + proname => 'to_timestamp', prorettype => 'timestamptz', + proargtypes => 'float8', prosrc => 'float8_timestamptz' }, +{ oid => '1159', descr => 'adjust timestamp to new time zone', + proname => 'timezone', prorettype => 'timestamp', + proargtypes => 'text timestamptz', prosrc => 'timestamptz_zone' }, + +{ oid => '1160', descr => 'I/O', + proname => 'interval_in', provolatile => 's', prorettype => 'interval', + proargtypes => 'cstring oid int4', prosrc => 'interval_in' }, +{ oid => '1161', descr => 'I/O', + proname => 'interval_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'interval', prosrc => 'interval_out' }, +{ oid => '2903', descr => 'I/O typmod', + proname => 'intervaltypmodin', prorettype => 'int4', + proargtypes => '_cstring', prosrc => 'intervaltypmodin' }, +{ oid => '2904', descr => 'I/O typmod', + proname => 'intervaltypmodout', prorettype => 'cstring', + proargtypes => 'int4', prosrc => 'intervaltypmodout' }, +{ oid => '1162', + proname => 'interval_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_eq' }, +{ oid => '1163', + proname => 'interval_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_ne' }, +{ oid => '1164', + proname => 'interval_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_lt' }, +{ oid => '1165', + proname => 'interval_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_le' }, +{ oid => '1166', + proname => 'interval_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_ge' }, +{ oid => '1167', + proname => 'interval_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'interval interval', prosrc => 'interval_gt' }, +{ oid => '1168', + proname => 'interval_um', prorettype => 'interval', proargtypes => 'interval', + prosrc => 'interval_um' }, +{ oid => '1169', + proname => 'interval_pl', prorettype => 'interval', + proargtypes => 'interval interval', prosrc => 'interval_pl' }, +{ oid => '1170', + proname => 'interval_mi', prorettype => 'interval', + proargtypes => 'interval interval', prosrc => 'interval_mi' }, +{ oid => '1171', descr => 'extract field from timestamp with time zone', + proname => 'date_part', provolatile => 's', prorettype => 'float8', + proargtypes => 'text timestamptz', prosrc => 'timestamptz_part' }, +{ oid => '6203', descr => 'extract field from timestamp with time zone', + proname => 'extract', provolatile => 's', prorettype => 'numeric', + proargtypes => 'text timestamptz', prosrc => 'extract_timestamptz' }, +{ oid => '1172', descr => 'extract field from interval', + proname => 'date_part', prorettype => 'float8', + proargtypes => 'text interval', prosrc => 'interval_part' }, +{ oid => '6204', descr => 'extract field from interval', + proname => 'extract', prorettype => 'numeric', proargtypes => 'text interval', + prosrc => 'extract_interval' }, +{ oid => '1174', descr => 'convert date to timestamp with time zone', + proname => 'timestamptz', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'date', prosrc => 'date_timestamptz' }, +{ oid => '2711', + descr => 'promote groups of 24 hours to numbers of days and promote groups of 30 days to numbers of months', + proname => 'justify_interval', prorettype => 'interval', + proargtypes => 'interval', prosrc => 'interval_justify_interval' }, +{ oid => '1175', descr => 'promote groups of 24 hours to numbers of days', + proname => 'justify_hours', prorettype => 'interval', + proargtypes => 'interval', prosrc => 'interval_justify_hours' }, +{ oid => '1295', descr => 'promote groups of 30 days to numbers of months', + proname => 'justify_days', prorettype => 'interval', + proargtypes => 'interval', prosrc => 'interval_justify_days' }, +{ oid => '1176', descr => 'convert date and time to timestamp with time zone', + proname => 'timestamptz', prolang => 'sql', provolatile => 's', + prorettype => 'timestamptz', proargtypes => 'date time', + prosrc => 'see system_functions.sql' }, +{ oid => '1178', descr => 'convert timestamp with time zone to date', + proname => 'date', provolatile => 's', prorettype => 'date', + proargtypes => 'timestamptz', prosrc => 'timestamptz_date' }, +{ oid => '1181', + descr => 'age of a transaction ID, in transactions before current transaction', + proname => 'age', provolatile => 's', proparallel => 'r', + prorettype => 'int4', proargtypes => 'xid', prosrc => 'xid_age' }, +{ oid => '3939', + descr => 'age of a multi-transaction ID, in multi-transactions before current multi-transaction', + proname => 'mxid_age', provolatile => 's', prorettype => 'int4', + proargtypes => 'xid', prosrc => 'mxid_age' }, + +{ oid => '1188', + proname => 'timestamptz_mi', prorettype => 'interval', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_mi' }, +{ oid => '1189', + proname => 'timestamptz_pl_interval', provolatile => 's', + prorettype => 'timestamptz', proargtypes => 'timestamptz interval', + prosrc => 'timestamptz_pl_interval' }, +{ oid => '1190', + proname => 'timestamptz_mi_interval', provolatile => 's', + prorettype => 'timestamptz', proargtypes => 'timestamptz interval', + prosrc => 'timestamptz_mi_interval' }, +{ oid => '1195', descr => 'smaller of two', + proname => 'timestamptz_smaller', prorettype => 'timestamptz', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_smaller' }, +{ oid => '1196', descr => 'larger of two', + proname => 'timestamptz_larger', prorettype => 'timestamptz', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_larger' }, +{ oid => '1197', descr => 'smaller of two', + proname => 'interval_smaller', prorettype => 'interval', + proargtypes => 'interval interval', prosrc => 'interval_smaller' }, +{ oid => '1198', descr => 'larger of two', + proname => 'interval_larger', prorettype => 'interval', + proargtypes => 'interval interval', prosrc => 'interval_larger' }, +{ oid => '1199', descr => 'date difference preserving months and years', + proname => 'age', prorettype => 'interval', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamptz_age' }, + +# OIDS 1200 - 1299 + +{ oid => '3918', descr => 'planner support for interval length coercion', + proname => 'interval_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'interval_support' }, +{ oid => '1200', descr => 'adjust interval precision', + proname => 'interval', prosupport => 'interval_support', + prorettype => 'interval', proargtypes => 'interval int4', + prosrc => 'interval_scale' }, + +{ oid => '1215', descr => 'get description for object id and catalog name', + proname => 'obj_description', prolang => 'sql', procost => '100', + provolatile => 's', prorettype => 'text', proargtypes => 'oid name', + prosrc => 'see system_functions.sql' }, +{ oid => '1216', descr => 'get description for table column', + proname => 'col_description', prolang => 'sql', procost => '100', + provolatile => 's', prorettype => 'text', proargtypes => 'oid int4', + prosrc => 'see system_functions.sql' }, +{ oid => '1993', + descr => 'get description for object id and shared catalog name', + proname => 'shobj_description', prolang => 'sql', procost => '100', + provolatile => 's', prorettype => 'text', proargtypes => 'oid name', + prosrc => 'see system_functions.sql' }, + +{ oid => '1217', + descr => 'truncate timestamp with time zone to specified units', + proname => 'date_trunc', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'text timestamptz', prosrc => 'timestamptz_trunc' }, +{ oid => '1284', + descr => 'truncate timestamp with time zone to specified units in specified time zone', + proname => 'date_trunc', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'text timestamptz text', prosrc => 'timestamptz_trunc_zone' }, +{ oid => '1218', descr => 'truncate interval to specified units', + proname => 'date_trunc', prorettype => 'interval', + proargtypes => 'text interval', prosrc => 'interval_trunc' }, + +{ oid => '1219', descr => 'increment', + proname => 'int8inc', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8inc' }, +{ oid => '3546', descr => 'decrement', + proname => 'int8dec', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8dec' }, +{ oid => '2804', descr => 'increment, ignores second argument', + proname => 'int8inc_any', prorettype => 'int8', proargtypes => 'int8 any', + prosrc => 'int8inc_any' }, +{ oid => '3547', descr => 'decrement, ignores second argument', + proname => 'int8dec_any', prorettype => 'int8', proargtypes => 'int8 any', + prosrc => 'int8dec_any' }, +{ oid => '1230', + proname => 'int8abs', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8abs' }, + +{ oid => '1236', descr => 'larger of two', + proname => 'int8larger', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8larger' }, +{ oid => '1237', descr => 'smaller of two', + proname => 'int8smaller', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8smaller' }, + +{ oid => '1238', + proname => 'texticregexeq', prosupport => 'texticregexeq_support', + prorettype => 'bool', proargtypes => 'text text', prosrc => 'texticregexeq' }, +{ oid => '1024', descr => 'planner support for texticregexeq', + proname => 'texticregexeq_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'texticregexeq_support' }, +{ oid => '1239', + proname => 'texticregexne', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'texticregexne' }, +{ oid => '1240', + proname => 'nameicregexeq', prosupport => 'texticregexeq_support', + prorettype => 'bool', proargtypes => 'name text', prosrc => 'nameicregexeq' }, +{ oid => '1241', + proname => 'nameicregexne', prorettype => 'bool', proargtypes => 'name text', + prosrc => 'nameicregexne' }, + +{ oid => '1251', + proname => 'int4abs', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4abs' }, +{ oid => '1253', + proname => 'int2abs', prorettype => 'int2', proargtypes => 'int2', + prosrc => 'int2abs' }, + +{ oid => '1271', descr => 'intervals overlap?', + proname => 'overlaps', proisstrict => 'f', prorettype => 'bool', + proargtypes => 'timetz timetz timetz timetz', prosrc => 'overlaps_timetz' }, +{ oid => '1272', + proname => 'datetime_pl', prorettype => 'timestamp', + proargtypes => 'date time', prosrc => 'datetime_timestamp' }, +{ oid => '1273', descr => 'extract field from time with time zone', + proname => 'date_part', prorettype => 'float8', proargtypes => 'text timetz', + prosrc => 'timetz_part' }, +{ oid => '6201', descr => 'extract field from time with time zone', + proname => 'extract', prorettype => 'numeric', proargtypes => 'text timetz', + prosrc => 'extract_timetz' }, +{ oid => '1274', + proname => 'int84pl', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int84pl' }, +{ oid => '1275', + proname => 'int84mi', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int84mi' }, +{ oid => '1276', + proname => 'int84mul', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int84mul' }, +{ oid => '1277', + proname => 'int84div', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int84div' }, +{ oid => '1278', + proname => 'int48pl', prorettype => 'int8', proargtypes => 'int4 int8', + prosrc => 'int48pl' }, +{ oid => '1279', + proname => 'int48mi', prorettype => 'int8', proargtypes => 'int4 int8', + prosrc => 'int48mi' }, +{ oid => '1280', + proname => 'int48mul', prorettype => 'int8', proargtypes => 'int4 int8', + prosrc => 'int48mul' }, +{ oid => '1281', + proname => 'int48div', prorettype => 'int8', proargtypes => 'int4 int8', + prosrc => 'int48div' }, + +{ oid => '837', + proname => 'int82pl', prorettype => 'int8', proargtypes => 'int8 int2', + prosrc => 'int82pl' }, +{ oid => '838', + proname => 'int82mi', prorettype => 'int8', proargtypes => 'int8 int2', + prosrc => 'int82mi' }, +{ oid => '839', + proname => 'int82mul', prorettype => 'int8', proargtypes => 'int8 int2', + prosrc => 'int82mul' }, +{ oid => '840', + proname => 'int82div', prorettype => 'int8', proargtypes => 'int8 int2', + prosrc => 'int82div' }, +{ oid => '841', + proname => 'int28pl', prorettype => 'int8', proargtypes => 'int2 int8', + prosrc => 'int28pl' }, +{ oid => '942', + proname => 'int28mi', prorettype => 'int8', proargtypes => 'int2 int8', + prosrc => 'int28mi' }, +{ oid => '943', + proname => 'int28mul', prorettype => 'int8', proargtypes => 'int2 int8', + prosrc => 'int28mul' }, +{ oid => '948', + proname => 'int28div', prorettype => 'int8', proargtypes => 'int2 int8', + prosrc => 'int28div' }, + +{ oid => '1287', descr => 'convert int8 to oid', + proname => 'oid', prorettype => 'oid', proargtypes => 'int8', + prosrc => 'i8tooid' }, +{ oid => '1288', descr => 'convert oid to int8', + proname => 'int8', proleakproof => 't', prorettype => 'int8', + proargtypes => 'oid', prosrc => 'oidtoi8' }, + +{ oid => '1291', + descr => 'trigger to suppress updates when new and old records match', + proname => 'suppress_redundant_updates_trigger', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'suppress_redundant_updates_trigger' }, + +{ oid => '1292', + proname => 'tideq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tideq' }, +{ oid => '1294', descr => 'latest tid of a tuple', + proname => 'currtid2', provolatile => 'v', proparallel => 'u', + prorettype => 'tid', proargtypes => 'text tid', + prosrc => 'currtid_byrelname' }, +{ oid => '1265', + proname => 'tidne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tidne' }, +{ oid => '2790', + proname => 'tidgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tidgt' }, +{ oid => '2791', + proname => 'tidlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tidlt' }, +{ oid => '2792', + proname => 'tidge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tidge' }, +{ oid => '2793', + proname => 'tidle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'tid tid', prosrc => 'tidle' }, +{ oid => '2794', descr => 'less-equal-greater', + proname => 'bttidcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'tid tid', prosrc => 'bttidcmp' }, +{ oid => '2795', descr => 'larger of two', + proname => 'tidlarger', prorettype => 'tid', proargtypes => 'tid tid', + prosrc => 'tidlarger' }, +{ oid => '2796', descr => 'smaller of two', + proname => 'tidsmaller', prorettype => 'tid', proargtypes => 'tid tid', + prosrc => 'tidsmaller' }, +{ oid => '2233', descr => 'hash', + proname => 'hashtid', prorettype => 'int4', proargtypes => 'tid', + prosrc => 'hashtid' }, +{ oid => '2234', descr => 'hash', + proname => 'hashtidextended', prorettype => 'int8', proargtypes => 'tid int8', + prosrc => 'hashtidextended' }, + +{ oid => '1296', + proname => 'timedate_pl', prolang => 'sql', prorettype => 'timestamp', + proargtypes => 'time date', prosrc => 'see system_functions.sql' }, +{ oid => '1297', + proname => 'datetimetz_pl', prorettype => 'timestamptz', + proargtypes => 'date timetz', prosrc => 'datetimetz_timestamptz' }, +{ oid => '1298', + proname => 'timetzdate_pl', prolang => 'sql', prorettype => 'timestamptz', + proargtypes => 'timetz date', prosrc => 'see system_functions.sql' }, +{ oid => '1299', descr => 'current transaction time', + proname => 'now', provolatile => 's', prorettype => 'timestamptz', + proargtypes => '', prosrc => 'now' }, +{ oid => '2647', descr => 'current transaction time', + proname => 'transaction_timestamp', provolatile => 's', + prorettype => 'timestamptz', proargtypes => '', prosrc => 'now' }, +{ oid => '2648', descr => 'current statement time', + proname => 'statement_timestamp', provolatile => 's', + prorettype => 'timestamptz', proargtypes => '', + prosrc => 'statement_timestamp' }, +{ oid => '2649', descr => 'current clock time', + proname => 'clock_timestamp', provolatile => 'v', prorettype => 'timestamptz', + proargtypes => '', prosrc => 'clock_timestamp' }, + +# OIDS 1300 - 1399 + +{ oid => '1300', + descr => 'restriction selectivity for position-comparison operators', + proname => 'positionsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'positionsel' }, +{ oid => '1301', + descr => 'join selectivity for position-comparison operators', + proname => 'positionjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'positionjoinsel' }, +{ oid => '1302', + descr => 'restriction selectivity for containment comparison operators', + proname => 'contsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'contsel' }, +{ oid => '1303', + descr => 'join selectivity for containment comparison operators', + proname => 'contjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'contjoinsel' }, + +{ oid => '1304', descr => 'intervals overlap?', + proname => 'overlaps', proisstrict => 'f', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz timestamptz timestamptz', + prosrc => 'overlaps_timestamp' }, +{ oid => '1305', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz interval timestamptz interval', + prosrc => 'see system_functions.sql' }, +{ oid => '1306', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz timestamptz interval', + prosrc => 'see system_functions.sql' }, +{ oid => '1307', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz interval timestamptz timestamptz', + prosrc => 'see system_functions.sql' }, + +{ oid => '1308', descr => 'intervals overlap?', + proname => 'overlaps', proisstrict => 'f', prorettype => 'bool', + proargtypes => 'time time time time', prosrc => 'overlaps_time' }, +{ oid => '1309', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'time interval time interval', + prosrc => 'see system_functions.sql' }, +{ oid => '1310', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'time time time interval', + prosrc => 'see system_functions.sql' }, +{ oid => '1311', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'time interval time time', + prosrc => 'see system_functions.sql' }, + +{ oid => '1312', descr => 'I/O', + proname => 'timestamp_in', provolatile => 's', prorettype => 'timestamp', + proargtypes => 'cstring oid int4', prosrc => 'timestamp_in' }, +{ oid => '1313', descr => 'I/O', + proname => 'timestamp_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'timestamp', prosrc => 'timestamp_out' }, +{ oid => '2905', descr => 'I/O typmod', + proname => 'timestamptypmodin', prorettype => 'int4', + proargtypes => '_cstring', prosrc => 'timestamptypmodin' }, +{ oid => '2906', descr => 'I/O typmod', + proname => 'timestamptypmodout', prorettype => 'cstring', + proargtypes => 'int4', prosrc => 'timestamptypmodout' }, +{ oid => '1314', descr => 'less-equal-greater', + proname => 'timestamptz_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'timestamptz timestamptz', prosrc => 'timestamp_cmp' }, +{ oid => '1315', descr => 'less-equal-greater', + proname => 'interval_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'interval interval', prosrc => 'interval_cmp' }, +{ oid => '1316', descr => 'convert timestamp to time', + proname => 'time', prorettype => 'time', proargtypes => 'timestamp', + prosrc => 'timestamp_time' }, + +{ oid => '1317', descr => 'length', + proname => 'length', prorettype => 'int4', proargtypes => 'text', + prosrc => 'textlen' }, +{ oid => '1318', descr => 'character length', + proname => 'length', prorettype => 'int4', proargtypes => 'bpchar', + prosrc => 'bpcharlen' }, + +{ oid => '1319', + proname => 'xideqint4', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid int4', prosrc => 'xideq' }, +{ oid => '3309', + proname => 'xidneqint4', proleakproof => 't', prorettype => 'bool', + proargtypes => 'xid int4', prosrc => 'xidneq' }, + +{ oid => '1326', + proname => 'interval_div', prorettype => 'interval', + proargtypes => 'interval float8', prosrc => 'interval_div' }, + +{ oid => '1339', descr => 'base 10 logarithm', + proname => 'dlog10', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dlog10' }, +{ oid => '1340', descr => 'base 10 logarithm', + proname => 'log', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dlog10' }, +{ oid => '1194', descr => 'base 10 logarithm', + proname => 'log10', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dlog10' }, +{ oid => '1341', descr => 'natural logarithm', + proname => 'ln', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dlog1' }, +{ oid => '1342', descr => 'round to nearest integer', + proname => 'round', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dround' }, +{ oid => '1343', descr => 'truncate to integer', + proname => 'trunc', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dtrunc' }, +{ oid => '1344', descr => 'square root', + proname => 'sqrt', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsqrt' }, +{ oid => '1345', descr => 'cube root', + proname => 'cbrt', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcbrt' }, +{ oid => '1346', descr => 'exponentiation', + proname => 'pow', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'dpow' }, +{ oid => '1368', descr => 'exponentiation', + proname => 'power', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'dpow' }, +{ oid => '1347', descr => 'natural exponential (e^x)', + proname => 'exp', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dexp' }, + +# This form of obj_description is now deprecated, since it will fail if +# OIDs are not unique across system catalogs. Use the other form instead. +{ oid => '1348', descr => 'deprecated, use two-argument form instead', + proname => 'obj_description', prolang => 'sql', procost => '100', + provolatile => 's', prorettype => 'text', proargtypes => 'oid', + prosrc => 'see system_functions.sql' }, + +{ oid => '1349', descr => 'print type names of oidvector field', + proname => 'oidvectortypes', provolatile => 's', prorettype => 'text', + proargtypes => 'oidvector', prosrc => 'oidvectortypes' }, + +{ oid => '1350', descr => 'I/O', + proname => 'timetz_in', provolatile => 's', prorettype => 'timetz', + proargtypes => 'cstring oid int4', prosrc => 'timetz_in' }, +{ oid => '1351', descr => 'I/O', + proname => 'timetz_out', prorettype => 'cstring', proargtypes => 'timetz', + prosrc => 'timetz_out' }, +{ oid => '2911', descr => 'I/O typmod', + proname => 'timetztypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'timetztypmodin' }, +{ oid => '2912', descr => 'I/O typmod', + proname => 'timetztypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'timetztypmodout' }, +{ oid => '1352', + proname => 'timetz_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_eq' }, +{ oid => '1353', + proname => 'timetz_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_ne' }, +{ oid => '1354', + proname => 'timetz_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_lt' }, +{ oid => '1355', + proname => 'timetz_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_le' }, +{ oid => '1356', + proname => 'timetz_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_ge' }, +{ oid => '1357', + proname => 'timetz_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timetz timetz', prosrc => 'timetz_gt' }, +{ oid => '1358', descr => 'less-equal-greater', + proname => 'timetz_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'timetz timetz', prosrc => 'timetz_cmp' }, +{ oid => '1359', + descr => 'convert date and time with time zone to timestamp with time zone', + proname => 'timestamptz', prorettype => 'timestamptz', + proargtypes => 'date timetz', prosrc => 'datetimetz_timestamptz' }, + +{ oid => '1367', descr => 'character length', + proname => 'character_length', prorettype => 'int4', proargtypes => 'bpchar', + prosrc => 'bpcharlen' }, +{ oid => '1369', descr => 'character length', + proname => 'character_length', prorettype => 'int4', proargtypes => 'text', + prosrc => 'textlen' }, + +{ oid => '1370', descr => 'convert time to interval', + proname => 'interval', proleakproof => 't', prorettype => 'interval', + proargtypes => 'time', prosrc => 'time_interval' }, +{ oid => '1372', descr => 'character length', + proname => 'char_length', prorettype => 'int4', proargtypes => 'bpchar', + prosrc => 'bpcharlen' }, +{ oid => '1374', descr => 'octet length', + proname => 'octet_length', prorettype => 'int4', proargtypes => 'text', + prosrc => 'textoctetlen' }, +{ oid => '1375', descr => 'octet length', + proname => 'octet_length', prorettype => 'int4', proargtypes => 'bpchar', + prosrc => 'bpcharoctetlen' }, + +{ oid => '1377', descr => 'larger of two', + proname => 'time_larger', prorettype => 'time', proargtypes => 'time time', + prosrc => 'time_larger' }, +{ oid => '1378', descr => 'smaller of two', + proname => 'time_smaller', prorettype => 'time', proargtypes => 'time time', + prosrc => 'time_smaller' }, +{ oid => '1379', descr => 'larger of two', + proname => 'timetz_larger', prorettype => 'timetz', + proargtypes => 'timetz timetz', prosrc => 'timetz_larger' }, +{ oid => '1380', descr => 'smaller of two', + proname => 'timetz_smaller', prorettype => 'timetz', + proargtypes => 'timetz timetz', prosrc => 'timetz_smaller' }, + +{ oid => '1381', descr => 'character length', + proname => 'char_length', prorettype => 'int4', proargtypes => 'text', + prosrc => 'textlen' }, + +{ oid => '1384', descr => 'extract field from date', + proname => 'date_part', prolang => 'sql', prorettype => 'float8', + proargtypes => 'text date', prosrc => 'see system_functions.sql' }, +{ oid => '6199', descr => 'extract field from date', + proname => 'extract', prorettype => 'numeric', proargtypes => 'text date', + prosrc => 'extract_date' }, +{ oid => '1385', descr => 'extract field from time', + proname => 'date_part', prorettype => 'float8', proargtypes => 'text time', + prosrc => 'time_part' }, +{ oid => '6200', descr => 'extract field from time', + proname => 'extract', prorettype => 'numeric', proargtypes => 'text time', + prosrc => 'extract_time' }, +{ oid => '1386', + descr => 'date difference from today preserving months and years', + proname => 'age', prolang => 'sql', provolatile => 's', + prorettype => 'interval', proargtypes => 'timestamptz', + prosrc => 'see system_functions.sql' }, + +{ oid => '1388', + descr => 'convert timestamp with time zone to time with time zone', + proname => 'timetz', provolatile => 's', prorettype => 'timetz', + proargtypes => 'timestamptz', prosrc => 'timestamptz_timetz' }, + +{ oid => '1373', descr => 'finite date?', + proname => 'isfinite', prorettype => 'bool', proargtypes => 'date', + prosrc => 'date_finite' }, +{ oid => '1389', descr => 'finite timestamp?', + proname => 'isfinite', prorettype => 'bool', proargtypes => 'timestamptz', + prosrc => 'timestamp_finite' }, +{ oid => '1390', descr => 'finite interval?', + proname => 'isfinite', prorettype => 'bool', proargtypes => 'interval', + prosrc => 'interval_finite' }, + +{ oid => '1376', descr => 'factorial', + proname => 'factorial', prorettype => 'numeric', proargtypes => 'int8', + prosrc => 'numeric_fac' }, +{ oid => '1394', descr => 'absolute value', + proname => 'abs', prorettype => 'float4', proargtypes => 'float4', + prosrc => 'float4abs' }, +{ oid => '1395', descr => 'absolute value', + proname => 'abs', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'float8abs' }, +{ oid => '1396', descr => 'absolute value', + proname => 'abs', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8abs' }, +{ oid => '1397', descr => 'absolute value', + proname => 'abs', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4abs' }, +{ oid => '1398', descr => 'absolute value', + proname => 'abs', prorettype => 'int2', proargtypes => 'int2', + prosrc => 'int2abs' }, + +# OIDS 1400 - 1499 + +{ oid => '1400', descr => 'convert varchar to name', + proname => 'name', proleakproof => 't', prorettype => 'name', + proargtypes => 'varchar', prosrc => 'text_name' }, +{ oid => '1401', descr => 'convert name to varchar', + proname => 'varchar', proleakproof => 't', prorettype => 'varchar', + proargtypes => 'name', prosrc => 'name_text' }, + +{ oid => '1402', descr => 'current schema name', + proname => 'current_schema', provolatile => 's', proparallel => 'u', + prorettype => 'name', proargtypes => '', prosrc => 'current_schema' }, +{ oid => '1403', descr => 'current schema search list', + proname => 'current_schemas', provolatile => 's', proparallel => 'u', + prorettype => '_name', proargtypes => 'bool', prosrc => 'current_schemas' }, + +{ oid => '1404', descr => 'substitute portion of string', + proname => 'overlay', prorettype => 'text', + proargtypes => 'text text int4 int4', prosrc => 'textoverlay' }, +{ oid => '1405', descr => 'substitute portion of string', + proname => 'overlay', prorettype => 'text', proargtypes => 'text text int4', + prosrc => 'textoverlay_no_len' }, + +{ oid => '1406', descr => 'vertically aligned', + proname => 'isvertical', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_vert' }, +{ oid => '1407', descr => 'horizontally aligned', + proname => 'ishorizontal', prorettype => 'bool', proargtypes => 'point point', + prosrc => 'point_horiz' }, +{ oid => '1408', descr => 'parallel', + proname => 'isparallel', prorettype => 'bool', proargtypes => 'lseg lseg', + prosrc => 'lseg_parallel' }, +{ oid => '1409', descr => 'perpendicular', + proname => 'isperp', prorettype => 'bool', proargtypes => 'lseg lseg', + prosrc => 'lseg_perp' }, +{ oid => '1410', descr => 'vertical', + proname => 'isvertical', prorettype => 'bool', proargtypes => 'lseg', + prosrc => 'lseg_vertical' }, +{ oid => '1411', descr => 'horizontal', + proname => 'ishorizontal', prorettype => 'bool', proargtypes => 'lseg', + prosrc => 'lseg_horizontal' }, +{ oid => '1412', descr => 'parallel', + proname => 'isparallel', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_parallel' }, +{ oid => '1413', descr => 'perpendicular', + proname => 'isperp', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_perp' }, +{ oid => '1414', descr => 'vertical', + proname => 'isvertical', prorettype => 'bool', proargtypes => 'line', + prosrc => 'line_vertical' }, +{ oid => '1415', descr => 'horizontal', + proname => 'ishorizontal', prorettype => 'bool', proargtypes => 'line', + prosrc => 'line_horizontal' }, +{ oid => '1416', descr => 'center of', + proname => 'point', prorettype => 'point', proargtypes => 'circle', + prosrc => 'circle_center' }, + +{ oid => '1419', descr => 'convert interval to time', + proname => 'time', prorettype => 'time', proargtypes => 'interval', + prosrc => 'interval_time' }, + +{ oid => '1421', descr => 'convert points to box', + proname => 'box', prorettype => 'box', proargtypes => 'point point', + prosrc => 'points_box' }, +{ oid => '1422', + proname => 'box_add', prorettype => 'box', proargtypes => 'box point', + prosrc => 'box_add' }, +{ oid => '1423', + proname => 'box_sub', prorettype => 'box', proargtypes => 'box point', + prosrc => 'box_sub' }, +{ oid => '1424', + proname => 'box_mul', prorettype => 'box', proargtypes => 'box point', + prosrc => 'box_mul' }, +{ oid => '1425', + proname => 'box_div', prorettype => 'box', proargtypes => 'box point', + prosrc => 'box_div' }, +{ oid => '1426', + proname => 'path_contain_pt', prolang => 'sql', prorettype => 'bool', + proargtypes => 'path point', prosrc => 'see system_functions.sql' }, +{ oid => '1428', + proname => 'poly_contain_pt', prorettype => 'bool', + proargtypes => 'polygon point', prosrc => 'poly_contain_pt' }, +{ oid => '1429', + proname => 'pt_contained_poly', prorettype => 'bool', + proargtypes => 'point polygon', prosrc => 'pt_contained_poly' }, + +{ oid => '1430', descr => 'path closed?', + proname => 'isclosed', prorettype => 'bool', proargtypes => 'path', + prosrc => 'path_isclosed' }, +{ oid => '1431', descr => 'path open?', + proname => 'isopen', prorettype => 'bool', proargtypes => 'path', + prosrc => 'path_isopen' }, +{ oid => '1432', + proname => 'path_npoints', prorettype => 'int4', proargtypes => 'path', + prosrc => 'path_npoints' }, + +# pclose and popen might better be named close and open, but that crashes initdb. +# - thomas 97/04/20 +{ oid => '1433', descr => 'close path', + proname => 'pclose', prorettype => 'path', proargtypes => 'path', + prosrc => 'path_close' }, +{ oid => '1434', descr => 'open path', + proname => 'popen', prorettype => 'path', proargtypes => 'path', + prosrc => 'path_open' }, + +{ oid => '1435', + proname => 'path_add', prorettype => 'path', proargtypes => 'path path', + prosrc => 'path_add' }, +{ oid => '1436', + proname => 'path_add_pt', prorettype => 'path', proargtypes => 'path point', + prosrc => 'path_add_pt' }, +{ oid => '1437', + proname => 'path_sub_pt', prorettype => 'path', proargtypes => 'path point', + prosrc => 'path_sub_pt' }, +{ oid => '1438', + proname => 'path_mul_pt', prorettype => 'path', proargtypes => 'path point', + prosrc => 'path_mul_pt' }, +{ oid => '1439', + proname => 'path_div_pt', prorettype => 'path', proargtypes => 'path point', + prosrc => 'path_div_pt' }, + +{ oid => '1440', descr => 'convert x, y to point', + proname => 'point', prorettype => 'point', proargtypes => 'float8 float8', + prosrc => 'construct_point' }, +{ oid => '1441', + proname => 'point_add', prorettype => 'point', proargtypes => 'point point', + prosrc => 'point_add' }, +{ oid => '1442', + proname => 'point_sub', prorettype => 'point', proargtypes => 'point point', + prosrc => 'point_sub' }, +{ oid => '1443', + proname => 'point_mul', prorettype => 'point', proargtypes => 'point point', + prosrc => 'point_mul' }, +{ oid => '1444', + proname => 'point_div', prorettype => 'point', proargtypes => 'point point', + prosrc => 'point_div' }, + +{ oid => '1445', + proname => 'poly_npoints', prorettype => 'int4', proargtypes => 'polygon', + prosrc => 'poly_npoints' }, +{ oid => '1446', descr => 'convert polygon to bounding box', + proname => 'box', prorettype => 'box', proargtypes => 'polygon', + prosrc => 'poly_box' }, +{ oid => '1447', descr => 'convert polygon to path', + proname => 'path', prorettype => 'path', proargtypes => 'polygon', + prosrc => 'poly_path' }, +{ oid => '1448', descr => 'convert box to polygon', + proname => 'polygon', prorettype => 'polygon', proargtypes => 'box', + prosrc => 'box_poly' }, +{ oid => '1449', descr => 'convert path to polygon', + proname => 'polygon', prorettype => 'polygon', proargtypes => 'path', + prosrc => 'path_poly' }, + +{ oid => '1450', descr => 'I/O', + proname => 'circle_in', prorettype => 'circle', proargtypes => 'cstring', + prosrc => 'circle_in' }, +{ oid => '1451', descr => 'I/O', + proname => 'circle_out', prorettype => 'cstring', proargtypes => 'circle', + prosrc => 'circle_out' }, +{ oid => '1452', + proname => 'circle_same', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_same' }, +{ oid => '1453', + proname => 'circle_contain', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_contain' }, +{ oid => '1454', + proname => 'circle_left', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_left' }, +{ oid => '1455', + proname => 'circle_overleft', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_overleft' }, +{ oid => '1456', + proname => 'circle_overright', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_overright' }, +{ oid => '1457', + proname => 'circle_right', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_right' }, +{ oid => '1458', + proname => 'circle_contained', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_contained' }, +{ oid => '1459', + proname => 'circle_overlap', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_overlap' }, +{ oid => '1460', + proname => 'circle_below', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_below' }, +{ oid => '1461', + proname => 'circle_above', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_above' }, +{ oid => '1462', + proname => 'circle_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_eq' }, +{ oid => '1463', + proname => 'circle_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_ne' }, +{ oid => '1464', + proname => 'circle_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_lt' }, +{ oid => '1465', + proname => 'circle_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_gt' }, +{ oid => '1466', + proname => 'circle_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_le' }, +{ oid => '1467', + proname => 'circle_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_ge' }, +{ oid => '1468', descr => 'area of circle', + proname => 'area', prorettype => 'float8', proargtypes => 'circle', + prosrc => 'circle_area' }, +{ oid => '1469', descr => 'diameter of circle', + proname => 'diameter', prorettype => 'float8', proargtypes => 'circle', + prosrc => 'circle_diameter' }, +{ oid => '1470', descr => 'radius of circle', + proname => 'radius', prorettype => 'float8', proargtypes => 'circle', + prosrc => 'circle_radius' }, +{ oid => '1471', + proname => 'circle_distance', prorettype => 'float8', + proargtypes => 'circle circle', prosrc => 'circle_distance' }, +{ oid => '1472', + proname => 'circle_center', prorettype => 'point', proargtypes => 'circle', + prosrc => 'circle_center' }, +{ oid => '1473', descr => 'convert point and radius to circle', + proname => 'circle', prorettype => 'circle', proargtypes => 'point float8', + prosrc => 'cr_circle' }, +{ oid => '1474', descr => 'convert polygon to circle', + proname => 'circle', prorettype => 'circle', proargtypes => 'polygon', + prosrc => 'poly_circle' }, +{ oid => '1475', descr => 'convert vertex count and circle to polygon', + proname => 'polygon', prorettype => 'polygon', proargtypes => 'int4 circle', + prosrc => 'circle_poly' }, +{ oid => '1476', + proname => 'dist_pc', prorettype => 'float8', proargtypes => 'point circle', + prosrc => 'dist_pc' }, +{ oid => '1477', + proname => 'circle_contain_pt', prorettype => 'bool', + proargtypes => 'circle point', prosrc => 'circle_contain_pt' }, +{ oid => '1478', + proname => 'pt_contained_circle', prorettype => 'bool', + proargtypes => 'point circle', prosrc => 'pt_contained_circle' }, +{ oid => '4091', descr => 'convert point to empty box', + proname => 'box', prorettype => 'box', proargtypes => 'point', + prosrc => 'point_box' }, +{ oid => '1479', descr => 'convert box to circle', + proname => 'circle', prorettype => 'circle', proargtypes => 'box', + prosrc => 'box_circle' }, +{ oid => '1480', descr => 'convert circle to box', + proname => 'box', prorettype => 'box', proargtypes => 'circle', + prosrc => 'circle_box' }, + +{ oid => '1482', + proname => 'lseg_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_ne' }, +{ oid => '1483', + proname => 'lseg_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_lt' }, +{ oid => '1484', + proname => 'lseg_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_le' }, +{ oid => '1485', + proname => 'lseg_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_gt' }, +{ oid => '1486', + proname => 'lseg_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'lseg lseg', prosrc => 'lseg_ge' }, +{ oid => '1487', + proname => 'lseg_length', prorettype => 'float8', proargtypes => 'lseg', + prosrc => 'lseg_length' }, +{ oid => '1488', + proname => 'close_ls', prorettype => 'point', proargtypes => 'line lseg', + prosrc => 'close_ls' }, +{ oid => '1489', + proname => 'close_lseg', prorettype => 'point', proargtypes => 'lseg lseg', + prosrc => 'close_lseg' }, + +{ oid => '1490', descr => 'I/O', + proname => 'line_in', prorettype => 'line', proargtypes => 'cstring', + prosrc => 'line_in' }, +{ oid => '1491', descr => 'I/O', + proname => 'line_out', prorettype => 'cstring', proargtypes => 'line', + prosrc => 'line_out' }, +{ oid => '1492', + proname => 'line_eq', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_eq' }, +{ oid => '1493', descr => 'construct line from points', + proname => 'line', prorettype => 'line', proargtypes => 'point point', + prosrc => 'line_construct_pp' }, +{ oid => '1494', + proname => 'line_interpt', prorettype => 'point', proargtypes => 'line line', + prosrc => 'line_interpt' }, +{ oid => '1495', + proname => 'line_intersect', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_intersect' }, +{ oid => '1496', + proname => 'line_parallel', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_parallel' }, +{ oid => '1497', + proname => 'line_perp', prorettype => 'bool', proargtypes => 'line line', + prosrc => 'line_perp' }, +{ oid => '1498', + proname => 'line_vertical', prorettype => 'bool', proargtypes => 'line', + prosrc => 'line_vertical' }, +{ oid => '1499', + proname => 'line_horizontal', prorettype => 'bool', proargtypes => 'line', + prosrc => 'line_horizontal' }, + +# OIDS 1500 - 1599 + +{ oid => '1530', descr => 'distance between endpoints', + proname => 'length', prorettype => 'float8', proargtypes => 'lseg', + prosrc => 'lseg_length' }, +{ oid => '1531', descr => 'sum of path segments', + proname => 'length', prorettype => 'float8', proargtypes => 'path', + prosrc => 'path_length' }, + +{ oid => '1532', descr => 'center of', + proname => 'point', prorettype => 'point', proargtypes => 'lseg', + prosrc => 'lseg_center' }, +{ oid => '1534', descr => 'center of', + proname => 'point', prorettype => 'point', proargtypes => 'box', + prosrc => 'box_center' }, +{ oid => '1540', descr => 'center of', + proname => 'point', prorettype => 'point', proargtypes => 'polygon', + prosrc => 'poly_center' }, +{ oid => '1541', descr => 'diagonal of', + proname => 'lseg', prorettype => 'lseg', proargtypes => 'box', + prosrc => 'box_diagonal' }, +{ oid => '1542', descr => 'center of', + proname => 'center', prorettype => 'point', proargtypes => 'box', + prosrc => 'box_center' }, +{ oid => '1543', descr => 'center of', + proname => 'center', prorettype => 'point', proargtypes => 'circle', + prosrc => 'circle_center' }, +{ oid => '1544', descr => 'convert circle to 12-vertex polygon', + proname => 'polygon', prolang => 'sql', prorettype => 'polygon', + proargtypes => 'circle', prosrc => 'see system_functions.sql' }, +{ oid => '1545', descr => 'number of points', + proname => 'npoints', prorettype => 'int4', proargtypes => 'path', + prosrc => 'path_npoints' }, +{ oid => '1556', descr => 'number of points', + proname => 'npoints', prorettype => 'int4', proargtypes => 'polygon', + prosrc => 'poly_npoints' }, + +{ oid => '1564', descr => 'I/O', + proname => 'bit_in', prorettype => 'bit', proargtypes => 'cstring oid int4', + prosrc => 'bit_in' }, +{ oid => '1565', descr => 'I/O', + proname => 'bit_out', prorettype => 'cstring', proargtypes => 'bit', + prosrc => 'bit_out' }, +{ oid => '2919', descr => 'I/O typmod', + proname => 'bittypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'bittypmodin' }, +{ oid => '2920', descr => 'I/O typmod', + proname => 'bittypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'bittypmodout' }, + +{ oid => '1569', descr => 'matches LIKE expression', + proname => 'like', prosupport => 'textlike_support', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'textlike' }, +{ oid => '1570', descr => 'does not match LIKE expression', + proname => 'notlike', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'textnlike' }, +{ oid => '1571', descr => 'matches LIKE expression', + proname => 'like', prosupport => 'textlike_support', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'namelike' }, +{ oid => '1572', descr => 'does not match LIKE expression', + proname => 'notlike', prorettype => 'bool', proargtypes => 'name text', + prosrc => 'namenlike' }, + +# SEQUENCE functions +{ oid => '1574', descr => 'sequence next value', + proname => 'nextval', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass', prosrc => 'nextval_oid' }, +{ oid => '1575', descr => 'sequence current value', + proname => 'currval', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass', prosrc => 'currval_oid' }, +{ oid => '1576', descr => 'set sequence value', + proname => 'setval', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass int8', + prosrc => 'setval_oid' }, +{ oid => '1765', descr => 'set sequence value and is_called status', + proname => 'setval', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass int8 bool', + prosrc => 'setval3_oid' }, +{ oid => '3078', + descr => 'sequence parameters, for use by information schema', + proname => 'pg_sequence_parameters', provolatile => 's', + prorettype => 'record', proargtypes => 'oid', + proallargtypes => '{oid,int8,int8,int8,int8,bool,int8,oid}', + proargmodes => '{i,o,o,o,o,o,o,o}', + proargnames => '{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option,cache_size,data_type}', + prosrc => 'pg_sequence_parameters' }, +{ oid => '4032', descr => 'sequence last value', + proname => 'pg_sequence_last_value', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass', + prosrc => 'pg_sequence_last_value' }, + +{ oid => '275', descr => 'return the next oid for a system table', + proname => 'pg_nextoid', provolatile => 'v', proparallel => 'u', + prorettype => 'oid', proargtypes => 'regclass name regclass', + prosrc => 'pg_nextoid' }, +{ oid => '6241', descr => 'stop making pinned objects during initdb', + proname => 'pg_stop_making_pinned_objects', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => '', + prosrc => 'pg_stop_making_pinned_objects' }, + +{ oid => '1579', descr => 'I/O', + proname => 'varbit_in', prorettype => 'varbit', + proargtypes => 'cstring oid int4', prosrc => 'varbit_in' }, +{ oid => '1580', descr => 'I/O', + proname => 'varbit_out', prorettype => 'cstring', proargtypes => 'varbit', + prosrc => 'varbit_out' }, +{ oid => '2902', descr => 'I/O typmod', + proname => 'varbittypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'varbittypmodin' }, +{ oid => '2921', descr => 'I/O typmod', + proname => 'varbittypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'varbittypmodout' }, + +{ oid => '1581', + proname => 'biteq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'biteq' }, +{ oid => '1582', + proname => 'bitne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'bitne' }, +{ oid => '1592', + proname => 'bitge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'bitge' }, +{ oid => '1593', + proname => 'bitgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'bitgt' }, +{ oid => '1594', + proname => 'bitle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'bitle' }, +{ oid => '1595', + proname => 'bitlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bit bit', prosrc => 'bitlt' }, +{ oid => '1596', descr => 'less-equal-greater', + proname => 'bitcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bit bit', prosrc => 'bitcmp' }, + +{ oid => '1598', descr => 'random value', + proname => 'random', provolatile => 'v', proparallel => 'r', + prorettype => 'float8', proargtypes => '', prosrc => 'drandom' }, +{ oid => '1599', descr => 'set random seed', + proname => 'setseed', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'float8', prosrc => 'setseed' }, + +# OIDS 1600 - 1699 + +{ oid => '1600', descr => 'arcsine', + proname => 'asin', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dasin' }, +{ oid => '1601', descr => 'arccosine', + proname => 'acos', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dacos' }, +{ oid => '1602', descr => 'arctangent', + proname => 'atan', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'datan' }, +{ oid => '1603', descr => 'arctangent, two arguments', + proname => 'atan2', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'datan2' }, +{ oid => '1604', descr => 'sine', + proname => 'sin', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsin' }, +{ oid => '1605', descr => 'cosine', + proname => 'cos', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcos' }, +{ oid => '1606', descr => 'tangent', + proname => 'tan', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dtan' }, +{ oid => '1607', descr => 'cotangent', + proname => 'cot', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcot' }, + +{ oid => '2731', descr => 'arcsine, degrees', + proname => 'asind', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dasind' }, +{ oid => '2732', descr => 'arccosine, degrees', + proname => 'acosd', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dacosd' }, +{ oid => '2733', descr => 'arctangent, degrees', + proname => 'atand', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'datand' }, +{ oid => '2734', descr => 'arctangent, two arguments, degrees', + proname => 'atan2d', prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'datan2d' }, +{ oid => '2735', descr => 'sine, degrees', + proname => 'sind', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsind' }, +{ oid => '2736', descr => 'cosine, degrees', + proname => 'cosd', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcosd' }, +{ oid => '2737', descr => 'tangent, degrees', + proname => 'tand', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dtand' }, +{ oid => '2738', descr => 'cotangent, degrees', + proname => 'cotd', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcotd' }, + +{ oid => '1608', descr => 'radians to degrees', + proname => 'degrees', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'degrees' }, +{ oid => '1609', descr => 'degrees to radians', + proname => 'radians', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'radians' }, +{ oid => '1610', descr => 'PI', + proname => 'pi', prorettype => 'float8', proargtypes => '', prosrc => 'dpi' }, + +{ oid => '2462', descr => 'hyperbolic sine', + proname => 'sinh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dsinh' }, +{ oid => '2463', descr => 'hyperbolic cosine', + proname => 'cosh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dcosh' }, +{ oid => '2464', descr => 'hyperbolic tangent', + proname => 'tanh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dtanh' }, +{ oid => '2465', descr => 'inverse hyperbolic sine', + proname => 'asinh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dasinh' }, +{ oid => '2466', descr => 'inverse hyperbolic cosine', + proname => 'acosh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'dacosh' }, +{ oid => '2467', descr => 'inverse hyperbolic tangent', + proname => 'atanh', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'datanh' }, + +{ oid => '1618', + proname => 'interval_mul', prorettype => 'interval', + proargtypes => 'interval float8', prosrc => 'interval_mul' }, + +{ oid => '1620', descr => 'convert first char to int4', + proname => 'ascii', prorettype => 'int4', proargtypes => 'text', + prosrc => 'ascii' }, +{ oid => '1621', descr => 'convert int4 to char', + proname => 'chr', prorettype => 'text', proargtypes => 'int4', + prosrc => 'chr' }, +{ oid => '1622', descr => 'replicate string n times', + proname => 'repeat', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'repeat' }, + +{ oid => '1623', descr => 'convert SQL regexp pattern to POSIX style', + proname => 'similar_escape', proisstrict => 'f', prorettype => 'text', + proargtypes => 'text text', prosrc => 'similar_escape' }, +{ oid => '1986', descr => 'convert SQL regexp pattern to POSIX style', + proname => 'similar_to_escape', prorettype => 'text', + proargtypes => 'text text', prosrc => 'similar_to_escape_2' }, +{ oid => '1987', descr => 'convert SQL regexp pattern to POSIX style', + proname => 'similar_to_escape', prorettype => 'text', proargtypes => 'text', + prosrc => 'similar_to_escape_1' }, + +{ oid => '1624', + proname => 'mul_d_interval', prorettype => 'interval', + proargtypes => 'float8 interval', prosrc => 'mul_d_interval' }, + +{ oid => '1631', + proname => 'bpcharlike', prosupport => 'textlike_support', + prorettype => 'bool', proargtypes => 'bpchar text', prosrc => 'textlike' }, +{ oid => '1632', + proname => 'bpcharnlike', prorettype => 'bool', proargtypes => 'bpchar text', + prosrc => 'textnlike' }, + +{ oid => '1633', + proname => 'texticlike', prosupport => 'texticlike_support', + prorettype => 'bool', proargtypes => 'text text', prosrc => 'texticlike' }, +{ oid => '1025', descr => 'planner support for texticlike', + proname => 'texticlike_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'texticlike_support' }, +{ oid => '1634', + proname => 'texticnlike', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'texticnlike' }, +{ oid => '1635', + proname => 'nameiclike', prosupport => 'texticlike_support', + prorettype => 'bool', proargtypes => 'name text', prosrc => 'nameiclike' }, +{ oid => '1636', + proname => 'nameicnlike', prorettype => 'bool', proargtypes => 'name text', + prosrc => 'nameicnlike' }, +{ oid => '1637', descr => 'convert LIKE pattern to use backslash escapes', + proname => 'like_escape', prorettype => 'text', proargtypes => 'text text', + prosrc => 'like_escape' }, + +{ oid => '1656', + proname => 'bpcharicregexeq', prosupport => 'texticregexeq_support', + prorettype => 'bool', proargtypes => 'bpchar text', + prosrc => 'texticregexeq' }, +{ oid => '1657', + proname => 'bpcharicregexne', prorettype => 'bool', + proargtypes => 'bpchar text', prosrc => 'texticregexne' }, +{ oid => '1658', + proname => 'bpcharregexeq', prosupport => 'textregexeq_support', + prorettype => 'bool', proargtypes => 'bpchar text', prosrc => 'textregexeq' }, +{ oid => '1659', + proname => 'bpcharregexne', prorettype => 'bool', + proargtypes => 'bpchar text', prosrc => 'textregexne' }, +{ oid => '1660', + proname => 'bpchariclike', prosupport => 'texticlike_support', + prorettype => 'bool', proargtypes => 'bpchar text', prosrc => 'texticlike' }, +{ oid => '1661', + proname => 'bpcharicnlike', prorettype => 'bool', + proargtypes => 'bpchar text', prosrc => 'texticnlike' }, + +# Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> +{ oid => '868', descr => 'position of substring', + proname => 'strpos', prorettype => 'int4', proargtypes => 'text text', + prosrc => 'textpos' }, +{ oid => '870', descr => 'lowercase', + proname => 'lower', prorettype => 'text', proargtypes => 'text', + prosrc => 'lower' }, +{ oid => '871', descr => 'uppercase', + proname => 'upper', prorettype => 'text', proargtypes => 'text', + prosrc => 'upper' }, +{ oid => '872', descr => 'capitalize each word', + proname => 'initcap', prorettype => 'text', proargtypes => 'text', + prosrc => 'initcap' }, +{ oid => '873', descr => 'left-pad string to length', + proname => 'lpad', prorettype => 'text', proargtypes => 'text int4 text', + prosrc => 'lpad' }, +{ oid => '874', descr => 'right-pad string to length', + proname => 'rpad', prorettype => 'text', proargtypes => 'text int4 text', + prosrc => 'rpad' }, +{ oid => '875', descr => 'trim selected characters from left end of string', + proname => 'ltrim', prorettype => 'text', proargtypes => 'text text', + prosrc => 'ltrim' }, +{ oid => '876', descr => 'trim selected characters from right end of string', + proname => 'rtrim', prorettype => 'text', proargtypes => 'text text', + prosrc => 'rtrim' }, +{ oid => '877', descr => 'extract portion of string', + proname => 'substr', prorettype => 'text', proargtypes => 'text int4 int4', + prosrc => 'text_substr' }, +{ oid => '878', descr => 'map a set of characters appearing in string', + proname => 'translate', prorettype => 'text', proargtypes => 'text text text', + prosrc => 'translate' }, +{ oid => '879', descr => 'left-pad string to length', + proname => 'lpad', prolang => 'sql', prorettype => 'text', + proargtypes => 'text int4', prosrc => 'see system_functions.sql' }, +{ oid => '880', descr => 'right-pad string to length', + proname => 'rpad', prolang => 'sql', prorettype => 'text', + proargtypes => 'text int4', prosrc => 'see system_functions.sql' }, +{ oid => '881', descr => 'trim spaces from left end of string', + proname => 'ltrim', prorettype => 'text', proargtypes => 'text', + prosrc => 'ltrim1' }, +{ oid => '882', descr => 'trim spaces from right end of string', + proname => 'rtrim', prorettype => 'text', proargtypes => 'text', + prosrc => 'rtrim1' }, +{ oid => '883', descr => 'extract portion of string', + proname => 'substr', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'text_substr_no_len' }, +{ oid => '884', descr => 'trim selected characters from both ends of string', + proname => 'btrim', prorettype => 'text', proargtypes => 'text text', + prosrc => 'btrim' }, +{ oid => '885', descr => 'trim spaces from both ends of string', + proname => 'btrim', prorettype => 'text', proargtypes => 'text', + prosrc => 'btrim1' }, + +{ oid => '936', descr => 'extract portion of string', + proname => 'substring', prorettype => 'text', proargtypes => 'text int4 int4', + prosrc => 'text_substr' }, +{ oid => '937', descr => 'extract portion of string', + proname => 'substring', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'text_substr_no_len' }, +{ oid => '2087', + descr => 'replace all occurrences in string of old_substr with new_substr', + proname => 'replace', prorettype => 'text', proargtypes => 'text text text', + prosrc => 'replace_text' }, +{ oid => '2284', descr => 'replace text using regexp', + proname => 'regexp_replace', prorettype => 'text', + proargtypes => 'text text text', prosrc => 'textregexreplace_noopt' }, +{ oid => '2285', descr => 'replace text using regexp', + proname => 'regexp_replace', prorettype => 'text', + proargtypes => 'text text text text', prosrc => 'textregexreplace' }, +{ oid => '6251', descr => 'replace text using regexp', + proname => 'regexp_replace', prorettype => 'text', + proargtypes => 'text text text int4 int4 text', + prosrc => 'textregexreplace_extended' }, +{ oid => '6252', descr => 'replace text using regexp', + proname => 'regexp_replace', prorettype => 'text', + proargtypes => 'text text text int4 int4', + prosrc => 'textregexreplace_extended_no_flags' }, +{ oid => '6253', descr => 'replace text using regexp', + proname => 'regexp_replace', prorettype => 'text', + proargtypes => 'text text text int4', + prosrc => 'textregexreplace_extended_no_n' }, +{ oid => '3396', descr => 'find first match for regexp', + proname => 'regexp_match', prorettype => '_text', proargtypes => 'text text', + prosrc => 'regexp_match_no_flags' }, +{ oid => '3397', descr => 'find first match for regexp', + proname => 'regexp_match', prorettype => '_text', + proargtypes => 'text text text', prosrc => 'regexp_match' }, +{ oid => '2763', descr => 'find match(es) for regexp', + proname => 'regexp_matches', prorows => '1', proretset => 't', + prorettype => '_text', proargtypes => 'text text', + prosrc => 'regexp_matches_no_flags' }, +{ oid => '2764', descr => 'find match(es) for regexp', + proname => 'regexp_matches', prorows => '10', proretset => 't', + prorettype => '_text', proargtypes => 'text text text', + prosrc => 'regexp_matches' }, +{ oid => '6254', descr => 'count regexp matches', + proname => 'regexp_count', prorettype => 'int4', proargtypes => 'text text', + prosrc => 'regexp_count_no_start' }, +{ oid => '6255', descr => 'count regexp matches', + proname => 'regexp_count', prorettype => 'int4', + proargtypes => 'text text int4', prosrc => 'regexp_count_no_flags' }, +{ oid => '6256', descr => 'count regexp matches', + proname => 'regexp_count', prorettype => 'int4', + proargtypes => 'text text int4 text', prosrc => 'regexp_count' }, +{ oid => '6257', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', proargtypes => 'text text', + prosrc => 'regexp_instr_no_start' }, +{ oid => '6258', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', + proargtypes => 'text text int4', prosrc => 'regexp_instr_no_n' }, +{ oid => '6259', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', + proargtypes => 'text text int4 int4', prosrc => 'regexp_instr_no_endoption' }, +{ oid => '6260', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', + proargtypes => 'text text int4 int4 int4', + prosrc => 'regexp_instr_no_flags' }, +{ oid => '6261', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', + proargtypes => 'text text int4 int4 int4 text', + prosrc => 'regexp_instr_no_subexpr' }, +{ oid => '6262', descr => 'position of regexp match', + proname => 'regexp_instr', prorettype => 'int4', + proargtypes => 'text text int4 int4 int4 text int4', + prosrc => 'regexp_instr' }, +{ oid => '6263', descr => 'test for regexp match', + proname => 'regexp_like', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'regexp_like_no_flags' }, +{ oid => '6264', descr => 'test for regexp match', + proname => 'regexp_like', prorettype => 'bool', + proargtypes => 'text text text', prosrc => 'regexp_like' }, +{ oid => '6265', descr => 'extract substring that matches regexp', + proname => 'regexp_substr', prorettype => 'text', proargtypes => 'text text', + prosrc => 'regexp_substr_no_start' }, +{ oid => '6266', descr => 'extract substring that matches regexp', + proname => 'regexp_substr', prorettype => 'text', + proargtypes => 'text text int4', prosrc => 'regexp_substr_no_n' }, +{ oid => '6267', descr => 'extract substring that matches regexp', + proname => 'regexp_substr', prorettype => 'text', + proargtypes => 'text text int4 int4', prosrc => 'regexp_substr_no_flags' }, +{ oid => '6268', descr => 'extract substring that matches regexp', + proname => 'regexp_substr', prorettype => 'text', + proargtypes => 'text text int4 int4 text', + prosrc => 'regexp_substr_no_subexpr' }, +{ oid => '6269', descr => 'extract substring that matches regexp', + proname => 'regexp_substr', prorettype => 'text', + proargtypes => 'text text int4 int4 text int4', prosrc => 'regexp_substr' }, +{ oid => '2088', descr => 'split string by field_sep and return field_num', + proname => 'split_part', prorettype => 'text', + proargtypes => 'text text int4', prosrc => 'split_part' }, +{ oid => '2765', descr => 'split string by pattern', + proname => 'regexp_split_to_table', prorows => '1000', proretset => 't', + prorettype => 'text', proargtypes => 'text text', + prosrc => 'regexp_split_to_table_no_flags' }, +{ oid => '2766', descr => 'split string by pattern', + proname => 'regexp_split_to_table', prorows => '1000', proretset => 't', + prorettype => 'text', proargtypes => 'text text text', + prosrc => 'regexp_split_to_table' }, +{ oid => '2767', descr => 'split string by pattern', + proname => 'regexp_split_to_array', prorettype => '_text', + proargtypes => 'text text', prosrc => 'regexp_split_to_array_no_flags' }, +{ oid => '2768', descr => 'split string by pattern', + proname => 'regexp_split_to_array', prorettype => '_text', + proargtypes => 'text text text', prosrc => 'regexp_split_to_array' }, +{ oid => '2089', descr => 'convert int4 number to hex', + proname => 'to_hex', prorettype => 'text', proargtypes => 'int4', + prosrc => 'to_hex32' }, +{ oid => '2090', descr => 'convert int8 number to hex', + proname => 'to_hex', prorettype => 'text', proargtypes => 'int8', + prosrc => 'to_hex64' }, + +# for character set encoding support + +# return database encoding name +{ oid => '1039', descr => 'encoding name of current database', + proname => 'getdatabaseencoding', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'getdatabaseencoding' }, + +# return client encoding name i.e. session encoding +{ oid => '810', descr => 'encoding name of current database', + proname => 'pg_client_encoding', provolatile => 's', prorettype => 'name', + proargtypes => '', prosrc => 'pg_client_encoding' }, + +{ oid => '1713', descr => 'length of string in specified encoding', + proname => 'length', provolatile => 's', prorettype => 'int4', + proargtypes => 'bytea name', prosrc => 'length_in_encoding' }, + +{ oid => '1714', + descr => 'convert string with specified source encoding name', + proname => 'convert_from', provolatile => 's', prorettype => 'text', + proargtypes => 'bytea name', prosrc => 'pg_convert_from' }, + +{ oid => '1717', + descr => 'convert string with specified destination encoding name', + proname => 'convert_to', provolatile => 's', prorettype => 'bytea', + proargtypes => 'text name', prosrc => 'pg_convert_to' }, + +{ oid => '1813', descr => 'convert string with specified encoding names', + proname => 'convert', provolatile => 's', prorettype => 'bytea', + proargtypes => 'bytea name name', prosrc => 'pg_convert' }, + +{ oid => '1264', descr => 'convert encoding name to encoding id', + proname => 'pg_char_to_encoding', provolatile => 's', prorettype => 'int4', + proargtypes => 'name', prosrc => 'PG_char_to_encoding' }, + +{ oid => '1597', descr => 'convert encoding id to encoding name', + proname => 'pg_encoding_to_char', provolatile => 's', prorettype => 'name', + proargtypes => 'int4', prosrc => 'PG_encoding_to_char' }, + +{ oid => '2319', + descr => 'maximum octet length of a character in given encoding', + proname => 'pg_encoding_max_length', prorettype => 'int4', + proargtypes => 'int4', prosrc => 'pg_encoding_max_length_sql' }, + +{ oid => '1638', + proname => 'oidgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oidgt' }, +{ oid => '1639', + proname => 'oidge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'oid oid', prosrc => 'oidge' }, + +# System-view support functions +{ oid => '1573', descr => 'source text of a rule', + proname => 'pg_get_ruledef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_ruledef' }, +{ oid => '1640', descr => 'select statement of a view', + proname => 'pg_get_viewdef', provolatile => 's', proparallel => 'r', + prorettype => 'text', proargtypes => 'text', + prosrc => 'pg_get_viewdef_name' }, +{ oid => '1641', descr => 'select statement of a view', + proname => 'pg_get_viewdef', provolatile => 's', proparallel => 'r', + prorettype => 'text', proargtypes => 'oid', prosrc => 'pg_get_viewdef' }, +{ oid => '1642', descr => 'role name by OID (with fallback)', + proname => 'pg_get_userbyid', provolatile => 's', prorettype => 'name', + proargtypes => 'oid', prosrc => 'pg_get_userbyid' }, +{ oid => '1643', descr => 'index description', + proname => 'pg_get_indexdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_indexdef' }, +{ oid => '3415', descr => 'extended statistics object description', + proname => 'pg_get_statisticsobjdef', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_statisticsobjdef' }, +{ oid => '6174', descr => 'extended statistics columns', + proname => 'pg_get_statisticsobjdef_columns', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_statisticsobjdef_columns' }, +{ oid => '6173', descr => 'extended statistics expressions', + proname => 'pg_get_statisticsobjdef_expressions', provolatile => 's', + prorettype => '_text', proargtypes => 'oid', + prosrc => 'pg_get_statisticsobjdef_expressions' }, +{ oid => '3352', descr => 'partition key description', + proname => 'pg_get_partkeydef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_partkeydef' }, +{ oid => '3408', descr => 'partition constraint description', + proname => 'pg_get_partition_constraintdef', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_partition_constraintdef' }, +{ oid => '1662', descr => 'trigger description', + proname => 'pg_get_triggerdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_triggerdef' }, +{ oid => '1387', descr => 'constraint description', + proname => 'pg_get_constraintdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_constraintdef' }, +{ oid => '1716', descr => 'deparse an encoded expression', + proname => 'pg_get_expr', provolatile => 's', prorettype => 'text', + proargtypes => 'pg_node_tree oid', prosrc => 'pg_get_expr' }, +{ oid => '1665', descr => 'name of sequence for a serial column', + proname => 'pg_get_serial_sequence', provolatile => 's', prorettype => 'text', + proargtypes => 'text text', prosrc => 'pg_get_serial_sequence' }, +{ oid => '2098', descr => 'definition of a function', + proname => 'pg_get_functiondef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_functiondef' }, +{ oid => '2162', descr => 'argument list of a function', + proname => 'pg_get_function_arguments', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_function_arguments' }, +{ oid => '2232', descr => 'identity argument list of a function', + proname => 'pg_get_function_identity_arguments', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_function_identity_arguments' }, +{ oid => '2165', descr => 'result type of a function', + proname => 'pg_get_function_result', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_get_function_result' }, +{ oid => '3808', descr => 'function argument default', + proname => 'pg_get_function_arg_default', provolatile => 's', + prorettype => 'text', proargtypes => 'oid int4', + prosrc => 'pg_get_function_arg_default' }, +{ oid => '6197', descr => 'function SQL body', + proname => 'pg_get_function_sqlbody', provolatile => 's', + prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_get_function_sqlbody' }, + +{ oid => '1686', descr => 'list of SQL keywords', + proname => 'pg_get_keywords', procost => '10', prorows => '500', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,char,bool,text,text}', + proargmodes => '{o,o,o,o,o}', + proargnames => '{word,catcode,barelabel,catdesc,baredesc}', + prosrc => 'pg_get_keywords' }, + +{ oid => '6159', descr => 'list of catalog foreign key relationships', + proname => 'pg_get_catalog_foreign_keys', procost => '10', prorows => '250', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => '', + proallargtypes => '{regclass,_text,regclass,_text,bool,bool}', + proargmodes => '{o,o,o,o,o,o}', + proargnames => '{fktable,fkcols,pktable,pkcols,is_array,is_opt}', + prosrc => 'pg_get_catalog_foreign_keys' }, + +{ oid => '2289', descr => 'convert generic options array to name/value table', + proname => 'pg_options_to_table', prorows => '3', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => '_text', + proallargtypes => '{_text,text,text}', proargmodes => '{i,o,o}', + proargnames => '{options_array,option_name,option_value}', + prosrc => 'pg_options_to_table' }, + +{ oid => '1619', descr => 'type of the argument', + proname => 'pg_typeof', proisstrict => 'f', provolatile => 's', + prorettype => 'regtype', proargtypes => 'any', prosrc => 'pg_typeof' }, +{ oid => '3162', + descr => 'collation of the argument; implementation of the COLLATION FOR expression', + proname => 'pg_collation_for', proisstrict => 'f', provolatile => 's', + prorettype => 'text', proargtypes => 'any', prosrc => 'pg_collation_for' }, + +{ oid => '3842', descr => 'is a relation insertable/updatable/deletable', + proname => 'pg_relation_is_updatable', procost => '10', provolatile => 's', + prorettype => 'int4', proargtypes => 'regclass bool', + prosrc => 'pg_relation_is_updatable' }, +{ oid => '3843', descr => 'is a column updatable', + proname => 'pg_column_is_updatable', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'regclass int2 bool', + prosrc => 'pg_column_is_updatable' }, + +{ oid => '6120', descr => 'oid of replica identity index if any', + proname => 'pg_get_replica_identity_index', procost => '10', + provolatile => 's', prorettype => 'regclass', proargtypes => 'regclass', + prosrc => 'pg_get_replica_identity_index' }, + +# Deferrable unique constraint trigger +{ oid => '1250', descr => 'deferred UNIQUE constraint check', + proname => 'unique_key_recheck', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'unique_key_recheck' }, + +# Generic referential integrity constraint triggers +{ oid => '1644', descr => 'referential integrity FOREIGN KEY ... REFERENCES', + proname => 'RI_FKey_check_ins', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_check_ins' }, +{ oid => '1645', descr => 'referential integrity FOREIGN KEY ... REFERENCES', + proname => 'RI_FKey_check_upd', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_check_upd' }, +{ oid => '1646', descr => 'referential integrity ON DELETE CASCADE', + proname => 'RI_FKey_cascade_del', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_cascade_del' }, +{ oid => '1647', descr => 'referential integrity ON UPDATE CASCADE', + proname => 'RI_FKey_cascade_upd', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_cascade_upd' }, +{ oid => '1648', descr => 'referential integrity ON DELETE RESTRICT', + proname => 'RI_FKey_restrict_del', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_restrict_del' }, +{ oid => '1649', descr => 'referential integrity ON UPDATE RESTRICT', + proname => 'RI_FKey_restrict_upd', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_restrict_upd' }, +{ oid => '1650', descr => 'referential integrity ON DELETE SET NULL', + proname => 'RI_FKey_setnull_del', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_setnull_del' }, +{ oid => '1651', descr => 'referential integrity ON UPDATE SET NULL', + proname => 'RI_FKey_setnull_upd', provolatile => 'v', prorettype => 'trigger', + proargtypes => '', prosrc => 'RI_FKey_setnull_upd' }, +{ oid => '1652', descr => 'referential integrity ON DELETE SET DEFAULT', + proname => 'RI_FKey_setdefault_del', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_setdefault_del' }, +{ oid => '1653', descr => 'referential integrity ON UPDATE SET DEFAULT', + proname => 'RI_FKey_setdefault_upd', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_setdefault_upd' }, +{ oid => '1654', descr => 'referential integrity ON DELETE NO ACTION', + proname => 'RI_FKey_noaction_del', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_noaction_del' }, +{ oid => '1655', descr => 'referential integrity ON UPDATE NO ACTION', + proname => 'RI_FKey_noaction_upd', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'RI_FKey_noaction_upd' }, + +{ oid => '1666', + proname => 'varbiteq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'biteq' }, +{ oid => '1667', + proname => 'varbitne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'bitne' }, +{ oid => '1668', + proname => 'varbitge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'bitge' }, +{ oid => '1669', + proname => 'varbitgt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'bitgt' }, +{ oid => '1670', + proname => 'varbitle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'bitle' }, +{ oid => '1671', + proname => 'varbitlt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'varbit varbit', prosrc => 'bitlt' }, +{ oid => '1672', descr => 'less-equal-greater', + proname => 'varbitcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'varbit varbit', prosrc => 'bitcmp' }, + +# avoid the C names bitand and bitor, since they are C++ keywords +{ oid => '1673', + proname => 'bitand', prorettype => 'bit', proargtypes => 'bit bit', + prosrc => 'bit_and' }, +{ oid => '1674', + proname => 'bitor', prorettype => 'bit', proargtypes => 'bit bit', + prosrc => 'bit_or' }, +{ oid => '1675', + proname => 'bitxor', prorettype => 'bit', proargtypes => 'bit bit', + prosrc => 'bitxor' }, +{ oid => '1676', + proname => 'bitnot', prorettype => 'bit', proargtypes => 'bit', + prosrc => 'bitnot' }, +{ oid => '1677', + proname => 'bitshiftleft', prorettype => 'bit', proargtypes => 'bit int4', + prosrc => 'bitshiftleft' }, +{ oid => '1678', + proname => 'bitshiftright', prorettype => 'bit', proargtypes => 'bit int4', + prosrc => 'bitshiftright' }, +{ oid => '1679', + proname => 'bitcat', prorettype => 'varbit', proargtypes => 'varbit varbit', + prosrc => 'bitcat' }, +{ oid => '1680', descr => 'extract portion of bitstring', + proname => 'substring', prorettype => 'bit', proargtypes => 'bit int4 int4', + prosrc => 'bitsubstr' }, +{ oid => '1681', descr => 'bitstring length', + proname => 'length', prorettype => 'int4', proargtypes => 'bit', + prosrc => 'bitlength' }, +{ oid => '1682', descr => 'octet length', + proname => 'octet_length', prorettype => 'int4', proargtypes => 'bit', + prosrc => 'bitoctetlength' }, +{ oid => '1683', descr => 'convert int4 to bitstring', + proname => 'bit', prorettype => 'bit', proargtypes => 'int4 int4', + prosrc => 'bitfromint4' }, +{ oid => '1684', descr => 'convert bitstring to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'bit', + prosrc => 'bittoint4' }, + +{ oid => '1685', descr => 'adjust bit() to typmod length', + proname => 'bit', prorettype => 'bit', proargtypes => 'bit int4 bool', + prosrc => 'bit' }, +{ oid => '3158', descr => 'planner support for varbit length coercion', + proname => 'varbit_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'varbit_support' }, +{ oid => '1687', descr => 'adjust varbit() to typmod length', + proname => 'varbit', prosupport => 'varbit_support', prorettype => 'varbit', + proargtypes => 'varbit int4 bool', prosrc => 'varbit' }, + +{ oid => '1698', descr => 'position of sub-bitstring', + proname => 'position', prorettype => 'int4', proargtypes => 'bit bit', + prosrc => 'bitposition' }, +{ oid => '1699', descr => 'extract portion of bitstring', + proname => 'substring', prorettype => 'bit', proargtypes => 'bit int4', + prosrc => 'bitsubstr_no_len' }, + +{ oid => '3030', descr => 'substitute portion of bitstring', + proname => 'overlay', prorettype => 'bit', proargtypes => 'bit bit int4 int4', + prosrc => 'bitoverlay' }, +{ oid => '3031', descr => 'substitute portion of bitstring', + proname => 'overlay', prorettype => 'bit', proargtypes => 'bit bit int4', + prosrc => 'bitoverlay_no_len' }, +{ oid => '3032', descr => 'get bit', + proname => 'get_bit', prorettype => 'int4', proargtypes => 'bit int4', + prosrc => 'bitgetbit' }, +{ oid => '3033', descr => 'set bit', + proname => 'set_bit', prorettype => 'bit', proargtypes => 'bit int4 int4', + prosrc => 'bitsetbit' }, +{ oid => '6162', descr => 'number of set bits', + proname => 'bit_count', prorettype => 'int8', proargtypes => 'bit', + prosrc => 'bit_bit_count' }, + +# for macaddr type support +{ oid => '436', descr => 'I/O', + proname => 'macaddr_in', prorettype => 'macaddr', proargtypes => 'cstring', + prosrc => 'macaddr_in' }, +{ oid => '437', descr => 'I/O', + proname => 'macaddr_out', prorettype => 'cstring', proargtypes => 'macaddr', + prosrc => 'macaddr_out' }, + +{ oid => '753', descr => 'MACADDR manufacturer fields', + proname => 'trunc', prorettype => 'macaddr', proargtypes => 'macaddr', + prosrc => 'macaddr_trunc' }, + +{ oid => '830', + proname => 'macaddr_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_eq' }, +{ oid => '831', + proname => 'macaddr_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_lt' }, +{ oid => '832', + proname => 'macaddr_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_le' }, +{ oid => '833', + proname => 'macaddr_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_gt' }, +{ oid => '834', + proname => 'macaddr_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_ge' }, +{ oid => '835', + proname => 'macaddr_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_ne' }, +{ oid => '836', descr => 'less-equal-greater', + proname => 'macaddr_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_cmp' }, +{ oid => '3144', + proname => 'macaddr_not', prorettype => 'macaddr', proargtypes => 'macaddr', + prosrc => 'macaddr_not' }, +{ oid => '3145', + proname => 'macaddr_and', prorettype => 'macaddr', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_and' }, +{ oid => '3146', + proname => 'macaddr_or', prorettype => 'macaddr', + proargtypes => 'macaddr macaddr', prosrc => 'macaddr_or' }, +{ oid => '3359', descr => 'sort support', + proname => 'macaddr_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'macaddr_sortsupport' }, + +# for macaddr8 type support +{ oid => '4110', descr => 'I/O', + proname => 'macaddr8_in', prorettype => 'macaddr8', proargtypes => 'cstring', + prosrc => 'macaddr8_in' }, +{ oid => '4111', descr => 'I/O', + proname => 'macaddr8_out', prorettype => 'cstring', proargtypes => 'macaddr8', + prosrc => 'macaddr8_out' }, + +{ oid => '4112', descr => 'MACADDR8 manufacturer fields', + proname => 'trunc', prorettype => 'macaddr8', proargtypes => 'macaddr8', + prosrc => 'macaddr8_trunc' }, + +{ oid => '4113', + proname => 'macaddr8_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_eq' }, +{ oid => '4114', + proname => 'macaddr8_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_lt' }, +{ oid => '4115', + proname => 'macaddr8_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_le' }, +{ oid => '4116', + proname => 'macaddr8_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_gt' }, +{ oid => '4117', + proname => 'macaddr8_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_ge' }, +{ oid => '4118', + proname => 'macaddr8_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_ne' }, +{ oid => '4119', descr => 'less-equal-greater', + proname => 'macaddr8_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_cmp' }, +{ oid => '4120', + proname => 'macaddr8_not', prorettype => 'macaddr8', + proargtypes => 'macaddr8', prosrc => 'macaddr8_not' }, +{ oid => '4121', + proname => 'macaddr8_and', prorettype => 'macaddr8', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_and' }, +{ oid => '4122', + proname => 'macaddr8_or', prorettype => 'macaddr8', + proargtypes => 'macaddr8 macaddr8', prosrc => 'macaddr8_or' }, +{ oid => '4123', descr => 'convert macaddr to macaddr8', + proname => 'macaddr8', proleakproof => 't', prorettype => 'macaddr8', + proargtypes => 'macaddr', prosrc => 'macaddrtomacaddr8' }, +{ oid => '4124', descr => 'convert macaddr8 to macaddr', + proname => 'macaddr', prorettype => 'macaddr', proargtypes => 'macaddr8', + prosrc => 'macaddr8tomacaddr' }, +{ oid => '4125', descr => 'set 7th bit in macaddr8', + proname => 'macaddr8_set7bit', prorettype => 'macaddr8', + proargtypes => 'macaddr8', prosrc => 'macaddr8_set7bit' }, + +# for inet type support +{ oid => '910', descr => 'I/O', + proname => 'inet_in', prorettype => 'inet', proargtypes => 'cstring', + prosrc => 'inet_in' }, +{ oid => '911', descr => 'I/O', + proname => 'inet_out', prorettype => 'cstring', proargtypes => 'inet', + prosrc => 'inet_out' }, + +# for cidr type support +{ oid => '1267', descr => 'I/O', + proname => 'cidr_in', prorettype => 'cidr', proargtypes => 'cstring', + prosrc => 'cidr_in' }, +{ oid => '1427', descr => 'I/O', + proname => 'cidr_out', prorettype => 'cstring', proargtypes => 'cidr', + prosrc => 'cidr_out' }, + +# these are used for both inet and cidr +{ oid => '920', + proname => 'network_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_eq' }, +{ oid => '921', + proname => 'network_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_lt' }, +{ oid => '922', + proname => 'network_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_le' }, +{ oid => '923', + proname => 'network_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_gt' }, +{ oid => '924', + proname => 'network_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_ge' }, +{ oid => '925', + proname => 'network_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_ne' }, +{ oid => '3562', descr => 'larger of two', + proname => 'network_larger', prorettype => 'inet', proargtypes => 'inet inet', + prosrc => 'network_larger' }, +{ oid => '3563', descr => 'smaller of two', + proname => 'network_smaller', prorettype => 'inet', + proargtypes => 'inet inet', prosrc => 'network_smaller' }, +{ oid => '926', descr => 'less-equal-greater', + proname => 'network_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'inet inet', prosrc => 'network_cmp' }, +{ oid => '927', + proname => 'network_sub', prosupport => 'network_subset_support', + prorettype => 'bool', proargtypes => 'inet inet', prosrc => 'network_sub' }, +{ oid => '928', + proname => 'network_subeq', prosupport => 'network_subset_support', + prorettype => 'bool', proargtypes => 'inet inet', prosrc => 'network_subeq' }, +{ oid => '929', + proname => 'network_sup', prosupport => 'network_subset_support', + prorettype => 'bool', proargtypes => 'inet inet', prosrc => 'network_sup' }, +{ oid => '930', + proname => 'network_supeq', prosupport => 'network_subset_support', + prorettype => 'bool', proargtypes => 'inet inet', prosrc => 'network_supeq' }, +{ oid => '1173', descr => 'planner support for network_sub/superset', + proname => 'network_subset_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'network_subset_support' }, + +{ oid => '3551', + proname => 'network_overlap', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'network_overlap' }, +{ oid => '5033', descr => 'sort support', + proname => 'network_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'network_sortsupport' }, + +# inet/cidr functions +{ oid => '598', descr => 'abbreviated display of inet value', + proname => 'abbrev', prorettype => 'text', proargtypes => 'inet', + prosrc => 'inet_abbrev' }, +{ oid => '599', descr => 'abbreviated display of cidr value', + proname => 'abbrev', prorettype => 'text', proargtypes => 'cidr', + prosrc => 'cidr_abbrev' }, +{ oid => '605', descr => 'change netmask of inet', + proname => 'set_masklen', prorettype => 'inet', proargtypes => 'inet int4', + prosrc => 'inet_set_masklen' }, +{ oid => '635', descr => 'change netmask of cidr', + proname => 'set_masklen', prorettype => 'cidr', proargtypes => 'cidr int4', + prosrc => 'cidr_set_masklen' }, +{ oid => '711', descr => 'address family (4 for IPv4, 6 for IPv6)', + proname => 'family', prorettype => 'int4', proargtypes => 'inet', + prosrc => 'network_family' }, +{ oid => '683', descr => 'network part of address', + proname => 'network', prorettype => 'cidr', proargtypes => 'inet', + prosrc => 'network_network' }, +{ oid => '696', descr => 'netmask of address', + proname => 'netmask', prorettype => 'inet', proargtypes => 'inet', + prosrc => 'network_netmask' }, +{ oid => '697', descr => 'netmask length', + proname => 'masklen', prorettype => 'int4', proargtypes => 'inet', + prosrc => 'network_masklen' }, +{ oid => '698', descr => 'broadcast address of network', + proname => 'broadcast', prorettype => 'inet', proargtypes => 'inet', + prosrc => 'network_broadcast' }, +{ oid => '699', descr => 'show address octets only', + proname => 'host', prorettype => 'text', proargtypes => 'inet', + prosrc => 'network_host' }, +{ oid => '730', descr => 'show all parts of inet/cidr value', + proname => 'text', prorettype => 'text', proargtypes => 'inet', + prosrc => 'network_show' }, +{ oid => '1362', descr => 'hostmask of address', + proname => 'hostmask', prorettype => 'inet', proargtypes => 'inet', + prosrc => 'network_hostmask' }, +{ oid => '1715', descr => 'convert inet to cidr', + proname => 'cidr', prorettype => 'cidr', proargtypes => 'inet', + prosrc => 'inet_to_cidr' }, + +{ oid => '2196', descr => 'inet address of the client', + proname => 'inet_client_addr', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'inet', proargtypes => '', + prosrc => 'inet_client_addr' }, +{ oid => '2197', descr => 'client\'s port number for this connection', + proname => 'inet_client_port', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'int4', proargtypes => '', + prosrc => 'inet_client_port' }, +{ oid => '2198', descr => 'inet address of the server', + proname => 'inet_server_addr', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'inet', proargtypes => '', + prosrc => 'inet_server_addr' }, +{ oid => '2199', descr => 'server\'s port number for this connection', + proname => 'inet_server_port', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'int4', proargtypes => '', + prosrc => 'inet_server_port' }, + +{ oid => '2627', + proname => 'inetnot', prorettype => 'inet', proargtypes => 'inet', + prosrc => 'inetnot' }, +{ oid => '2628', + proname => 'inetand', prorettype => 'inet', proargtypes => 'inet inet', + prosrc => 'inetand' }, +{ oid => '2629', + proname => 'inetor', prorettype => 'inet', proargtypes => 'inet inet', + prosrc => 'inetor' }, +{ oid => '2630', + proname => 'inetpl', prorettype => 'inet', proargtypes => 'inet int8', + prosrc => 'inetpl' }, +{ oid => '2631', + proname => 'int8pl_inet', prolang => 'sql', prorettype => 'inet', + proargtypes => 'int8 inet', prosrc => 'see system_functions.sql' }, +{ oid => '2632', + proname => 'inetmi_int8', prorettype => 'inet', proargtypes => 'inet int8', + prosrc => 'inetmi_int8' }, +{ oid => '2633', + proname => 'inetmi', prorettype => 'int8', proargtypes => 'inet inet', + prosrc => 'inetmi' }, +{ oid => '4071', descr => 'are the addresses from the same family?', + proname => 'inet_same_family', prorettype => 'bool', + proargtypes => 'inet inet', prosrc => 'inet_same_family' }, +{ oid => '4063', + descr => 'the smallest network which includes both of the given networks', + proname => 'inet_merge', prorettype => 'cidr', proargtypes => 'inet inet', + prosrc => 'inet_merge' }, + +# GiST support for inet and cidr +{ oid => '3553', descr => 'GiST support', + proname => 'inet_gist_consistent', prorettype => 'bool', + proargtypes => 'internal inet int2 oid internal', + prosrc => 'inet_gist_consistent' }, +{ oid => '3554', descr => 'GiST support', + proname => 'inet_gist_union', prorettype => 'inet', + proargtypes => 'internal internal', prosrc => 'inet_gist_union' }, +{ oid => '3555', descr => 'GiST support', + proname => 'inet_gist_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'inet_gist_compress' }, +{ oid => '3573', descr => 'GiST support', + proname => 'inet_gist_fetch', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'inet_gist_fetch' }, +{ oid => '3557', descr => 'GiST support', + proname => 'inet_gist_penalty', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'inet_gist_penalty' }, +{ oid => '3558', descr => 'GiST support', + proname => 'inet_gist_picksplit', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'inet_gist_picksplit' }, +{ oid => '3559', descr => 'GiST support', + proname => 'inet_gist_same', prorettype => 'internal', + proargtypes => 'inet inet internal', prosrc => 'inet_gist_same' }, + +# SP-GiST support for inet and cidr +{ oid => '3795', descr => 'SP-GiST support', + proname => 'inet_spg_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'inet_spg_config' }, +{ oid => '3796', descr => 'SP-GiST support', + proname => 'inet_spg_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'inet_spg_choose' }, +{ oid => '3797', descr => 'SP-GiST support', + proname => 'inet_spg_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'inet_spg_picksplit' }, +{ oid => '3798', descr => 'SP-GiST support', + proname => 'inet_spg_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'inet_spg_inner_consistent' }, +{ oid => '3799', descr => 'SP-GiST support', + proname => 'inet_spg_leaf_consistent', prorettype => 'bool', + proargtypes => 'internal internal', prosrc => 'inet_spg_leaf_consistent' }, + +# Selectivity estimation for inet and cidr +{ oid => '3560', descr => 'restriction selectivity for network operators', + proname => 'networksel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'networksel' }, +{ oid => '3561', descr => 'join selectivity for network operators', + proname => 'networkjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'networkjoinsel' }, + +{ oid => '1690', + proname => 'time_mi_time', prorettype => 'interval', + proargtypes => 'time time', prosrc => 'time_mi_time' }, + +{ oid => '1691', + proname => 'boolle', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boolle' }, +{ oid => '1692', + proname => 'boolge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boolge' }, +{ oid => '1693', descr => 'less-equal-greater', + proname => 'btboolcmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bool bool', prosrc => 'btboolcmp' }, + +{ oid => '1688', descr => 'hash', + proname => 'time_hash', prorettype => 'int4', proargtypes => 'time', + prosrc => 'time_hash' }, +{ oid => '3409', descr => 'hash', + proname => 'time_hash_extended', prorettype => 'int8', + proargtypes => 'time int8', prosrc => 'time_hash_extended' }, +{ oid => '1696', descr => 'hash', + proname => 'timetz_hash', prorettype => 'int4', proargtypes => 'timetz', + prosrc => 'timetz_hash' }, +{ oid => '3410', descr => 'hash', + proname => 'timetz_hash_extended', prorettype => 'int8', + proargtypes => 'timetz int8', prosrc => 'timetz_hash_extended' }, +{ oid => '1697', descr => 'hash', + proname => 'interval_hash', prorettype => 'int4', proargtypes => 'interval', + prosrc => 'interval_hash' }, +{ oid => '3418', descr => 'hash', + proname => 'interval_hash_extended', prorettype => 'int8', + proargtypes => 'interval int8', prosrc => 'interval_hash_extended' }, + +# OID's 1700 - 1799 NUMERIC data type + +{ oid => '1701', descr => 'I/O', + proname => 'numeric_in', prorettype => 'numeric', + proargtypes => 'cstring oid int4', prosrc => 'numeric_in' }, +{ oid => '1702', descr => 'I/O', + proname => 'numeric_out', prorettype => 'cstring', proargtypes => 'numeric', + prosrc => 'numeric_out' }, +{ oid => '2917', descr => 'I/O typmod', + proname => 'numerictypmodin', prorettype => 'int4', proargtypes => '_cstring', + prosrc => 'numerictypmodin' }, +{ oid => '2918', descr => 'I/O typmod', + proname => 'numerictypmodout', prorettype => 'cstring', proargtypes => 'int4', + prosrc => 'numerictypmodout' }, +{ oid => '3157', descr => 'planner support for numeric length coercion', + proname => 'numeric_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'numeric_support' }, +{ oid => '1703', descr => 'adjust numeric to typmod precision/scale', + proname => 'numeric', prosupport => 'numeric_support', + prorettype => 'numeric', proargtypes => 'numeric int4', prosrc => 'numeric' }, +{ oid => '1704', + proname => 'numeric_abs', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_abs' }, +{ oid => '1705', descr => 'absolute value', + proname => 'abs', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_abs' }, +{ oid => '1706', descr => 'sign of value', + proname => 'sign', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_sign' }, +{ oid => '1707', descr => 'value rounded to \'scale\'', + proname => 'round', prorettype => 'numeric', proargtypes => 'numeric int4', + prosrc => 'numeric_round' }, +{ oid => '1708', descr => 'value rounded to \'scale\' of zero', + proname => 'round', prolang => 'sql', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'see system_functions.sql' }, +{ oid => '1709', descr => 'value truncated to \'scale\'', + proname => 'trunc', prorettype => 'numeric', proargtypes => 'numeric int4', + prosrc => 'numeric_trunc' }, +{ oid => '1710', descr => 'value truncated to \'scale\' of zero', + proname => 'trunc', prolang => 'sql', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'see system_functions.sql' }, +{ oid => '1711', descr => 'nearest integer >= value', + proname => 'ceil', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_ceil' }, +{ oid => '2167', descr => 'nearest integer >= value', + proname => 'ceiling', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_ceil' }, +{ oid => '1712', descr => 'nearest integer <= value', + proname => 'floor', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_floor' }, +{ oid => '1718', + proname => 'numeric_eq', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_eq' }, +{ oid => '1719', + proname => 'numeric_ne', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_ne' }, +{ oid => '1720', + proname => 'numeric_gt', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_gt' }, +{ oid => '1721', + proname => 'numeric_ge', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_ge' }, +{ oid => '1722', + proname => 'numeric_lt', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_lt' }, +{ oid => '1723', + proname => 'numeric_le', prorettype => 'bool', + proargtypes => 'numeric numeric', prosrc => 'numeric_le' }, +{ oid => '1724', + proname => 'numeric_add', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_add' }, +{ oid => '1725', + proname => 'numeric_sub', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_sub' }, +{ oid => '1726', + proname => 'numeric_mul', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_mul' }, +{ oid => '1727', + proname => 'numeric_div', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_div' }, +{ oid => '1728', descr => 'modulus', + proname => 'mod', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_mod' }, +{ oid => '1729', + proname => 'numeric_mod', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_mod' }, +{ oid => '5048', descr => 'greatest common divisor', + proname => 'gcd', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_gcd' }, +{ oid => '5049', descr => 'least common multiple', + proname => 'lcm', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_lcm' }, +{ oid => '1730', descr => 'square root', + proname => 'sqrt', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_sqrt' }, +{ oid => '1731', descr => 'square root', + proname => 'numeric_sqrt', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_sqrt' }, +{ oid => '1732', descr => 'natural exponential (e^x)', + proname => 'exp', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_exp' }, +{ oid => '1733', descr => 'natural exponential (e^x)', + proname => 'numeric_exp', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_exp' }, +{ oid => '1734', descr => 'natural logarithm', + proname => 'ln', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_ln' }, +{ oid => '1735', descr => 'natural logarithm', + proname => 'numeric_ln', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_ln' }, +{ oid => '1736', descr => 'logarithm base m of n', + proname => 'log', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_log' }, +{ oid => '1737', descr => 'logarithm base m of n', + proname => 'numeric_log', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_log' }, +{ oid => '1738', descr => 'exponentiation', + proname => 'pow', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_power' }, +{ oid => '2169', descr => 'exponentiation', + proname => 'power', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_power' }, +{ oid => '1739', + proname => 'numeric_power', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_power' }, +{ oid => '3281', descr => 'number of decimal digits in the fractional part', + proname => 'scale', prorettype => 'int4', proargtypes => 'numeric', + prosrc => 'numeric_scale' }, +{ oid => '5042', descr => 'minimum scale needed to represent the value', + proname => 'min_scale', prorettype => 'int4', proargtypes => 'numeric', + prosrc => 'numeric_min_scale' }, +{ oid => '5043', + descr => 'numeric with minimum scale needed to represent the value', + proname => 'trim_scale', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_trim_scale' }, +{ oid => '1740', descr => 'convert int4 to numeric', + proname => 'numeric', proleakproof => 't', prorettype => 'numeric', + proargtypes => 'int4', prosrc => 'int4_numeric' }, +{ oid => '1741', descr => 'base 10 logarithm', + proname => 'log', prolang => 'sql', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'see system_functions.sql' }, +{ oid => '1481', descr => 'base 10 logarithm', + proname => 'log10', prolang => 'sql', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'see system_functions.sql' }, +{ oid => '1742', descr => 'convert float4 to numeric', + proname => 'numeric', proleakproof => 't', prorettype => 'numeric', + proargtypes => 'float4', prosrc => 'float4_numeric' }, +{ oid => '1743', descr => 'convert float8 to numeric', + proname => 'numeric', proleakproof => 't', prorettype => 'numeric', + proargtypes => 'float8', prosrc => 'float8_numeric' }, +{ oid => '1744', descr => 'convert numeric to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'numeric', + prosrc => 'numeric_int4' }, +{ oid => '1745', descr => 'convert numeric to float4', + proname => 'float4', prorettype => 'float4', proargtypes => 'numeric', + prosrc => 'numeric_float4' }, +{ oid => '1746', descr => 'convert numeric to float8', + proname => 'float8', prorettype => 'float8', proargtypes => 'numeric', + prosrc => 'numeric_float8' }, +{ oid => '1973', descr => 'trunc(x/y)', + proname => 'div', prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'numeric_div_trunc' }, +{ oid => '1980', descr => 'trunc(x/y)', + proname => 'numeric_div_trunc', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_div_trunc' }, +{ oid => '2170', descr => 'bucket number of operand in equal-width histogram', + proname => 'width_bucket', prorettype => 'int4', + proargtypes => 'numeric numeric numeric int4', + prosrc => 'width_bucket_numeric' }, + +{ oid => '1747', + proname => 'time_pl_interval', prorettype => 'time', + proargtypes => 'time interval', prosrc => 'time_pl_interval' }, +{ oid => '1748', + proname => 'time_mi_interval', prorettype => 'time', + proargtypes => 'time interval', prosrc => 'time_mi_interval' }, +{ oid => '1749', + proname => 'timetz_pl_interval', prorettype => 'timetz', + proargtypes => 'timetz interval', prosrc => 'timetz_pl_interval' }, +{ oid => '1750', + proname => 'timetz_mi_interval', prorettype => 'timetz', + proargtypes => 'timetz interval', prosrc => 'timetz_mi_interval' }, + +{ oid => '1764', descr => 'increment by one', + proname => 'numeric_inc', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_inc' }, +{ oid => '1766', descr => 'smaller of two', + proname => 'numeric_smaller', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_smaller' }, +{ oid => '1767', descr => 'larger of two', + proname => 'numeric_larger', prorettype => 'numeric', + proargtypes => 'numeric numeric', prosrc => 'numeric_larger' }, +{ oid => '1769', descr => 'less-equal-greater', + proname => 'numeric_cmp', prorettype => 'int4', + proargtypes => 'numeric numeric', prosrc => 'numeric_cmp' }, +{ oid => '3283', descr => 'sort support', + proname => 'numeric_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'numeric_sortsupport' }, +{ oid => '1771', + proname => 'numeric_uminus', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'numeric_uminus' }, +{ oid => '1779', descr => 'convert numeric to int8', + proname => 'int8', prorettype => 'int8', proargtypes => 'numeric', + prosrc => 'numeric_int8' }, +{ oid => '1781', descr => 'convert int8 to numeric', + proname => 'numeric', proleakproof => 't', prorettype => 'numeric', + proargtypes => 'int8', prosrc => 'int8_numeric' }, +{ oid => '1782', descr => 'convert int2 to numeric', + proname => 'numeric', proleakproof => 't', prorettype => 'numeric', + proargtypes => 'int2', prosrc => 'int2_numeric' }, +{ oid => '1783', descr => 'convert numeric to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'numeric', + prosrc => 'numeric_int2' }, +{ oid => '6103', descr => 'convert numeric to pg_lsn', + proname => 'pg_lsn', prorettype => 'pg_lsn', proargtypes => 'numeric', + prosrc => 'numeric_pg_lsn' }, + +{ oid => '3556', descr => 'convert jsonb to boolean', + proname => 'bool', prorettype => 'bool', proargtypes => 'jsonb', + prosrc => 'jsonb_bool' }, +{ oid => '3449', descr => 'convert jsonb to numeric', + proname => 'numeric', prorettype => 'numeric', proargtypes => 'jsonb', + prosrc => 'jsonb_numeric' }, +{ oid => '3450', descr => 'convert jsonb to int2', + proname => 'int2', prorettype => 'int2', proargtypes => 'jsonb', + prosrc => 'jsonb_int2' }, +{ oid => '3451', descr => 'convert jsonb to int4', + proname => 'int4', prorettype => 'int4', proargtypes => 'jsonb', + prosrc => 'jsonb_int4' }, +{ oid => '3452', descr => 'convert jsonb to int8', + proname => 'int8', prorettype => 'int8', proargtypes => 'jsonb', + prosrc => 'jsonb_int8' }, +{ oid => '3453', descr => 'convert jsonb to float4', + proname => 'float4', prorettype => 'float4', proargtypes => 'jsonb', + prosrc => 'jsonb_float4' }, +{ oid => '2580', descr => 'convert jsonb to float8', + proname => 'float8', prorettype => 'float8', proargtypes => 'jsonb', + prosrc => 'jsonb_float8' }, + +# formatting +{ oid => '1770', descr => 'format timestamp with time zone to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'timestamptz text', prosrc => 'timestamptz_to_char' }, +{ oid => '1772', descr => 'format numeric to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'numeric text', prosrc => 'numeric_to_char' }, +{ oid => '1773', descr => 'format int4 to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'int4 text', prosrc => 'int4_to_char' }, +{ oid => '1774', descr => 'format int8 to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'int8 text', prosrc => 'int8_to_char' }, +{ oid => '1775', descr => 'format float4 to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'float4 text', prosrc => 'float4_to_char' }, +{ oid => '1776', descr => 'format float8 to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'float8 text', prosrc => 'float8_to_char' }, +{ oid => '1777', descr => 'convert text to numeric', + proname => 'to_number', provolatile => 's', prorettype => 'numeric', + proargtypes => 'text text', prosrc => 'numeric_to_number' }, +{ oid => '1778', descr => 'convert text to timestamp with time zone', + proname => 'to_timestamp', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'text text', prosrc => 'to_timestamp' }, +{ oid => '1780', descr => 'convert text to date', + proname => 'to_date', provolatile => 's', prorettype => 'date', + proargtypes => 'text text', prosrc => 'to_date' }, +{ oid => '1768', descr => 'format interval to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'interval text', prosrc => 'interval_to_char' }, + +{ oid => '1282', descr => 'quote an identifier for usage in a querystring', + proname => 'quote_ident', prorettype => 'text', proargtypes => 'text', + prosrc => 'quote_ident' }, +{ oid => '1283', descr => 'quote a literal for usage in a querystring', + proname => 'quote_literal', prorettype => 'text', proargtypes => 'text', + prosrc => 'quote_literal' }, +{ oid => '1285', descr => 'quote a data value for usage in a querystring', + proname => 'quote_literal', prolang => 'sql', provolatile => 's', + prorettype => 'text', proargtypes => 'anyelement', + prosrc => 'select pg_catalog.quote_literal($1::pg_catalog.text)' }, +{ oid => '1289', + descr => 'quote a possibly-null literal for usage in a querystring', + proname => 'quote_nullable', proisstrict => 'f', prorettype => 'text', + proargtypes => 'text', prosrc => 'quote_nullable' }, +{ oid => '1290', + descr => 'quote a possibly-null data value for usage in a querystring', + proname => 'quote_nullable', prolang => 'sql', proisstrict => 'f', + provolatile => 's', prorettype => 'text', proargtypes => 'anyelement', + prosrc => 'select pg_catalog.quote_nullable($1::pg_catalog.text)' }, + +{ oid => '1798', descr => 'I/O', + proname => 'oidin', prorettype => 'oid', proargtypes => 'cstring', + prosrc => 'oidin' }, +{ oid => '1799', descr => 'I/O', + proname => 'oidout', prorettype => 'cstring', proargtypes => 'oid', + prosrc => 'oidout' }, + +{ oid => '3058', descr => 'concatenate values', + proname => 'concat', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'text', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', prosrc => 'text_concat' }, +{ oid => '3059', descr => 'concatenate values with separators', + proname => 'concat_ws', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'text', proargtypes => 'text any', + proallargtypes => '{text,any}', proargmodes => '{i,v}', + prosrc => 'text_concat_ws' }, +{ oid => '3060', descr => 'extract the first n characters', + proname => 'left', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'text_left' }, +{ oid => '3061', descr => 'extract the last n characters', + proname => 'right', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'text_right' }, +{ oid => '3062', descr => 'reverse text', + proname => 'reverse', prorettype => 'text', proargtypes => 'text', + prosrc => 'text_reverse' }, +{ oid => '3539', descr => 'format text message', + proname => 'format', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'text', proargtypes => 'text any', + proallargtypes => '{text,any}', proargmodes => '{i,v}', + prosrc => 'text_format' }, +{ oid => '3540', descr => 'format text message', + proname => 'format', proisstrict => 'f', provolatile => 's', + prorettype => 'text', proargtypes => 'text', prosrc => 'text_format_nv' }, + +{ oid => '1810', descr => 'length in bits', + proname => 'bit_length', prolang => 'sql', prorettype => 'int4', + proargtypes => 'bytea', prosrc => 'see system_functions.sql' }, +{ oid => '1811', descr => 'length in bits', + proname => 'bit_length', prolang => 'sql', prorettype => 'int4', + proargtypes => 'text', prosrc => 'see system_functions.sql' }, +{ oid => '1812', descr => 'length in bits', + proname => 'bit_length', prolang => 'sql', prorettype => 'int4', + proargtypes => 'bit', prosrc => 'see system_functions.sql' }, + +# Selectivity estimators for LIKE and related operators +{ oid => '1814', descr => 'restriction selectivity of ILIKE', + proname => 'iclikesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'iclikesel' }, +{ oid => '1815', descr => 'restriction selectivity of NOT ILIKE', + proname => 'icnlikesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'icnlikesel' }, +{ oid => '1816', descr => 'join selectivity of ILIKE', + proname => 'iclikejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'iclikejoinsel' }, +{ oid => '1817', descr => 'join selectivity of NOT ILIKE', + proname => 'icnlikejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'icnlikejoinsel' }, +{ oid => '1818', descr => 'restriction selectivity of regex match', + proname => 'regexeqsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'regexeqsel' }, +{ oid => '1819', descr => 'restriction selectivity of LIKE', + proname => 'likesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'likesel' }, +{ oid => '1820', + descr => 'restriction selectivity of case-insensitive regex match', + proname => 'icregexeqsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'icregexeqsel' }, +{ oid => '1821', descr => 'restriction selectivity of regex non-match', + proname => 'regexnesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'regexnesel' }, +{ oid => '1822', descr => 'restriction selectivity of NOT LIKE', + proname => 'nlikesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'nlikesel' }, +{ oid => '1823', + descr => 'restriction selectivity of case-insensitive regex non-match', + proname => 'icregexnesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'icregexnesel' }, +{ oid => '1824', descr => 'join selectivity of regex match', + proname => 'regexeqjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'regexeqjoinsel' }, +{ oid => '1825', descr => 'join selectivity of LIKE', + proname => 'likejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'likejoinsel' }, +{ oid => '1826', descr => 'join selectivity of case-insensitive regex match', + proname => 'icregexeqjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'icregexeqjoinsel' }, +{ oid => '1827', descr => 'join selectivity of regex non-match', + proname => 'regexnejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'regexnejoinsel' }, +{ oid => '1828', descr => 'join selectivity of NOT LIKE', + proname => 'nlikejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'nlikejoinsel' }, +{ oid => '1829', + descr => 'join selectivity of case-insensitive regex non-match', + proname => 'icregexnejoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'icregexnejoinsel' }, +{ oid => '3437', descr => 'restriction selectivity of exact prefix', + proname => 'prefixsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'prefixsel' }, +{ oid => '3438', descr => 'join selectivity of exact prefix', + proname => 'prefixjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'prefixjoinsel' }, + +# Aggregate-related functions +{ oid => '1830', descr => 'aggregate final function', + proname => 'float8_avg', prorettype => 'float8', proargtypes => '_float8', + prosrc => 'float8_avg' }, +{ oid => '2512', descr => 'aggregate final function', + proname => 'float8_var_pop', prorettype => 'float8', proargtypes => '_float8', + prosrc => 'float8_var_pop' }, +{ oid => '1831', descr => 'aggregate final function', + proname => 'float8_var_samp', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_var_samp' }, +{ oid => '2513', descr => 'aggregate final function', + proname => 'float8_stddev_pop', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_stddev_pop' }, +{ oid => '1832', descr => 'aggregate final function', + proname => 'float8_stddev_samp', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_stddev_samp' }, +{ oid => '1833', descr => 'aggregate transition function', + proname => 'numeric_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal numeric', prosrc => 'numeric_accum' }, +{ oid => '3341', descr => 'aggregate combine function', + proname => 'numeric_combine', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'numeric_combine' }, +{ oid => '2858', descr => 'aggregate transition function', + proname => 'numeric_avg_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal numeric', prosrc => 'numeric_avg_accum' }, +{ oid => '3337', descr => 'aggregate combine function', + proname => 'numeric_avg_combine', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal internal', + prosrc => 'numeric_avg_combine' }, +{ oid => '2740', descr => 'aggregate serial function', + proname => 'numeric_avg_serialize', prorettype => 'bytea', + proargtypes => 'internal', prosrc => 'numeric_avg_serialize' }, +{ oid => '2741', descr => 'aggregate deserial function', + proname => 'numeric_avg_deserialize', prorettype => 'internal', + proargtypes => 'bytea internal', prosrc => 'numeric_avg_deserialize' }, +{ oid => '3335', descr => 'aggregate serial function', + proname => 'numeric_serialize', prorettype => 'bytea', + proargtypes => 'internal', prosrc => 'numeric_serialize' }, +{ oid => '3336', descr => 'aggregate deserial function', + proname => 'numeric_deserialize', prorettype => 'internal', + proargtypes => 'bytea internal', prosrc => 'numeric_deserialize' }, +{ oid => '3548', descr => 'aggregate transition function', + proname => 'numeric_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal numeric', prosrc => 'numeric_accum_inv' }, +{ oid => '1834', descr => 'aggregate transition function', + proname => 'int2_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int2', prosrc => 'int2_accum' }, +{ oid => '1835', descr => 'aggregate transition function', + proname => 'int4_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int4', prosrc => 'int4_accum' }, +{ oid => '1836', descr => 'aggregate transition function', + proname => 'int8_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int8', prosrc => 'int8_accum' }, +{ oid => '3338', descr => 'aggregate combine function', + proname => 'numeric_poly_combine', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal internal', + prosrc => 'numeric_poly_combine' }, +{ oid => '3339', descr => 'aggregate serial function', + proname => 'numeric_poly_serialize', prorettype => 'bytea', + proargtypes => 'internal', prosrc => 'numeric_poly_serialize' }, +{ oid => '3340', descr => 'aggregate deserial function', + proname => 'numeric_poly_deserialize', prorettype => 'internal', + proargtypes => 'bytea internal', prosrc => 'numeric_poly_deserialize' }, +{ oid => '2746', descr => 'aggregate transition function', + proname => 'int8_avg_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int8', prosrc => 'int8_avg_accum' }, +{ oid => '3567', descr => 'aggregate transition function', + proname => 'int2_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int2', prosrc => 'int2_accum_inv' }, +{ oid => '3568', descr => 'aggregate transition function', + proname => 'int4_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int4', prosrc => 'int4_accum_inv' }, +{ oid => '3569', descr => 'aggregate transition function', + proname => 'int8_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int8', prosrc => 'int8_accum_inv' }, +{ oid => '3387', descr => 'aggregate transition function', + proname => 'int8_avg_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal int8', prosrc => 'int8_avg_accum_inv' }, +{ oid => '2785', descr => 'aggregate combine function', + proname => 'int8_avg_combine', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'int8_avg_combine' }, +{ oid => '2786', descr => 'aggregate serial function', + proname => 'int8_avg_serialize', prorettype => 'bytea', + proargtypes => 'internal', prosrc => 'int8_avg_serialize' }, +{ oid => '2787', descr => 'aggregate deserial function', + proname => 'int8_avg_deserialize', prorettype => 'internal', + proargtypes => 'bytea internal', prosrc => 'int8_avg_deserialize' }, +{ oid => '3324', descr => 'aggregate combine function', + proname => 'int4_avg_combine', prorettype => '_int8', + proargtypes => '_int8 _int8', prosrc => 'int4_avg_combine' }, +{ oid => '3178', descr => 'aggregate final function', + proname => 'numeric_sum', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_sum' }, +{ oid => '1837', descr => 'aggregate final function', + proname => 'numeric_avg', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_avg' }, +{ oid => '2514', descr => 'aggregate final function', + proname => 'numeric_var_pop', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_var_pop' }, +{ oid => '1838', descr => 'aggregate final function', + proname => 'numeric_var_samp', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_var_samp' }, +{ oid => '2596', descr => 'aggregate final function', + proname => 'numeric_stddev_pop', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_stddev_pop' }, +{ oid => '1839', descr => 'aggregate final function', + proname => 'numeric_stddev_samp', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_stddev_samp' }, +{ oid => '1840', descr => 'aggregate transition function', + proname => 'int2_sum', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int8 int2', prosrc => 'int2_sum' }, +{ oid => '1841', descr => 'aggregate transition function', + proname => 'int4_sum', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int8 int4', prosrc => 'int4_sum' }, +{ oid => '1842', descr => 'aggregate transition function', + proname => 'int8_sum', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'numeric int8', prosrc => 'int8_sum' }, +{ oid => '3388', descr => 'aggregate final function', + proname => 'numeric_poly_sum', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_poly_sum' }, +{ oid => '3389', descr => 'aggregate final function', + proname => 'numeric_poly_avg', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'internal', prosrc => 'numeric_poly_avg' }, +{ oid => '3390', descr => 'aggregate final function', + proname => 'numeric_poly_var_pop', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'internal', + prosrc => 'numeric_poly_var_pop' }, +{ oid => '3391', descr => 'aggregate final function', + proname => 'numeric_poly_var_samp', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'internal', + prosrc => 'numeric_poly_var_samp' }, +{ oid => '3392', descr => 'aggregate final function', + proname => 'numeric_poly_stddev_pop', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'internal', + prosrc => 'numeric_poly_stddev_pop' }, +{ oid => '3393', descr => 'aggregate final function', + proname => 'numeric_poly_stddev_samp', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'internal', + prosrc => 'numeric_poly_stddev_samp' }, + +{ oid => '1843', descr => 'aggregate transition function', + proname => 'interval_accum', prorettype => '_interval', + proargtypes => '_interval interval', prosrc => 'interval_accum' }, +{ oid => '3325', descr => 'aggregate combine function', + proname => 'interval_combine', prorettype => '_interval', + proargtypes => '_interval _interval', prosrc => 'interval_combine' }, +{ oid => '3549', descr => 'aggregate transition function', + proname => 'interval_accum_inv', prorettype => '_interval', + proargtypes => '_interval interval', prosrc => 'interval_accum_inv' }, +{ oid => '1844', descr => 'aggregate final function', + proname => 'interval_avg', prorettype => 'interval', + proargtypes => '_interval', prosrc => 'interval_avg' }, +{ oid => '1962', descr => 'aggregate transition function', + proname => 'int2_avg_accum', prorettype => '_int8', + proargtypes => '_int8 int2', prosrc => 'int2_avg_accum' }, +{ oid => '1963', descr => 'aggregate transition function', + proname => 'int4_avg_accum', prorettype => '_int8', + proargtypes => '_int8 int4', prosrc => 'int4_avg_accum' }, +{ oid => '3570', descr => 'aggregate transition function', + proname => 'int2_avg_accum_inv', prorettype => '_int8', + proargtypes => '_int8 int2', prosrc => 'int2_avg_accum_inv' }, +{ oid => '3571', descr => 'aggregate transition function', + proname => 'int4_avg_accum_inv', prorettype => '_int8', + proargtypes => '_int8 int4', prosrc => 'int4_avg_accum_inv' }, +{ oid => '1964', descr => 'aggregate final function', + proname => 'int8_avg', prorettype => 'numeric', proargtypes => '_int8', + prosrc => 'int8_avg' }, +{ oid => '3572', descr => 'aggregate final function', + proname => 'int2int4_sum', prorettype => 'int8', proargtypes => '_int8', + prosrc => 'int2int4_sum' }, +{ oid => '2805', descr => 'aggregate transition function', + proname => 'int8inc_float8_float8', prorettype => 'int8', + proargtypes => 'int8 float8 float8', prosrc => 'int8inc_float8_float8' }, +{ oid => '2806', descr => 'aggregate transition function', + proname => 'float8_regr_accum', prorettype => '_float8', + proargtypes => '_float8 float8 float8', prosrc => 'float8_regr_accum' }, +{ oid => '3342', descr => 'aggregate combine function', + proname => 'float8_regr_combine', prorettype => '_float8', + proargtypes => '_float8 _float8', prosrc => 'float8_regr_combine' }, +{ oid => '2807', descr => 'aggregate final function', + proname => 'float8_regr_sxx', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_sxx' }, +{ oid => '2808', descr => 'aggregate final function', + proname => 'float8_regr_syy', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_syy' }, +{ oid => '2809', descr => 'aggregate final function', + proname => 'float8_regr_sxy', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_sxy' }, +{ oid => '2810', descr => 'aggregate final function', + proname => 'float8_regr_avgx', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_avgx' }, +{ oid => '2811', descr => 'aggregate final function', + proname => 'float8_regr_avgy', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_avgy' }, +{ oid => '2812', descr => 'aggregate final function', + proname => 'float8_regr_r2', prorettype => 'float8', proargtypes => '_float8', + prosrc => 'float8_regr_r2' }, +{ oid => '2813', descr => 'aggregate final function', + proname => 'float8_regr_slope', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_slope' }, +{ oid => '2814', descr => 'aggregate final function', + proname => 'float8_regr_intercept', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_regr_intercept' }, +{ oid => '2815', descr => 'aggregate final function', + proname => 'float8_covar_pop', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_covar_pop' }, +{ oid => '2816', descr => 'aggregate final function', + proname => 'float8_covar_samp', prorettype => 'float8', + proargtypes => '_float8', prosrc => 'float8_covar_samp' }, +{ oid => '2817', descr => 'aggregate final function', + proname => 'float8_corr', prorettype => 'float8', proargtypes => '_float8', + prosrc => 'float8_corr' }, + +{ oid => '3535', descr => 'aggregate transition function', + proname => 'string_agg_transfn', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal text text', prosrc => 'string_agg_transfn' }, +{ oid => '3536', descr => 'aggregate final function', + proname => 'string_agg_finalfn', proisstrict => 'f', prorettype => 'text', + proargtypes => 'internal', prosrc => 'string_agg_finalfn' }, +{ oid => '3538', descr => 'concatenate aggregate input into a string', + proname => 'string_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'text', proargtypes => 'text text', + prosrc => 'aggregate_dummy' }, +{ oid => '3543', descr => 'aggregate transition function', + proname => 'bytea_string_agg_transfn', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal bytea bytea', + prosrc => 'bytea_string_agg_transfn' }, +{ oid => '3544', descr => 'aggregate final function', + proname => 'bytea_string_agg_finalfn', proisstrict => 'f', + prorettype => 'bytea', proargtypes => 'internal', + prosrc => 'bytea_string_agg_finalfn' }, +{ oid => '3545', descr => 'concatenate aggregate input into a bytea', + proname => 'string_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'aggregate_dummy' }, + +# To ASCII conversion +{ oid => '1845', descr => 'encode text from DB encoding to ASCII text', + proname => 'to_ascii', prorettype => 'text', proargtypes => 'text', + prosrc => 'to_ascii_default' }, +{ oid => '1846', descr => 'encode text from encoding to ASCII text', + proname => 'to_ascii', prorettype => 'text', proargtypes => 'text int4', + prosrc => 'to_ascii_enc' }, +{ oid => '1847', descr => 'encode text from encoding to ASCII text', + proname => 'to_ascii', prorettype => 'text', proargtypes => 'text name', + prosrc => 'to_ascii_encname' }, + +{ oid => '1848', + proname => 'interval_pl_time', prolang => 'sql', prorettype => 'time', + proargtypes => 'interval time', prosrc => 'see system_functions.sql' }, + +{ oid => '1850', + proname => 'int28eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28eq' }, +{ oid => '1851', + proname => 'int28ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28ne' }, +{ oid => '1852', + proname => 'int28lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28lt' }, +{ oid => '1853', + proname => 'int28gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28gt' }, +{ oid => '1854', + proname => 'int28le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28le' }, +{ oid => '1855', + proname => 'int28ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int2 int8', prosrc => 'int28ge' }, + +{ oid => '1856', + proname => 'int82eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82eq' }, +{ oid => '1857', + proname => 'int82ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82ne' }, +{ oid => '1858', + proname => 'int82lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82lt' }, +{ oid => '1859', + proname => 'int82gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82gt' }, +{ oid => '1860', + proname => 'int82le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82le' }, +{ oid => '1861', + proname => 'int82ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int8 int2', prosrc => 'int82ge' }, + +{ oid => '1892', + proname => 'int2and', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2and' }, +{ oid => '1893', + proname => 'int2or', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2or' }, +{ oid => '1894', + proname => 'int2xor', prorettype => 'int2', proargtypes => 'int2 int2', + prosrc => 'int2xor' }, +{ oid => '1895', + proname => 'int2not', prorettype => 'int2', proargtypes => 'int2', + prosrc => 'int2not' }, +{ oid => '1896', + proname => 'int2shl', prorettype => 'int2', proargtypes => 'int2 int4', + prosrc => 'int2shl' }, +{ oid => '1897', + proname => 'int2shr', prorettype => 'int2', proargtypes => 'int2 int4', + prosrc => 'int2shr' }, + +{ oid => '1898', + proname => 'int4and', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4and' }, +{ oid => '1899', + proname => 'int4or', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4or' }, +{ oid => '1900', + proname => 'int4xor', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4xor' }, +{ oid => '1901', + proname => 'int4not', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4not' }, +{ oid => '1902', + proname => 'int4shl', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4shl' }, +{ oid => '1903', + proname => 'int4shr', prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'int4shr' }, + +{ oid => '1904', + proname => 'int8and', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8and' }, +{ oid => '1905', + proname => 'int8or', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8or' }, +{ oid => '1906', + proname => 'int8xor', prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'int8xor' }, +{ oid => '1907', + proname => 'int8not', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8not' }, +{ oid => '1908', + proname => 'int8shl', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int8shl' }, +{ oid => '1909', + proname => 'int8shr', prorettype => 'int8', proargtypes => 'int8 int4', + prosrc => 'int8shr' }, + +{ oid => '1910', + proname => 'int8up', prorettype => 'int8', proargtypes => 'int8', + prosrc => 'int8up' }, +{ oid => '1911', + proname => 'int2up', prorettype => 'int2', proargtypes => 'int2', + prosrc => 'int2up' }, +{ oid => '1912', + proname => 'int4up', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'int4up' }, +{ oid => '1913', + proname => 'float4up', prorettype => 'float4', proargtypes => 'float4', + prosrc => 'float4up' }, +{ oid => '1914', + proname => 'float8up', prorettype => 'float8', proargtypes => 'float8', + prosrc => 'float8up' }, +{ oid => '1915', + proname => 'numeric_uplus', prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'numeric_uplus' }, + +{ oid => '1922', descr => 'user privilege on relation by username, rel name', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', prosrc => 'has_table_privilege_name_name' }, +{ oid => '1923', descr => 'user privilege on relation by username, rel oid', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_table_privilege_name_id' }, +{ oid => '1924', descr => 'user privilege on relation by user oid, rel name', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_table_privilege_id_name' }, +{ oid => '1925', descr => 'user privilege on relation by user oid, rel oid', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_table_privilege_id_id' }, +{ oid => '1926', descr => 'current user privilege on relation by rel name', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_table_privilege_name' }, +{ oid => '1927', descr => 'current user privilege on relation by rel oid', + proname => 'has_table_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_table_privilege_id' }, + +{ oid => '2181', descr => 'user privilege on sequence by username, seq name', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', + prosrc => 'has_sequence_privilege_name_name' }, +{ oid => '2182', descr => 'user privilege on sequence by username, seq oid', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_sequence_privilege_name_id' }, +{ oid => '2183', descr => 'user privilege on sequence by user oid, seq name', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_sequence_privilege_id_name' }, +{ oid => '2184', descr => 'user privilege on sequence by user oid, seq oid', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_sequence_privilege_id_id' }, +{ oid => '2185', descr => 'current user privilege on sequence by seq name', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_sequence_privilege_name' }, +{ oid => '2186', descr => 'current user privilege on sequence by seq oid', + proname => 'has_sequence_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_sequence_privilege_id' }, + +{ oid => '3012', + descr => 'user privilege on column by username, rel name, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text text', + prosrc => 'has_column_privilege_name_name_name' }, +{ oid => '3013', + descr => 'user privilege on column by username, rel name, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text int2 text', + prosrc => 'has_column_privilege_name_name_attnum' }, +{ oid => '3014', + descr => 'user privilege on column by username, rel oid, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text text', + prosrc => 'has_column_privilege_name_id_name' }, +{ oid => '3015', + descr => 'user privilege on column by username, rel oid, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid int2 text', + prosrc => 'has_column_privilege_name_id_attnum' }, +{ oid => '3016', + descr => 'user privilege on column by user oid, rel name, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text text', + prosrc => 'has_column_privilege_id_name_name' }, +{ oid => '3017', + descr => 'user privilege on column by user oid, rel name, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text int2 text', + prosrc => 'has_column_privilege_id_name_attnum' }, +{ oid => '3018', + descr => 'user privilege on column by user oid, rel oid, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text text', + prosrc => 'has_column_privilege_id_id_name' }, +{ oid => '3019', + descr => 'user privilege on column by user oid, rel oid, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid int2 text', + prosrc => 'has_column_privilege_id_id_attnum' }, +{ oid => '3020', + descr => 'current user privilege on column by rel name, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text text', prosrc => 'has_column_privilege_name_name' }, +{ oid => '3021', + descr => 'current user privilege on column by rel name, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text int2 text', + prosrc => 'has_column_privilege_name_attnum' }, +{ oid => '3022', + descr => 'current user privilege on column by rel oid, col name', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_column_privilege_id_name' }, +{ oid => '3023', + descr => 'current user privilege on column by rel oid, col attnum', + proname => 'has_column_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid int2 text', prosrc => 'has_column_privilege_id_attnum' }, + +{ oid => '3024', + descr => 'user privilege on any column by username, rel name', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'name text text', + prosrc => 'has_any_column_privilege_name_name' }, +{ oid => '3025', descr => 'user privilege on any column by username, rel oid', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'name oid text', + prosrc => 'has_any_column_privilege_name_id' }, +{ oid => '3026', + descr => 'user privilege on any column by user oid, rel name', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text text', + prosrc => 'has_any_column_privilege_id_name' }, +{ oid => '3027', descr => 'user privilege on any column by user oid, rel oid', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid oid text', + prosrc => 'has_any_column_privilege_id_id' }, +{ oid => '3028', descr => 'current user privilege on any column by rel name', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'text text', + prosrc => 'has_any_column_privilege_name' }, +{ oid => '3029', descr => 'current user privilege on any column by rel oid', + proname => 'has_any_column_privilege', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text', + prosrc => 'has_any_column_privilege_id' }, + +{ oid => '3355', descr => 'I/O', + proname => 'pg_ndistinct_in', prorettype => 'pg_ndistinct', + proargtypes => 'cstring', prosrc => 'pg_ndistinct_in' }, +{ oid => '3356', descr => 'I/O', + proname => 'pg_ndistinct_out', prorettype => 'cstring', + proargtypes => 'pg_ndistinct', prosrc => 'pg_ndistinct_out' }, +{ oid => '3357', descr => 'I/O', + proname => 'pg_ndistinct_recv', provolatile => 's', + prorettype => 'pg_ndistinct', proargtypes => 'internal', + prosrc => 'pg_ndistinct_recv' }, +{ oid => '3358', descr => 'I/O', + proname => 'pg_ndistinct_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'pg_ndistinct', prosrc => 'pg_ndistinct_send' }, + +{ oid => '3404', descr => 'I/O', + proname => 'pg_dependencies_in', prorettype => 'pg_dependencies', + proargtypes => 'cstring', prosrc => 'pg_dependencies_in' }, +{ oid => '3405', descr => 'I/O', + proname => 'pg_dependencies_out', prorettype => 'cstring', + proargtypes => 'pg_dependencies', prosrc => 'pg_dependencies_out' }, +{ oid => '3406', descr => 'I/O', + proname => 'pg_dependencies_recv', provolatile => 's', + prorettype => 'pg_dependencies', proargtypes => 'internal', + prosrc => 'pg_dependencies_recv' }, +{ oid => '3407', descr => 'I/O', + proname => 'pg_dependencies_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'pg_dependencies', prosrc => 'pg_dependencies_send' }, + +{ oid => '5018', descr => 'I/O', + proname => 'pg_mcv_list_in', prorettype => 'pg_mcv_list', + proargtypes => 'cstring', prosrc => 'pg_mcv_list_in' }, +{ oid => '5019', descr => 'I/O', + proname => 'pg_mcv_list_out', prorettype => 'cstring', + proargtypes => 'pg_mcv_list', prosrc => 'pg_mcv_list_out' }, +{ oid => '5020', descr => 'I/O', + proname => 'pg_mcv_list_recv', provolatile => 's', + prorettype => 'pg_mcv_list', proargtypes => 'internal', + prosrc => 'pg_mcv_list_recv' }, +{ oid => '5021', descr => 'I/O', + proname => 'pg_mcv_list_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'pg_mcv_list', prosrc => 'pg_mcv_list_send' }, + +{ oid => '3427', descr => 'details about MCV list items', + proname => 'pg_mcv_list_items', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'pg_mcv_list', + proallargtypes => '{pg_mcv_list,int4,_text,_bool,float8,float8}', + proargmodes => '{i,o,o,o,o,o}', + proargnames => '{mcv_list,index,values,nulls,frequency,base_frequency}', + prosrc => 'pg_stats_ext_mcvlist_items' }, + +{ oid => '1928', descr => 'statistics: number of scans done for table/index', + proname => 'pg_stat_get_numscans', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_numscans' }, +{ oid => '1929', descr => 'statistics: number of tuples read by seqscan', + proname => 'pg_stat_get_tuples_returned', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_returned' }, +{ oid => '1930', descr => 'statistics: number of tuples fetched by idxscan', + proname => 'pg_stat_get_tuples_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_fetched' }, +{ oid => '1931', descr => 'statistics: number of tuples inserted', + proname => 'pg_stat_get_tuples_inserted', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_inserted' }, +{ oid => '1932', descr => 'statistics: number of tuples updated', + proname => 'pg_stat_get_tuples_updated', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_updated' }, +{ oid => '1933', descr => 'statistics: number of tuples deleted', + proname => 'pg_stat_get_tuples_deleted', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_deleted' }, +{ oid => '1972', descr => 'statistics: number of tuples hot updated', + proname => 'pg_stat_get_tuples_hot_updated', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_tuples_hot_updated' }, +{ oid => '2878', descr => 'statistics: number of live tuples', + proname => 'pg_stat_get_live_tuples', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_live_tuples' }, +{ oid => '2879', descr => 'statistics: number of dead tuples', + proname => 'pg_stat_get_dead_tuples', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_dead_tuples' }, +{ oid => '3177', + descr => 'statistics: number of tuples changed since last analyze', + proname => 'pg_stat_get_mod_since_analyze', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_mod_since_analyze' }, +{ oid => '5053', + descr => 'statistics: number of tuples inserted since last vacuum', + proname => 'pg_stat_get_ins_since_vacuum', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_ins_since_vacuum' }, +{ oid => '1934', descr => 'statistics: number of blocks fetched', + proname => 'pg_stat_get_blocks_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_blocks_fetched' }, +{ oid => '1935', descr => 'statistics: number of blocks found in cache', + proname => 'pg_stat_get_blocks_hit', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_blocks_hit' }, +{ oid => '2781', descr => 'statistics: last manual vacuum time for a table', + proname => 'pg_stat_get_last_vacuum_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_vacuum_time' }, +{ oid => '2782', descr => 'statistics: last auto vacuum time for a table', + proname => 'pg_stat_get_last_autovacuum_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_autovacuum_time' }, +{ oid => '2783', descr => 'statistics: last manual analyze time for a table', + proname => 'pg_stat_get_last_analyze_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_analyze_time' }, +{ oid => '2784', descr => 'statistics: last auto analyze time for a table', + proname => 'pg_stat_get_last_autoanalyze_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_last_autoanalyze_time' }, +{ oid => '3054', descr => 'statistics: number of manual vacuums for a table', + proname => 'pg_stat_get_vacuum_count', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_vacuum_count' }, +{ oid => '3055', descr => 'statistics: number of auto vacuums for a table', + proname => 'pg_stat_get_autovacuum_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_autovacuum_count' }, +{ oid => '3056', descr => 'statistics: number of manual analyzes for a table', + proname => 'pg_stat_get_analyze_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_analyze_count' }, +{ oid => '3057', descr => 'statistics: number of auto analyzes for a table', + proname => 'pg_stat_get_autoanalyze_count', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_autoanalyze_count' }, +{ oid => '1936', descr => 'statistics: currently active backend IDs', + proname => 'pg_stat_get_backend_idset', prorows => '100', proretset => 't', + provolatile => 's', proparallel => 'r', prorettype => 'int4', + proargtypes => '', prosrc => 'pg_stat_get_backend_idset' }, +{ oid => '2022', + descr => 'statistics: information about currently active backends', + proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => 'int4', + proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,text,numeric,text,bool,text,bool,int4,int8}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid,query_id}', + prosrc => 'pg_stat_get_activity' }, +{ oid => '3318', + descr => 'statistics: information about progress of backends running maintenance command', + proname => 'pg_stat_get_progress_info', prorows => '100', proretset => 't', + provolatile => 's', proparallel => 'r', prorettype => 'record', + proargtypes => 'text', + proallargtypes => '{text,int4,oid,oid,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8,int8}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10,param11,param12,param13,param14,param15,param16,param17,param18,param19,param20}', + prosrc => 'pg_stat_get_progress_info' }, +{ oid => '3099', + descr => 'statistics: information about currently active replication', + proname => 'pg_stat_get_wal_senders', prorows => '10', proisstrict => 'f', + proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{int4,text,pg_lsn,pg_lsn,pg_lsn,pg_lsn,interval,interval,interval,int4,text,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state,reply_time}', + prosrc => 'pg_stat_get_wal_senders' }, +{ oid => '3317', descr => 'statistics: information about WAL receiver', + proname => 'pg_stat_get_wal_receiver', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => '', + proallargtypes => '{int4,text,pg_lsn,int4,pg_lsn,pg_lsn,int4,timestamptz,timestamptz,pg_lsn,timestamptz,text,text,int4,text}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{pid,status,receive_start_lsn,receive_start_tli,written_lsn,flushed_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,sender_host,sender_port,conninfo}', + prosrc => 'pg_stat_get_wal_receiver' }, +{ oid => '6169', descr => 'statistics: information about replication slot', + proname => 'pg_stat_get_replication_slot', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => 'text', + proallargtypes => '{text,text,int8,int8,int8,int8,int8,int8,int8,int8,timestamptz}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{slot_name,slot_name,spill_txns,spill_count,spill_bytes,stream_txns,stream_count,stream_bytes,total_txns,total_bytes,stats_reset}', + prosrc => 'pg_stat_get_replication_slot' }, + +{ oid => '6230', descr => 'statistics: check if a stats object exists', + proname => 'pg_stat_have_stats', provolatile => 'v', proparallel => 'r', + prorettype => 'bool', proargtypes => 'text oid oid', + prosrc => 'pg_stat_have_stats' }, + +{ oid => '6231', descr => 'statistics: information about subscription stats', + proname => 'pg_stat_get_subscription_stats', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => 'oid', + proallargtypes => '{oid,oid,int8,int8,timestamptz}', + proargmodes => '{i,o,o,o,o}', + proargnames => '{subid,subid,apply_error_count,sync_error_count,stats_reset}', + prosrc => 'pg_stat_get_subscription_stats' }, +{ oid => '6118', descr => 'statistics: information about subscription', + proname => 'pg_stat_get_subscription', prorows => '10', proisstrict => 'f', + proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => 'oid', + proallargtypes => '{oid,oid,oid,int4,pg_lsn,timestamptz,timestamptz,pg_lsn,timestamptz}', + proargmodes => '{i,o,o,o,o,o,o,o,o}', + proargnames => '{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}', + prosrc => 'pg_stat_get_subscription' }, +{ oid => '2026', descr => 'statistics: current backend PID', + proname => 'pg_backend_pid', provolatile => 's', proparallel => 'r', + prorettype => 'int4', proargtypes => '', prosrc => 'pg_backend_pid' }, +{ oid => '1937', descr => 'statistics: PID of backend', + proname => 'pg_stat_get_backend_pid', provolatile => 's', proparallel => 'r', + prorettype => 'int4', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_pid' }, +{ oid => '1938', descr => 'statistics: database ID of backend', + proname => 'pg_stat_get_backend_dbid', provolatile => 's', proparallel => 'r', + prorettype => 'oid', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_dbid' }, +{ oid => '1939', descr => 'statistics: user ID of backend', + proname => 'pg_stat_get_backend_userid', provolatile => 's', + proparallel => 'r', prorettype => 'oid', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_userid' }, +{ oid => '1940', descr => 'statistics: current query of backend', + proname => 'pg_stat_get_backend_activity', provolatile => 's', + proparallel => 'r', prorettype => 'text', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_activity' }, +{ oid => '2788', + descr => 'statistics: wait event type on which backend is currently waiting', + proname => 'pg_stat_get_backend_wait_event_type', provolatile => 's', + proparallel => 'r', prorettype => 'text', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_wait_event_type' }, +{ oid => '2853', + descr => 'statistics: wait event on which backend is currently waiting', + proname => 'pg_stat_get_backend_wait_event', provolatile => 's', + proparallel => 'r', prorettype => 'text', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_wait_event' }, +{ oid => '2094', + descr => 'statistics: start time for current query of backend', + proname => 'pg_stat_get_backend_activity_start', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_activity_start' }, +{ oid => '2857', + descr => 'statistics: start time for backend\'s current transaction', + proname => 'pg_stat_get_backend_xact_start', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_xact_start' }, +{ oid => '1391', + descr => 'statistics: start time for current backend session', + proname => 'pg_stat_get_backend_start', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_start' }, +{ oid => '1392', + descr => 'statistics: address of client connected to backend', + proname => 'pg_stat_get_backend_client_addr', provolatile => 's', + proparallel => 'r', prorettype => 'inet', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_client_addr' }, +{ oid => '1393', + descr => 'statistics: port number of client connected to backend', + proname => 'pg_stat_get_backend_client_port', provolatile => 's', + proparallel => 'r', prorettype => 'int4', proargtypes => 'int4', + prosrc => 'pg_stat_get_backend_client_port' }, +{ oid => '1941', descr => 'statistics: number of backends in database', + proname => 'pg_stat_get_db_numbackends', provolatile => 's', + proparallel => 'r', prorettype => 'int4', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_numbackends' }, +{ oid => '1942', descr => 'statistics: transactions committed', + proname => 'pg_stat_get_db_xact_commit', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_xact_commit' }, +{ oid => '1943', descr => 'statistics: transactions rolled back', + proname => 'pg_stat_get_db_xact_rollback', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_xact_rollback' }, +{ oid => '1944', descr => 'statistics: blocks fetched for database', + proname => 'pg_stat_get_db_blocks_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_blocks_fetched' }, +{ oid => '1945', descr => 'statistics: blocks found in cache for database', + proname => 'pg_stat_get_db_blocks_hit', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_blocks_hit' }, +{ oid => '2758', descr => 'statistics: tuples returned for database', + proname => 'pg_stat_get_db_tuples_returned', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_tuples_returned' }, +{ oid => '2759', descr => 'statistics: tuples fetched for database', + proname => 'pg_stat_get_db_tuples_fetched', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_tuples_fetched' }, +{ oid => '2760', descr => 'statistics: tuples inserted in database', + proname => 'pg_stat_get_db_tuples_inserted', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_tuples_inserted' }, +{ oid => '2761', descr => 'statistics: tuples updated in database', + proname => 'pg_stat_get_db_tuples_updated', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_tuples_updated' }, +{ oid => '2762', descr => 'statistics: tuples deleted in database', + proname => 'pg_stat_get_db_tuples_deleted', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_tuples_deleted' }, +{ oid => '3065', + descr => 'statistics: recovery conflicts in database caused by drop tablespace', + proname => 'pg_stat_get_db_conflict_tablespace', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_tablespace' }, +{ oid => '3066', + descr => 'statistics: recovery conflicts in database caused by relation lock', + proname => 'pg_stat_get_db_conflict_lock', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_lock' }, +{ oid => '3067', + descr => 'statistics: recovery conflicts in database caused by snapshot expiry', + proname => 'pg_stat_get_db_conflict_snapshot', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_snapshot' }, +{ oid => '3068', + descr => 'statistics: recovery conflicts in database caused by shared buffer pin', + proname => 'pg_stat_get_db_conflict_bufferpin', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_bufferpin' }, +{ oid => '3069', + descr => 'statistics: recovery conflicts in database caused by buffer deadlock', + proname => 'pg_stat_get_db_conflict_startup_deadlock', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_startup_deadlock' }, +{ oid => '3070', descr => 'statistics: recovery conflicts in database', + proname => 'pg_stat_get_db_conflict_all', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_conflict_all' }, +{ oid => '3152', descr => 'statistics: deadlocks detected in database', + proname => 'pg_stat_get_db_deadlocks', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_deadlocks' }, +{ oid => '3426', + descr => 'statistics: checksum failures detected in database', + proname => 'pg_stat_get_db_checksum_failures', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_checksum_failures' }, +{ oid => '3428', + descr => 'statistics: when last checksum failure was detected in database', + proname => 'pg_stat_get_db_checksum_last_failure', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_checksum_last_failure' }, +{ oid => '3074', descr => 'statistics: last reset for a database', + proname => 'pg_stat_get_db_stat_reset_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_stat_reset_time' }, +{ oid => '3150', descr => 'statistics: number of temporary files written', + proname => 'pg_stat_get_db_temp_files', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_temp_files' }, +{ oid => '3151', + descr => 'statistics: number of bytes in temporary files written', + proname => 'pg_stat_get_db_temp_bytes', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_temp_bytes' }, +{ oid => '2844', descr => 'statistics: block read time, in milliseconds', + proname => 'pg_stat_get_db_blk_read_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_blk_read_time' }, +{ oid => '2845', descr => 'statistics: block write time, in milliseconds', + proname => 'pg_stat_get_db_blk_write_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_blk_write_time' }, +{ oid => '6185', descr => 'statistics: session time, in milliseconds', + proname => 'pg_stat_get_db_session_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_session_time' }, +{ oid => '6186', descr => 'statistics: session active time, in milliseconds', + proname => 'pg_stat_get_db_active_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_active_time' }, +{ oid => '6187', + descr => 'statistics: session idle in transaction time, in milliseconds', + proname => 'pg_stat_get_db_idle_in_transaction_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_idle_in_transaction_time' }, +{ oid => '6188', descr => 'statistics: total number of sessions', + proname => 'pg_stat_get_db_sessions', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions' }, +{ oid => '6189', + descr => 'statistics: number of sessions disconnected by the client closing the network connection', + proname => 'pg_stat_get_db_sessions_abandoned', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_abandoned' }, +{ oid => '6190', + descr => 'statistics: number of sessions disconnected by fatal errors', + proname => 'pg_stat_get_db_sessions_fatal', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_fatal' }, +{ oid => '6191', + descr => 'statistics: number of sessions killed by administrative action', + proname => 'pg_stat_get_db_sessions_killed', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_db_sessions_killed' }, +{ oid => '3195', descr => 'statistics: information about WAL archiver', + proname => 'pg_stat_get_archiver', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => '', + proallargtypes => '{int8,text,timestamptz,int8,text,timestamptz,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o}', + proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}', + prosrc => 'pg_stat_get_archiver' }, +{ oid => '2769', + descr => 'statistics: number of timed checkpoints started by the bgwriter', + proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' }, +{ oid => '2770', + descr => 'statistics: number of backend requested checkpoints started by the bgwriter', + proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' }, +{ oid => '2771', + descr => 'statistics: number of buffers written by the bgwriter during checkpoints', + proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' }, +{ oid => '2772', + descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers', + proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_buf_written_clean' }, +{ oid => '2773', + descr => 'statistics: number of times the bgwriter stopped processing when it had written too many buffers while cleaning', + proname => 'pg_stat_get_bgwriter_maxwritten_clean', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_maxwritten_clean' }, +{ oid => '3075', descr => 'statistics: last reset for the bgwriter', + proname => 'pg_stat_get_bgwriter_stat_reset_time', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => '', + prosrc => 'pg_stat_get_bgwriter_stat_reset_time' }, +{ oid => '3160', + descr => 'statistics: checkpoint time spent writing buffers to disk, in milliseconds', + proname => 'pg_stat_get_checkpoint_write_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => '', + prosrc => 'pg_stat_get_checkpoint_write_time' }, +{ oid => '3161', + descr => 'statistics: checkpoint time spent synchronizing buffers to disk, in milliseconds', + proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => '', + prosrc => 'pg_stat_get_checkpoint_sync_time' }, +{ oid => '2775', descr => 'statistics: number of buffers written by backends', + proname => 'pg_stat_get_buf_written_backend', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_buf_written_backend' }, +{ oid => '3063', + descr => 'statistics: number of backend buffer writes that did their own fsync', + proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => '', + prosrc => 'pg_stat_get_buf_fsync_backend' }, +{ oid => '2859', descr => 'statistics: number of buffer allocations', + proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' }, + +{ oid => '1136', descr => 'statistics: information about WAL activity', + proname => 'pg_stat_get_wal', proisstrict => 'f', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => '', + proallargtypes => '{int8,int8,numeric,int8,int8,int8,float8,float8,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o}', + proargnames => '{wal_records,wal_fpi,wal_bytes,wal_buffers_full,wal_write,wal_sync,wal_write_time,wal_sync_time,stats_reset}', + prosrc => 'pg_stat_get_wal' }, +{ oid => '6248', descr => 'statistics: information about WAL prefetching', + proname => 'pg_stat_get_recovery_prefetch', prorows => '1', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{timestamptz,int8,int8,int8,int8,int8,int8,int4,int4,int4}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o}', + proargnames => '{stats_reset,prefetch,hit,skip_init,skip_new,skip_fpw,skip_rep,wal_distance,block_distance,io_depth}', + prosrc => 'pg_stat_get_recovery_prefetch' }, + +{ oid => '2306', descr => 'statistics: information about SLRU caches', + proname => 'pg_stat_get_slru', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8,int8,int8,int8,int8,int8,int8,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o}', + proargnames => '{name,blks_zeroed,blks_hit,blks_read,blks_written,blks_exists,flushes,truncates,stats_reset}', + prosrc => 'pg_stat_get_slru' }, + +{ oid => '2978', descr => 'statistics: number of function calls', + proname => 'pg_stat_get_function_calls', provolatile => 's', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_function_calls' }, +{ oid => '2979', + descr => 'statistics: total execution time of function, in milliseconds', + proname => 'pg_stat_get_function_total_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_function_total_time' }, +{ oid => '2980', + descr => 'statistics: self execution time of function, in milliseconds', + proname => 'pg_stat_get_function_self_time', provolatile => 's', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_function_self_time' }, + +{ oid => '3037', + descr => 'statistics: number of scans done for table/index in current transaction', + proname => 'pg_stat_get_xact_numscans', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_numscans' }, +{ oid => '3038', + descr => 'statistics: number of tuples read by seqscan in current transaction', + proname => 'pg_stat_get_xact_tuples_returned', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_returned' }, +{ oid => '3039', + descr => 'statistics: number of tuples fetched by idxscan in current transaction', + proname => 'pg_stat_get_xact_tuples_fetched', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_fetched' }, +{ oid => '3040', + descr => 'statistics: number of tuples inserted in current transaction', + proname => 'pg_stat_get_xact_tuples_inserted', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_inserted' }, +{ oid => '3041', + descr => 'statistics: number of tuples updated in current transaction', + proname => 'pg_stat_get_xact_tuples_updated', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_updated' }, +{ oid => '3042', + descr => 'statistics: number of tuples deleted in current transaction', + proname => 'pg_stat_get_xact_tuples_deleted', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_deleted' }, +{ oid => '3043', + descr => 'statistics: number of tuples hot updated in current transaction', + proname => 'pg_stat_get_xact_tuples_hot_updated', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_tuples_hot_updated' }, +{ oid => '3044', + descr => 'statistics: number of blocks fetched in current transaction', + proname => 'pg_stat_get_xact_blocks_fetched', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_blocks_fetched' }, +{ oid => '3045', + descr => 'statistics: number of blocks found in cache in current transaction', + proname => 'pg_stat_get_xact_blocks_hit', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_blocks_hit' }, +{ oid => '3046', + descr => 'statistics: number of function calls in current transaction', + proname => 'pg_stat_get_xact_function_calls', provolatile => 'v', + proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_function_calls' }, +{ oid => '3047', + descr => 'statistics: total execution time of function in current transaction, in milliseconds', + proname => 'pg_stat_get_xact_function_total_time', provolatile => 'v', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_function_total_time' }, +{ oid => '3048', + descr => 'statistics: self execution time of function in current transaction, in milliseconds', + proname => 'pg_stat_get_xact_function_self_time', provolatile => 'v', + proparallel => 'r', prorettype => 'float8', proargtypes => 'oid', + prosrc => 'pg_stat_get_xact_function_self_time' }, + +{ oid => '3788', + descr => 'statistics: timestamp of the current statistics snapshot', + proname => 'pg_stat_get_snapshot_timestamp', provolatile => 's', + proparallel => 'r', prorettype => 'timestamptz', proargtypes => '', + prosrc => 'pg_stat_get_snapshot_timestamp' }, +{ oid => '2230', + descr => 'statistics: discard current transaction\'s statistics snapshot', + proname => 'pg_stat_clear_snapshot', proisstrict => 'f', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => '', + prosrc => 'pg_stat_clear_snapshot' }, +{ oid => '2137', + descr => 'statistics: force stats to be flushed after the next commit', + proname => 'pg_stat_force_next_flush', proisstrict => 'f', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => '', + prosrc => 'pg_stat_force_next_flush' }, +{ oid => '2274', + descr => 'statistics: reset collected statistics for current database', + proname => 'pg_stat_reset', proisstrict => 'f', provolatile => 'v', + prorettype => 'void', proargtypes => '', prosrc => 'pg_stat_reset' }, +{ oid => '3775', + descr => 'statistics: reset collected statistics shared across the cluster', + proname => 'pg_stat_reset_shared', provolatile => 'v', prorettype => 'void', + proargtypes => 'text', prosrc => 'pg_stat_reset_shared' }, +{ oid => '3776', + descr => 'statistics: reset collected statistics for a single table or index in the current database or shared across all databases in the cluster', + proname => 'pg_stat_reset_single_table_counters', provolatile => 'v', + prorettype => 'void', proargtypes => 'oid', + prosrc => 'pg_stat_reset_single_table_counters' }, +{ oid => '3777', + descr => 'statistics: reset collected statistics for a single function in the current database', + proname => 'pg_stat_reset_single_function_counters', provolatile => 'v', + prorettype => 'void', proargtypes => 'oid', + prosrc => 'pg_stat_reset_single_function_counters' }, +{ oid => '2307', + descr => 'statistics: reset collected statistics for a single SLRU', + proname => 'pg_stat_reset_slru', proisstrict => 'f', provolatile => 'v', + prorettype => 'void', proargtypes => 'text', prosrc => 'pg_stat_reset_slru' }, +{ oid => '6170', + descr => 'statistics: reset collected statistics for a single replication slot', + proname => 'pg_stat_reset_replication_slot', proisstrict => 'f', + provolatile => 'v', prorettype => 'void', proargtypes => 'text', + prosrc => 'pg_stat_reset_replication_slot' }, +{ oid => '6232', + descr => 'statistics: reset collected statistics for a single subscription', + proname => 'pg_stat_reset_subscription_stats', proisstrict => 'f', + provolatile => 'v', prorettype => 'void', proargtypes => 'oid', + prosrc => 'pg_stat_reset_subscription_stats' }, + +{ oid => '3163', descr => 'current trigger depth', + proname => 'pg_trigger_depth', provolatile => 's', proparallel => 'r', + prorettype => 'int4', proargtypes => '', prosrc => 'pg_trigger_depth' }, + +{ oid => '3778', descr => 'tablespace location', + proname => 'pg_tablespace_location', provolatile => 's', prorettype => 'text', + proargtypes => 'oid', prosrc => 'pg_tablespace_location' }, + +{ oid => '1946', + descr => 'convert bytea value into some ascii-only text string', + proname => 'encode', prorettype => 'text', proargtypes => 'bytea text', + prosrc => 'binary_encode' }, +{ oid => '1947', + descr => 'convert ascii-encoded text string into bytea value', + proname => 'decode', prorettype => 'bytea', proargtypes => 'text text', + prosrc => 'binary_decode' }, + +{ oid => '1948', + proname => 'byteaeq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'byteaeq' }, +{ oid => '1949', + proname => 'bytealt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'bytealt' }, +{ oid => '1950', + proname => 'byteale', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'byteale' }, +{ oid => '1951', + proname => 'byteagt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'byteagt' }, +{ oid => '1952', + proname => 'byteage', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'byteage' }, +{ oid => '1953', + proname => 'byteane', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'byteane' }, +{ oid => '1954', descr => 'less-equal-greater', + proname => 'byteacmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bytea bytea', prosrc => 'byteacmp' }, +{ oid => '3331', descr => 'sort support', + proname => 'bytea_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'bytea_sortsupport' }, + +{ oid => '3917', descr => 'planner support for timestamp length coercion', + proname => 'timestamp_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'timestamp_support' }, +{ oid => '3944', descr => 'planner support for time length coercion', + proname => 'time_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'time_support' }, + +{ oid => '1961', descr => 'adjust timestamp precision', + proname => 'timestamp', prosupport => 'timestamp_support', + prorettype => 'timestamp', proargtypes => 'timestamp int4', + prosrc => 'timestamp_scale' }, + +{ oid => '1965', descr => 'larger of two', + proname => 'oidlarger', prorettype => 'oid', proargtypes => 'oid oid', + prosrc => 'oidlarger' }, +{ oid => '1966', descr => 'smaller of two', + proname => 'oidsmaller', prorettype => 'oid', proargtypes => 'oid oid', + prosrc => 'oidsmaller' }, + +{ oid => '1967', descr => 'adjust timestamptz precision', + proname => 'timestamptz', prosupport => 'timestamp_support', + prorettype => 'timestamptz', proargtypes => 'timestamptz int4', + prosrc => 'timestamptz_scale' }, +{ oid => '1968', descr => 'adjust time precision', + proname => 'time', prosupport => 'time_support', prorettype => 'time', + proargtypes => 'time int4', prosrc => 'time_scale' }, +{ oid => '1969', descr => 'adjust time with time zone precision', + proname => 'timetz', prosupport => 'time_support', prorettype => 'timetz', + proargtypes => 'timetz int4', prosrc => 'timetz_scale' }, + +{ oid => '2003', + proname => 'textanycat', prolang => 'sql', provolatile => 's', + prorettype => 'text', proargtypes => 'text anynonarray', + prosrc => 'select $1 operator(pg_catalog.||) $2::pg_catalog.text' }, +{ oid => '2004', + proname => 'anytextcat', prolang => 'sql', provolatile => 's', + prorettype => 'text', proargtypes => 'anynonarray text', + prosrc => 'select $1::pg_catalog.text operator(pg_catalog.||) $2' }, + +{ oid => '2005', + proname => 'bytealike', prosupport => 'textlike_support', + prorettype => 'bool', proargtypes => 'bytea bytea', prosrc => 'bytealike' }, +{ oid => '2006', + proname => 'byteanlike', prorettype => 'bool', proargtypes => 'bytea bytea', + prosrc => 'byteanlike' }, +{ oid => '2007', descr => 'matches LIKE expression', + proname => 'like', prosupport => 'textlike_support', prorettype => 'bool', + proargtypes => 'bytea bytea', prosrc => 'bytealike' }, +{ oid => '2008', descr => 'does not match LIKE expression', + proname => 'notlike', prorettype => 'bool', proargtypes => 'bytea bytea', + prosrc => 'byteanlike' }, +{ oid => '2009', descr => 'convert LIKE pattern to use backslash escapes', + proname => 'like_escape', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'like_escape_bytea' }, +{ oid => '2010', descr => 'octet length', + proname => 'length', prorettype => 'int4', proargtypes => 'bytea', + prosrc => 'byteaoctetlen' }, +{ oid => '2011', + proname => 'byteacat', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'byteacat' }, +{ oid => '2012', descr => 'extract portion of string', + proname => 'substring', prorettype => 'bytea', + proargtypes => 'bytea int4 int4', prosrc => 'bytea_substr' }, +{ oid => '2013', descr => 'extract portion of string', + proname => 'substring', prorettype => 'bytea', proargtypes => 'bytea int4', + prosrc => 'bytea_substr_no_len' }, +{ oid => '2085', descr => 'extract portion of string', + proname => 'substr', prorettype => 'bytea', proargtypes => 'bytea int4 int4', + prosrc => 'bytea_substr' }, +{ oid => '2086', descr => 'extract portion of string', + proname => 'substr', prorettype => 'bytea', proargtypes => 'bytea int4', + prosrc => 'bytea_substr_no_len' }, +{ oid => '2014', descr => 'position of substring', + proname => 'position', prorettype => 'int4', proargtypes => 'bytea bytea', + prosrc => 'byteapos' }, +{ oid => '2015', descr => 'trim selected bytes from both ends of string', + proname => 'btrim', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'byteatrim' }, +{ oid => '6195', descr => 'trim selected bytes from left end of string', + proname => 'ltrim', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'bytealtrim' }, +{ oid => '6196', descr => 'trim selected bytes from right end of string', + proname => 'rtrim', prorettype => 'bytea', proargtypes => 'bytea bytea', + prosrc => 'byteartrim' }, + +{ oid => '2019', descr => 'convert timestamp with time zone to time', + proname => 'time', provolatile => 's', prorettype => 'time', + proargtypes => 'timestamptz', prosrc => 'timestamptz_time' }, +{ oid => '2020', descr => 'truncate timestamp to specified units', + proname => 'date_trunc', prorettype => 'timestamp', + proargtypes => 'text timestamp', prosrc => 'timestamp_trunc' }, + +{ oid => '6177', descr => 'bin timestamp into specified interval', + proname => 'date_bin', prorettype => 'timestamp', + proargtypes => 'interval timestamp timestamp', prosrc => 'timestamp_bin' }, +{ oid => '6178', + descr => 'bin timestamp with time zone into specified interval', + proname => 'date_bin', prorettype => 'timestamptz', + proargtypes => 'interval timestamptz timestamptz', + prosrc => 'timestamptz_bin' }, + +{ oid => '2021', descr => 'extract field from timestamp', + proname => 'date_part', prorettype => 'float8', + proargtypes => 'text timestamp', prosrc => 'timestamp_part' }, +{ oid => '6202', descr => 'extract field from timestamp', + proname => 'extract', prorettype => 'numeric', + proargtypes => 'text timestamp', prosrc => 'extract_timestamp' }, +{ oid => '2024', descr => 'convert date to timestamp', + proname => 'timestamp', prorettype => 'timestamp', proargtypes => 'date', + prosrc => 'date_timestamp' }, +{ oid => '2025', descr => 'convert date and time to timestamp', + proname => 'timestamp', prorettype => 'timestamp', proargtypes => 'date time', + prosrc => 'datetime_timestamp' }, +{ oid => '2027', descr => 'convert timestamp with time zone to timestamp', + proname => 'timestamp', provolatile => 's', prorettype => 'timestamp', + proargtypes => 'timestamptz', prosrc => 'timestamptz_timestamp' }, +{ oid => '2028', descr => 'convert timestamp to timestamp with time zone', + proname => 'timestamptz', provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'timestamp', prosrc => 'timestamp_timestamptz' }, +{ oid => '2029', descr => 'convert timestamp to date', + proname => 'date', prorettype => 'date', proargtypes => 'timestamp', + prosrc => 'timestamp_date' }, +{ oid => '2031', + proname => 'timestamp_mi', prorettype => 'interval', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_mi' }, +{ oid => '2032', + proname => 'timestamp_pl_interval', prorettype => 'timestamp', + proargtypes => 'timestamp interval', prosrc => 'timestamp_pl_interval' }, +{ oid => '2033', + proname => 'timestamp_mi_interval', prorettype => 'timestamp', + proargtypes => 'timestamp interval', prosrc => 'timestamp_mi_interval' }, +{ oid => '2035', descr => 'smaller of two', + proname => 'timestamp_smaller', prorettype => 'timestamp', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_smaller' }, +{ oid => '2036', descr => 'larger of two', + proname => 'timestamp_larger', prorettype => 'timestamp', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_larger' }, +{ oid => '2037', descr => 'adjust time with time zone to new zone', + proname => 'timezone', provolatile => 's', prorettype => 'timetz', + proargtypes => 'text timetz', prosrc => 'timetz_zone' }, +{ oid => '2038', descr => 'adjust time with time zone to new zone', + proname => 'timezone', prorettype => 'timetz', + proargtypes => 'interval timetz', prosrc => 'timetz_izone' }, +{ oid => '2039', descr => 'hash', + proname => 'timestamp_hash', prorettype => 'int4', proargtypes => 'timestamp', + prosrc => 'timestamp_hash' }, +{ oid => '3411', descr => 'hash', + proname => 'timestamp_hash_extended', prorettype => 'int8', + proargtypes => 'timestamp int8', prosrc => 'timestamp_hash_extended' }, +{ oid => '2041', descr => 'intervals overlap?', + proname => 'overlaps', proisstrict => 'f', prorettype => 'bool', + proargtypes => 'timestamp timestamp timestamp timestamp', + prosrc => 'overlaps_timestamp' }, +{ oid => '2042', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'timestamp interval timestamp interval', + prosrc => 'see system_functions.sql' }, +{ oid => '2043', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'timestamp timestamp timestamp interval', + prosrc => 'see system_functions.sql' }, +{ oid => '2044', descr => 'intervals overlap?', + proname => 'overlaps', prolang => 'sql', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'timestamp interval timestamp timestamp', + prosrc => 'see system_functions.sql' }, +{ oid => '2045', descr => 'less-equal-greater', + proname => 'timestamp_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_cmp' }, +{ oid => '3137', descr => 'sort support', + proname => 'timestamp_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'timestamp_sortsupport' }, + +{ oid => '4134', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'timestamp timestamp interval bool bool', + prosrc => 'in_range_timestamp_interval' }, +{ oid => '4135', descr => 'window RANGE support', + proname => 'in_range', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz timestamptz interval bool bool', + prosrc => 'in_range_timestamptz_interval' }, +{ oid => '4136', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'interval interval interval bool bool', + prosrc => 'in_range_interval_interval' }, +{ oid => '4137', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'time time interval bool bool', + prosrc => 'in_range_time_interval' }, +{ oid => '4138', descr => 'window RANGE support', + proname => 'in_range', prorettype => 'bool', + proargtypes => 'timetz timetz interval bool bool', + prosrc => 'in_range_timetz_interval' }, + +{ oid => '2046', descr => 'convert time with time zone to time', + proname => 'time', prorettype => 'time', proargtypes => 'timetz', + prosrc => 'timetz_time' }, +{ oid => '2047', descr => 'convert time to time with time zone', + proname => 'timetz', provolatile => 's', prorettype => 'timetz', + proargtypes => 'time', prosrc => 'time_timetz' }, +{ oid => '2048', descr => 'finite timestamp?', + proname => 'isfinite', prorettype => 'bool', proargtypes => 'timestamp', + prosrc => 'timestamp_finite' }, +{ oid => '2049', descr => 'format timestamp to text', + proname => 'to_char', provolatile => 's', prorettype => 'text', + proargtypes => 'timestamp text', prosrc => 'timestamp_to_char' }, +{ oid => '2052', + proname => 'timestamp_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_eq' }, +{ oid => '2053', + proname => 'timestamp_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_ne' }, +{ oid => '2054', + proname => 'timestamp_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_lt' }, +{ oid => '2055', + proname => 'timestamp_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_le' }, +{ oid => '2056', + proname => 'timestamp_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_ge' }, +{ oid => '2057', + proname => 'timestamp_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_gt' }, +{ oid => '2058', descr => 'date difference preserving months and years', + proname => 'age', prorettype => 'interval', + proargtypes => 'timestamp timestamp', prosrc => 'timestamp_age' }, +{ oid => '2059', + descr => 'date difference from today preserving months and years', + proname => 'age', prolang => 'sql', provolatile => 's', + prorettype => 'interval', proargtypes => 'timestamp', + prosrc => 'see system_functions.sql' }, + +{ oid => '2069', descr => 'adjust timestamp to new time zone', + proname => 'timezone', prorettype => 'timestamptz', + proargtypes => 'text timestamp', prosrc => 'timestamp_zone' }, +{ oid => '2070', descr => 'adjust timestamp to new time zone', + proname => 'timezone', prorettype => 'timestamptz', + proargtypes => 'interval timestamp', prosrc => 'timestamp_izone' }, +{ oid => '2071', + proname => 'date_pl_interval', prorettype => 'timestamp', + proargtypes => 'date interval', prosrc => 'date_pl_interval' }, +{ oid => '2072', + proname => 'date_mi_interval', prorettype => 'timestamp', + proargtypes => 'date interval', prosrc => 'date_mi_interval' }, + +{ oid => '2073', descr => 'extract text matching regular expression', + proname => 'substring', prorettype => 'text', proargtypes => 'text text', + prosrc => 'textregexsubstr' }, +{ oid => '2074', descr => 'extract text matching SQL regular expression', + proname => 'substring', prolang => 'sql', prorettype => 'text', + proargtypes => 'text text text', prosrc => 'see system_functions.sql' }, + +{ oid => '2075', descr => 'convert int8 to bitstring', + proname => 'bit', prorettype => 'bit', proargtypes => 'int8 int4', + prosrc => 'bitfromint8' }, +{ oid => '2076', descr => 'convert bitstring to int8', + proname => 'int8', prorettype => 'int8', proargtypes => 'bit', + prosrc => 'bittoint8' }, + +{ oid => '2077', descr => 'SHOW X as a function', + proname => 'current_setting', provolatile => 's', prorettype => 'text', + proargtypes => 'text', prosrc => 'show_config_by_name' }, +{ oid => '3294', + descr => 'SHOW X as a function, optionally no error for missing variable', + proname => 'current_setting', provolatile => 's', prorettype => 'text', + proargtypes => 'text bool', prosrc => 'show_config_by_name_missing_ok' }, +{ oid => '2078', descr => 'SET X as a function', + proname => 'set_config', proisstrict => 'f', provolatile => 'v', + proparallel => 'u', prorettype => 'text', proargtypes => 'text text bool', + prosrc => 'set_config_by_name' }, +{ oid => '2084', descr => 'SHOW ALL as a function', + proname => 'pg_show_all_settings', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,text,text,text,text,text,text,text,text,text,text,_text,text,text,text,int4,bool}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline,pending_restart}', + prosrc => 'show_all_settings' }, + +{ oid => '6240', descr => 'return flags for specified GUC', + proname => 'pg_settings_get_flags', provolatile => 's', prorettype => '_text', + proargtypes => 'text', prosrc => 'pg_settings_get_flags' }, + +{ oid => '3329', descr => 'show config file settings', + proname => 'pg_show_all_file_settings', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int4,int4,text,text,bool,text}', + proargmodes => '{o,o,o,o,o,o,o}', + proargnames => '{sourcefile,sourceline,seqno,name,setting,applied,error}', + prosrc => 'show_all_file_settings' }, +{ oid => '3401', descr => 'show pg_hba.conf rules', + proname => 'pg_hba_file_rules', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{int4,text,_text,_text,text,text,text,_text,text}', + proargmodes => '{o,o,o,o,o,o,o,o,o}', + proargnames => '{line_number,type,database,user_name,address,netmask,auth_method,options,error}', + prosrc => 'pg_hba_file_rules' }, +{ oid => '6250', descr => 'show pg_ident.conf mappings', + proname => 'pg_ident_file_mappings', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{int4,text,text,text,text}', proargmodes => '{o,o,o,o,o}', + proargnames => '{line_number,map_name,sys_name,pg_username,error}', + prosrc => 'pg_ident_file_mappings' }, +{ oid => '1371', descr => 'view system lock information', + proname => 'pg_lock_status', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,oid,oid,int4,int2,text,xid,oid,oid,int2,text,int4,text,bool,bool,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath,waitstart}', + prosrc => 'pg_lock_status' }, +{ oid => '2561', + descr => 'get array of PIDs of sessions blocking specified backend PID from acquiring a heavyweight lock', + proname => 'pg_blocking_pids', provolatile => 'v', prorettype => '_int4', + proargtypes => 'int4', prosrc => 'pg_blocking_pids' }, +{ oid => '3376', + descr => 'get array of PIDs of sessions blocking specified backend PID from acquiring a safe snapshot', + proname => 'pg_safe_snapshot_blocking_pids', provolatile => 'v', + prorettype => '_int4', proargtypes => 'int4', + prosrc => 'pg_safe_snapshot_blocking_pids' }, +{ oid => '3378', descr => 'isolationtester support function', + proname => 'pg_isolation_test_session_is_blocked', provolatile => 'v', + prorettype => 'bool', proargtypes => 'int4 _int4', + prosrc => 'pg_isolation_test_session_is_blocked' }, +{ oid => '1065', descr => 'view two-phase transactions', + proname => 'pg_prepared_xact', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{xid,text,timestamptz,oid,oid}', + proargmodes => '{o,o,o,o,o}', + proargnames => '{transaction,gid,prepared,ownerid,dbid}', + prosrc => 'pg_prepared_xact' }, +{ oid => '3819', descr => 'view members of a multixactid', + proname => 'pg_get_multixact_members', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => 'xid', + proallargtypes => '{xid,xid,text}', proargmodes => '{i,o,o}', + proargnames => '{multixid,xid,mode}', prosrc => 'pg_get_multixact_members' }, + +{ oid => '3581', descr => 'get commit timestamp of a transaction', + proname => 'pg_xact_commit_timestamp', provolatile => 'v', + prorettype => 'timestamptz', proargtypes => 'xid', + prosrc => 'pg_xact_commit_timestamp' }, + +{ oid => '6168', + descr => 'get commit timestamp and replication origin of a transaction', + proname => 'pg_xact_commit_timestamp_origin', provolatile => 'v', + prorettype => 'record', proargtypes => 'xid', + proallargtypes => '{xid,timestamptz,oid}', proargmodes => '{i,o,o}', + proargnames => '{xid,timestamp,roident}', + prosrc => 'pg_xact_commit_timestamp_origin' }, + +{ oid => '3583', + descr => 'get transaction Id, commit timestamp and replication origin of latest transaction commit', + proname => 'pg_last_committed_xact', provolatile => 'v', + prorettype => 'record', proargtypes => '', + proallargtypes => '{xid,timestamptz,oid}', proargmodes => '{o,o,o}', + proargnames => '{xid,timestamp,roident}', + prosrc => 'pg_last_committed_xact' }, + +{ oid => '3537', descr => 'get identification of SQL object', + proname => 'pg_describe_object', provolatile => 's', prorettype => 'text', + proargtypes => 'oid oid int4', prosrc => 'pg_describe_object' }, + +{ oid => '3839', + descr => 'get machine-parseable identification of SQL object', + proname => 'pg_identify_object', provolatile => 's', prorettype => 'record', + proargtypes => 'oid oid int4', + proallargtypes => '{oid,oid,int4,text,text,text,text}', + proargmodes => '{i,i,i,o,o,o,o}', + proargnames => '{classid,objid,objsubid,type,schema,name,identity}', + prosrc => 'pg_identify_object' }, + +{ oid => '3382', + descr => 'get identification of SQL object for pg_get_object_address()', + proname => 'pg_identify_object_as_address', provolatile => 's', + prorettype => 'record', proargtypes => 'oid oid int4', + proallargtypes => '{oid,oid,int4,text,_text,_text}', + proargmodes => '{i,i,i,o,o,o}', + proargnames => '{classid,objid,objsubid,type,object_names,object_args}', + prosrc => 'pg_identify_object_as_address' }, + +{ oid => '3954', + descr => 'get OID-based object address from name/args arrays', + proname => 'pg_get_object_address', provolatile => 's', + prorettype => 'record', proargtypes => 'text _text _text', + proallargtypes => '{text,_text,_text,oid,oid,int4}', + proargmodes => '{i,i,i,o,o,o}', + proargnames => '{type,object_names,object_args,classid,objid,objsubid}', + prosrc => 'pg_get_object_address' }, + +{ oid => '2079', descr => 'is table visible in search path?', + proname => 'pg_table_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', prosrc => 'pg_table_is_visible' }, +{ oid => '2080', descr => 'is type visible in search path?', + proname => 'pg_type_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', prosrc => 'pg_type_is_visible' }, +{ oid => '2081', descr => 'is function visible in search path?', + proname => 'pg_function_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_function_is_visible' }, +{ oid => '2082', descr => 'is operator visible in search path?', + proname => 'pg_operator_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_operator_is_visible' }, +{ oid => '2083', descr => 'is opclass visible in search path?', + proname => 'pg_opclass_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_opclass_is_visible' }, +{ oid => '3829', descr => 'is opfamily visible in search path?', + proname => 'pg_opfamily_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_opfamily_is_visible' }, +{ oid => '2093', descr => 'is conversion visible in search path?', + proname => 'pg_conversion_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_conversion_is_visible' }, +{ oid => '3403', descr => 'is statistics object visible in search path?', + proname => 'pg_statistics_obj_is_visible', procost => '10', + provolatile => 's', prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_statistics_obj_is_visible' }, +{ oid => '3756', descr => 'is text search parser visible in search path?', + proname => 'pg_ts_parser_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_ts_parser_is_visible' }, +{ oid => '3757', descr => 'is text search dictionary visible in search path?', + proname => 'pg_ts_dict_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_ts_dict_is_visible' }, +{ oid => '3768', descr => 'is text search template visible in search path?', + proname => 'pg_ts_template_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_ts_template_is_visible' }, +{ oid => '3758', + descr => 'is text search configuration visible in search path?', + proname => 'pg_ts_config_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_ts_config_is_visible' }, +{ oid => '3815', descr => 'is collation visible in search path?', + proname => 'pg_collation_is_visible', procost => '10', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_collation_is_visible' }, + +{ oid => '2854', descr => 'get OID of current session\'s temp schema, if any', + proname => 'pg_my_temp_schema', provolatile => 's', proparallel => 'r', + prorettype => 'oid', proargtypes => '', prosrc => 'pg_my_temp_schema' }, +{ oid => '2855', descr => 'is schema another session\'s temp schema?', + proname => 'pg_is_other_temp_schema', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid', + prosrc => 'pg_is_other_temp_schema' }, + +{ oid => '2171', descr => 'cancel a server process\' current query', + proname => 'pg_cancel_backend', provolatile => 'v', prorettype => 'bool', + proargtypes => 'int4', prosrc => 'pg_cancel_backend' }, +{ oid => '2096', descr => 'terminate a server process', + proname => 'pg_terminate_backend', provolatile => 'v', prorettype => 'bool', + proargtypes => 'int4 int8', proargnames => '{pid,timeout}', + prosrc => 'pg_terminate_backend' }, +{ oid => '2172', descr => 'prepare for taking an online backup', + proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r', + prorettype => 'pg_lsn', proargtypes => 'text bool', + prosrc => 'pg_backup_start' }, +{ oid => '2739', descr => 'finish taking an online backup', + proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r', + prorettype => 'record', proargtypes => 'bool', + proallargtypes => '{bool,pg_lsn,text,text}', proargmodes => '{i,o,o,o}', + proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}', + prosrc => 'pg_backup_stop' }, +{ oid => '3436', descr => 'promote standby server', + proname => 'pg_promote', provolatile => 'v', prorettype => 'bool', + proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}', + prosrc => 'pg_promote' }, +{ oid => '2848', descr => 'switch to new wal file', + proname => 'pg_switch_wal', provolatile => 'v', prorettype => 'pg_lsn', + proargtypes => '', prosrc => 'pg_switch_wal' }, +{ oid => '3098', descr => 'create a named restore point', + proname => 'pg_create_restore_point', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => 'text', + prosrc => 'pg_create_restore_point' }, +{ oid => '2849', descr => 'current wal write location', + proname => 'pg_current_wal_lsn', provolatile => 'v', prorettype => 'pg_lsn', + proargtypes => '', prosrc => 'pg_current_wal_lsn' }, +{ oid => '2852', descr => 'current wal insert location', + proname => 'pg_current_wal_insert_lsn', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => '', + prosrc => 'pg_current_wal_insert_lsn' }, +{ oid => '3330', descr => 'current wal flush location', + proname => 'pg_current_wal_flush_lsn', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => '', + prosrc => 'pg_current_wal_flush_lsn' }, +{ oid => '2850', + descr => 'wal filename and byte offset, given a wal location', + proname => 'pg_walfile_name_offset', prorettype => 'record', + proargtypes => 'pg_lsn', proallargtypes => '{pg_lsn,text,int4}', + proargmodes => '{i,o,o}', proargnames => '{lsn,file_name,file_offset}', + prosrc => 'pg_walfile_name_offset' }, +{ oid => '2851', descr => 'wal filename, given a wal location', + proname => 'pg_walfile_name', prorettype => 'text', proargtypes => 'pg_lsn', + prosrc => 'pg_walfile_name' }, + +{ oid => '3165', descr => 'difference in bytes, given two wal locations', + proname => 'pg_wal_lsn_diff', prorettype => 'numeric', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_wal_lsn_diff' }, + +{ oid => '3809', descr => 'export a snapshot', + proname => 'pg_export_snapshot', provolatile => 'v', proparallel => 'u', + prorettype => 'text', proargtypes => '', prosrc => 'pg_export_snapshot' }, + +{ oid => '3810', descr => 'true if server is in recovery', + proname => 'pg_is_in_recovery', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_is_in_recovery' }, + +{ oid => '3820', descr => 'current wal flush location', + proname => 'pg_last_wal_receive_lsn', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => '', + prosrc => 'pg_last_wal_receive_lsn' }, +{ oid => '3821', descr => 'last wal replay location', + proname => 'pg_last_wal_replay_lsn', provolatile => 'v', + prorettype => 'pg_lsn', proargtypes => '', + prosrc => 'pg_last_wal_replay_lsn' }, +{ oid => '3830', descr => 'timestamp of last replay xact', + proname => 'pg_last_xact_replay_timestamp', provolatile => 'v', + prorettype => 'timestamptz', proargtypes => '', + prosrc => 'pg_last_xact_replay_timestamp' }, + +{ oid => '3071', descr => 'pause wal replay', + proname => 'pg_wal_replay_pause', provolatile => 'v', prorettype => 'void', + proargtypes => '', prosrc => 'pg_wal_replay_pause' }, +{ oid => '3072', descr => 'resume wal replay, if it was paused', + proname => 'pg_wal_replay_resume', provolatile => 'v', prorettype => 'void', + proargtypes => '', prosrc => 'pg_wal_replay_resume' }, +{ oid => '3073', descr => 'true if wal replay is paused', + proname => 'pg_is_wal_replay_paused', provolatile => 'v', + prorettype => 'bool', proargtypes => '', + prosrc => 'pg_is_wal_replay_paused' }, +{ oid => '1137', descr => 'get wal replay pause state', + proname => 'pg_get_wal_replay_pause_state', provolatile => 'v', + prorettype => 'text', proargtypes => '', + prosrc => 'pg_get_wal_replay_pause_state' }, + +{ oid => '6224', descr => 'get resource managers loaded in system', + proname => 'pg_get_wal_resource_managers', prorows => '50', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{int4,text,bool}', proargmodes => '{o,o,o}', + proargnames => '{rm_id, rm_name, rm_builtin}', + prosrc => 'pg_get_wal_resource_managers' }, + +{ oid => '2621', descr => 'reload configuration files', + proname => 'pg_reload_conf', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_reload_conf' }, +{ oid => '2622', descr => 'rotate log file', + proname => 'pg_rotate_logfile', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_rotate_logfile_v2' }, +{ oid => '4099', descr => 'rotate log file - old version for adminpack 1.0', + proname => 'pg_rotate_logfile_old', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_rotate_logfile' }, +{ oid => '3800', descr => 'current logging collector file location', + proname => 'pg_current_logfile', proisstrict => 'f', provolatile => 'v', + prorettype => 'text', proargtypes => '', prosrc => 'pg_current_logfile' }, +{ oid => '3801', descr => 'current logging collector file location', + proname => 'pg_current_logfile', proisstrict => 'f', provolatile => 'v', + prorettype => 'text', proargtypes => 'text', + prosrc => 'pg_current_logfile_1arg' }, + +{ oid => '2623', descr => 'get information about file', + proname => 'pg_stat_file', provolatile => 'v', prorettype => 'record', + proargtypes => 'text', + proallargtypes => '{text,int8,timestamptz,timestamptz,timestamptz,timestamptz,bool}', + proargmodes => '{i,o,o,o,o,o,o}', + proargnames => '{filename,size,access,modification,change,creation,isdir}', + prosrc => 'pg_stat_file_1arg' }, +{ oid => '3307', descr => 'get information about file', + proname => 'pg_stat_file', provolatile => 'v', prorettype => 'record', + proargtypes => 'text bool', + proallargtypes => '{text,bool,int8,timestamptz,timestamptz,timestamptz,timestamptz,bool}', + proargmodes => '{i,i,o,o,o,o,o,o}', + proargnames => '{filename,missing_ok,size,access,modification,change,creation,isdir}', + prosrc => 'pg_stat_file' }, +{ oid => '2624', descr => 'read text from a file', + proname => 'pg_read_file', provolatile => 'v', prorettype => 'text', + proargtypes => 'text int8 int8', prosrc => 'pg_read_file_off_len' }, +{ oid => '3293', descr => 'read text from a file', + proname => 'pg_read_file', provolatile => 'v', prorettype => 'text', + proargtypes => 'text int8 int8 bool', prosrc => 'pg_read_file_v2' }, +{ oid => '4100', + descr => 'read text from a file - old version for adminpack 1.0', + proname => 'pg_read_file_old', provolatile => 'v', prorettype => 'text', + proargtypes => 'text int8 int8', prosrc => 'pg_read_file' }, +{ oid => '3826', descr => 'read text from a file', + proname => 'pg_read_file', provolatile => 'v', prorettype => 'text', + proargtypes => 'text', prosrc => 'pg_read_file_all' }, +{ oid => '3827', descr => 'read bytea from a file', + proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea', + proargtypes => 'text int8 int8', prosrc => 'pg_read_binary_file_off_len' }, +{ oid => '3295', descr => 'read bytea from a file', + proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea', + proargtypes => 'text int8 int8 bool', prosrc => 'pg_read_binary_file' }, +{ oid => '3828', descr => 'read bytea from a file', + proname => 'pg_read_binary_file', provolatile => 'v', prorettype => 'bytea', + proargtypes => 'text', prosrc => 'pg_read_binary_file_all' }, +{ oid => '2625', descr => 'list all files in a directory', + proname => 'pg_ls_dir', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'text', proargtypes => 'text', + prosrc => 'pg_ls_dir_1arg' }, +{ oid => '3297', descr => 'list all files in a directory', + proname => 'pg_ls_dir', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'text', proargtypes => 'text bool bool', + prosrc => 'pg_ls_dir' }, +{ oid => '2626', descr => 'sleep for the specified time in seconds', + proname => 'pg_sleep', provolatile => 'v', prorettype => 'void', + proargtypes => 'float8', prosrc => 'pg_sleep' }, +{ oid => '3935', descr => 'sleep for the specified interval', + proname => 'pg_sleep_for', prolang => 'sql', provolatile => 'v', + prorettype => 'void', proargtypes => 'interval', + prosrc => 'see system_functions.sql' }, +{ oid => '3936', descr => 'sleep until the specified time', + proname => 'pg_sleep_until', prolang => 'sql', provolatile => 'v', + prorettype => 'void', proargtypes => 'timestamptz', + prosrc => 'see system_functions.sql' }, +{ oid => '315', descr => 'Is JIT compilation available in this session?', + proname => 'pg_jit_available', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_jit_available' }, + +{ oid => '2971', descr => 'convert boolean to text', + proname => 'text', prorettype => 'text', proargtypes => 'bool', + prosrc => 'booltext' }, + +# Aggregates (moved here from pg_aggregate for 7.3) + +{ oid => '2100', + descr => 'the average (arithmetic mean) as numeric of all bigint values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2101', + descr => 'the average (arithmetic mean) as numeric of all integer values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2102', + descr => 'the average (arithmetic mean) as numeric of all smallint values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2103', + descr => 'the average (arithmetic mean) as numeric of all numeric values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, +{ oid => '2104', + descr => 'the average (arithmetic mean) as float8 of all float4 values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float4', prosrc => 'aggregate_dummy' }, +{ oid => '2105', + descr => 'the average (arithmetic mean) as float8 of all float8 values', + proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float8', prosrc => 'aggregate_dummy' }, +{ oid => '2106', + descr => 'the average (arithmetic mean) as interval of all interval values', + proname => 'avg', prokind => 'a', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'interval', + prosrc => 'aggregate_dummy' }, + +{ oid => '2107', descr => 'sum as numeric across all bigint input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2108', descr => 'sum as bigint across all integer input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2109', descr => 'sum as bigint across all smallint input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2110', descr => 'sum as float4 across all float4 input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proargtypes => 'float4', prosrc => 'aggregate_dummy' }, +{ oid => '2111', descr => 'sum as float8 across all float8 input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float8', prosrc => 'aggregate_dummy' }, +{ oid => '2112', descr => 'sum as money across all money input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proargtypes => 'money', prosrc => 'aggregate_dummy' }, +{ oid => '2113', descr => 'sum as interval across all interval input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'interval', + prosrc => 'aggregate_dummy' }, +{ oid => '2114', descr => 'sum as numeric across all numeric input values', + proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, + +{ oid => '2115', descr => 'maximum value of all bigint input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2116', descr => 'maximum value of all integer input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2117', descr => 'maximum value of all smallint input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2118', descr => 'maximum value of all oid input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'oid', + proargtypes => 'oid', prosrc => 'aggregate_dummy' }, +{ oid => '2119', descr => 'maximum value of all float4 input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proargtypes => 'float4', prosrc => 'aggregate_dummy' }, +{ oid => '2120', descr => 'maximum value of all float8 input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float8', prosrc => 'aggregate_dummy' }, +{ oid => '2122', descr => 'maximum value of all date input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'date', + proargtypes => 'date', prosrc => 'aggregate_dummy' }, +{ oid => '2123', descr => 'maximum value of all time input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'time', + proargtypes => 'time', prosrc => 'aggregate_dummy' }, +{ oid => '2124', + descr => 'maximum value of all time with time zone input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'timetz', + proargtypes => 'timetz', prosrc => 'aggregate_dummy' }, +{ oid => '2125', descr => 'maximum value of all money input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proargtypes => 'money', prosrc => 'aggregate_dummy' }, +{ oid => '2126', descr => 'maximum value of all timestamp input values', + proname => 'max', prokind => 'a', proisstrict => 'f', + prorettype => 'timestamp', proargtypes => 'timestamp', + prosrc => 'aggregate_dummy' }, +{ oid => '2127', + descr => 'maximum value of all timestamp with time zone input values', + proname => 'max', prokind => 'a', proisstrict => 'f', + prorettype => 'timestamptz', proargtypes => 'timestamptz', + prosrc => 'aggregate_dummy' }, +{ oid => '2128', descr => 'maximum value of all interval input values', + proname => 'max', prokind => 'a', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'interval', + prosrc => 'aggregate_dummy' }, +{ oid => '2129', descr => 'maximum value of all text input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'text', + proargtypes => 'text', prosrc => 'aggregate_dummy' }, +{ oid => '2130', descr => 'maximum value of all numeric input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, +{ oid => '2050', descr => 'maximum value of all anyarray input values', + proname => 'max', prokind => 'a', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'anyarray', + prosrc => 'aggregate_dummy' }, +{ oid => '2244', descr => 'maximum value of all bpchar input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar', + proargtypes => 'bpchar', prosrc => 'aggregate_dummy' }, +{ oid => '2797', descr => 'maximum value of all tid input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'tid', + proargtypes => 'tid', prosrc => 'aggregate_dummy' }, +{ oid => '3564', descr => 'maximum value of all inet input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'inet', + proargtypes => 'inet', prosrc => 'aggregate_dummy' }, +{ oid => '4189', descr => 'maximum value of all pg_lsn input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' }, +{ oid => '5099', descr => 'maximum value of all xid8 input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'xid8', + proargtypes => 'xid8', prosrc => 'aggregate_dummy' }, + +{ oid => '2131', descr => 'minimum value of all bigint input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2132', descr => 'minimum value of all integer input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2133', descr => 'minimum value of all smallint input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2134', descr => 'minimum value of all oid input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'oid', + proargtypes => 'oid', prosrc => 'aggregate_dummy' }, +{ oid => '2135', descr => 'minimum value of all float4 input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float4', + proargtypes => 'float4', prosrc => 'aggregate_dummy' }, +{ oid => '2136', descr => 'minimum value of all float8 input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float8', prosrc => 'aggregate_dummy' }, +{ oid => '2138', descr => 'minimum value of all date input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'date', + proargtypes => 'date', prosrc => 'aggregate_dummy' }, +{ oid => '2139', descr => 'minimum value of all time input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'time', + proargtypes => 'time', prosrc => 'aggregate_dummy' }, +{ oid => '2140', + descr => 'minimum value of all time with time zone input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'timetz', + proargtypes => 'timetz', prosrc => 'aggregate_dummy' }, +{ oid => '2141', descr => 'minimum value of all money input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'money', + proargtypes => 'money', prosrc => 'aggregate_dummy' }, +{ oid => '2142', descr => 'minimum value of all timestamp input values', + proname => 'min', prokind => 'a', proisstrict => 'f', + prorettype => 'timestamp', proargtypes => 'timestamp', + prosrc => 'aggregate_dummy' }, +{ oid => '2143', + descr => 'minimum value of all timestamp with time zone input values', + proname => 'min', prokind => 'a', proisstrict => 'f', + prorettype => 'timestamptz', proargtypes => 'timestamptz', + prosrc => 'aggregate_dummy' }, +{ oid => '2144', descr => 'minimum value of all interval input values', + proname => 'min', prokind => 'a', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'interval', + prosrc => 'aggregate_dummy' }, +{ oid => '2145', descr => 'minimum value of all text values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'text', + proargtypes => 'text', prosrc => 'aggregate_dummy' }, +{ oid => '2146', descr => 'minimum value of all numeric input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'numeric', + proargtypes => 'numeric', prosrc => 'aggregate_dummy' }, +{ oid => '2051', descr => 'minimum value of all anyarray input values', + proname => 'min', prokind => 'a', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'anyarray', + prosrc => 'aggregate_dummy' }, +{ oid => '2245', descr => 'minimum value of all bpchar input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar', + proargtypes => 'bpchar', prosrc => 'aggregate_dummy' }, +{ oid => '2798', descr => 'minimum value of all tid input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'tid', + proargtypes => 'tid', prosrc => 'aggregate_dummy' }, +{ oid => '3565', descr => 'minimum value of all inet input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'inet', + proargtypes => 'inet', prosrc => 'aggregate_dummy' }, +{ oid => '4190', descr => 'minimum value of all pg_lsn input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' }, +{ oid => '5100', descr => 'minimum value of all xid8 input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'xid8', + proargtypes => 'xid8', prosrc => 'aggregate_dummy' }, + +# count has two forms: count(any) and count(*) +{ oid => '2147', + descr => 'number of input rows for which the input expression is not null', + proname => 'count', prosupport => 'int8inc_support', prokind => 'a', + proisstrict => 'f', prorettype => 'int8', proargtypes => 'any', + prosrc => 'aggregate_dummy' }, +{ oid => '2803', descr => 'number of input rows', + proname => 'count', prosupport => 'int8inc_support', prokind => 'a', + proisstrict => 'f', prorettype => 'int8', proargtypes => '', + prosrc => 'aggregate_dummy' }, +{ oid => '6236', descr => 'planner support for count run condition', + proname => 'int8inc_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'int8inc_support' }, + +{ oid => '2718', + descr => 'population variance of bigint input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2719', + descr => 'population variance of integer input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2720', + descr => 'population variance of smallint input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2721', + descr => 'population variance of float4 input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, +{ oid => '2722', + descr => 'population variance of float8 input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2723', + descr => 'population variance of numeric input values (square of the population standard deviation)', + proname => 'var_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2641', + descr => 'sample variance of bigint input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2642', + descr => 'sample variance of integer input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2643', + descr => 'sample variance of smallint input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2644', + descr => 'sample variance of float4 input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, + +{ oid => '2645', + descr => 'sample variance of float8 input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2646', + descr => 'sample variance of numeric input values (square of the sample standard deviation)', + proname => 'var_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2148', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2149', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2150', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2151', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, +{ oid => '2152', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2153', descr => 'historical alias for var_samp', + proname => 'variance', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2724', + descr => 'population standard deviation of bigint input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2725', + descr => 'population standard deviation of integer input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2726', + descr => 'population standard deviation of smallint input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2727', + descr => 'population standard deviation of float4 input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, +{ oid => '2728', + descr => 'population standard deviation of float8 input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2729', + descr => 'population standard deviation of numeric input values', + proname => 'stddev_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2712', descr => 'sample standard deviation of bigint input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2713', descr => 'sample standard deviation of integer input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2714', + descr => 'sample standard deviation of smallint input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2715', descr => 'sample standard deviation of float4 input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, +{ oid => '2716', descr => 'sample standard deviation of float8 input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2717', descr => 'sample standard deviation of numeric input values', + proname => 'stddev_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2154', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2155', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2156', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2157', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float4', + prosrc => 'aggregate_dummy' }, +{ oid => '2158', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2159', descr => 'historical alias for stddev_samp', + proname => 'stddev', prokind => 'a', proisstrict => 'f', + prorettype => 'numeric', proargtypes => 'numeric', + prosrc => 'aggregate_dummy' }, + +{ oid => '2818', + descr => 'number of input rows in which both expressions are not null', + proname => 'regr_count', prokind => 'a', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2819', + descr => 'sum of squares of the independent variable (sum(X^2) - sum(X)^2/N)', + proname => 'regr_sxx', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2820', + descr => 'sum of squares of the dependent variable (sum(Y^2) - sum(Y)^2/N)', + proname => 'regr_syy', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2821', + descr => 'sum of products of independent times dependent variable (sum(X*Y) - sum(X) * sum(Y)/N)', + proname => 'regr_sxy', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2822', descr => 'average of the independent variable (sum(X)/N)', + proname => 'regr_avgx', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2823', descr => 'average of the dependent variable (sum(Y)/N)', + proname => 'regr_avgy', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2824', descr => 'square of the correlation coefficient', + proname => 'regr_r2', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2825', + descr => 'slope of the least-squares-fit linear equation determined by the (X, Y) pairs', + proname => 'regr_slope', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2826', + descr => 'y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs', + proname => 'regr_intercept', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, + +{ oid => '2827', descr => 'population covariance', + proname => 'covar_pop', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2828', descr => 'sample covariance', + proname => 'covar_samp', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '2829', descr => 'correlation coefficient', + proname => 'corr', prokind => 'a', proisstrict => 'f', prorettype => 'float8', + proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' }, + +{ oid => '2160', + proname => 'text_pattern_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_pattern_lt' }, +{ oid => '2161', + proname => 'text_pattern_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_pattern_le' }, +{ oid => '2163', + proname => 'text_pattern_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_pattern_ge' }, +{ oid => '2164', + proname => 'text_pattern_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'text_pattern_gt' }, +{ oid => '2166', descr => 'less-equal-greater', + proname => 'bttext_pattern_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'text text', prosrc => 'bttext_pattern_cmp' }, +{ oid => '3332', descr => 'sort support', + proname => 'bttext_pattern_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'bttext_pattern_sortsupport' }, + +{ oid => '2174', + proname => 'bpchar_pattern_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_pattern_lt' }, +{ oid => '2175', + proname => 'bpchar_pattern_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_pattern_le' }, +{ oid => '2177', + proname => 'bpchar_pattern_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_pattern_ge' }, +{ oid => '2178', + proname => 'bpchar_pattern_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'bpchar bpchar', prosrc => 'bpchar_pattern_gt' }, +{ oid => '2180', descr => 'less-equal-greater', + proname => 'btbpchar_pattern_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bpchar bpchar', prosrc => 'btbpchar_pattern_cmp' }, +{ oid => '3333', descr => 'sort support', + proname => 'btbpchar_pattern_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'btbpchar_pattern_sortsupport' }, + +{ oid => '2188', descr => 'less-equal-greater', + proname => 'btint48cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int4 int8', prosrc => 'btint48cmp' }, +{ oid => '2189', descr => 'less-equal-greater', + proname => 'btint84cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int8 int4', prosrc => 'btint84cmp' }, +{ oid => '2190', descr => 'less-equal-greater', + proname => 'btint24cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int2 int4', prosrc => 'btint24cmp' }, +{ oid => '2191', descr => 'less-equal-greater', + proname => 'btint42cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int4 int2', prosrc => 'btint42cmp' }, +{ oid => '2192', descr => 'less-equal-greater', + proname => 'btint28cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int2 int8', prosrc => 'btint28cmp' }, +{ oid => '2193', descr => 'less-equal-greater', + proname => 'btint82cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'int8 int2', prosrc => 'btint82cmp' }, +{ oid => '2194', descr => 'less-equal-greater', + proname => 'btfloat48cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'float4 float8', prosrc => 'btfloat48cmp' }, +{ oid => '2195', descr => 'less-equal-greater', + proname => 'btfloat84cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'float8 float4', prosrc => 'btfloat84cmp' }, + +{ oid => '2212', descr => 'I/O', + proname => 'regprocedurein', provolatile => 's', prorettype => 'regprocedure', + proargtypes => 'cstring', prosrc => 'regprocedurein' }, +{ oid => '2213', descr => 'I/O', + proname => 'regprocedureout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regprocedure', prosrc => 'regprocedureout' }, +{ oid => '2214', descr => 'I/O', + proname => 'regoperin', provolatile => 's', prorettype => 'regoper', + proargtypes => 'cstring', prosrc => 'regoperin' }, +{ oid => '2215', descr => 'I/O', + proname => 'regoperout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regoper', prosrc => 'regoperout' }, +{ oid => '3492', descr => 'convert operator name to regoper', + proname => 'to_regoper', provolatile => 's', prorettype => 'regoper', + proargtypes => 'text', prosrc => 'to_regoper' }, +{ oid => '3476', descr => 'convert operator name to regoperator', + proname => 'to_regoperator', provolatile => 's', prorettype => 'regoperator', + proargtypes => 'text', prosrc => 'to_regoperator' }, +{ oid => '2216', descr => 'I/O', + proname => 'regoperatorin', provolatile => 's', prorettype => 'regoperator', + proargtypes => 'cstring', prosrc => 'regoperatorin' }, +{ oid => '2217', descr => 'I/O', + proname => 'regoperatorout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regoperator', prosrc => 'regoperatorout' }, +{ oid => '2218', descr => 'I/O', + proname => 'regclassin', provolatile => 's', prorettype => 'regclass', + proargtypes => 'cstring', prosrc => 'regclassin' }, +{ oid => '2219', descr => 'I/O', + proname => 'regclassout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regclass', prosrc => 'regclassout' }, +{ oid => '3495', descr => 'convert classname to regclass', + proname => 'to_regclass', provolatile => 's', prorettype => 'regclass', + proargtypes => 'text', prosrc => 'to_regclass' }, +{ oid => '4193', descr => 'I/O', + proname => 'regcollationin', provolatile => 's', prorettype => 'regcollation', + proargtypes => 'cstring', prosrc => 'regcollationin' }, +{ oid => '4194', descr => 'I/O', + proname => 'regcollationout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regcollation', prosrc => 'regcollationout' }, +{ oid => '4195', descr => 'convert classname to regcollation', + proname => 'to_regcollation', provolatile => 's', + prorettype => 'regcollation', proargtypes => 'text', + prosrc => 'to_regcollation' }, +{ oid => '2220', descr => 'I/O', + proname => 'regtypein', provolatile => 's', prorettype => 'regtype', + proargtypes => 'cstring', prosrc => 'regtypein' }, +{ oid => '2221', descr => 'I/O', + proname => 'regtypeout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regtype', prosrc => 'regtypeout' }, +{ oid => '3493', descr => 'convert type name to regtype', + proname => 'to_regtype', provolatile => 's', prorettype => 'regtype', + proargtypes => 'text', prosrc => 'to_regtype' }, +{ oid => '1079', descr => 'convert text to regclass', + proname => 'regclass', provolatile => 's', prorettype => 'regclass', + proargtypes => 'text', prosrc => 'text_regclass' }, + +{ oid => '4098', descr => 'I/O', + proname => 'regrolein', provolatile => 's', prorettype => 'regrole', + proargtypes => 'cstring', prosrc => 'regrolein' }, +{ oid => '4092', descr => 'I/O', + proname => 'regroleout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regrole', prosrc => 'regroleout' }, +{ oid => '4093', descr => 'convert role name to regrole', + proname => 'to_regrole', provolatile => 's', prorettype => 'regrole', + proargtypes => 'text', prosrc => 'to_regrole' }, + +{ oid => '4084', descr => 'I/O', + proname => 'regnamespacein', provolatile => 's', prorettype => 'regnamespace', + proargtypes => 'cstring', prosrc => 'regnamespacein' }, +{ oid => '4085', descr => 'I/O', + proname => 'regnamespaceout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regnamespace', prosrc => 'regnamespaceout' }, +{ oid => '4086', descr => 'convert namespace name to regnamespace', + proname => 'to_regnamespace', provolatile => 's', + prorettype => 'regnamespace', proargtypes => 'text', + prosrc => 'to_regnamespace' }, + +{ oid => '1268', + descr => 'parse qualified identifier to array of identifiers', + proname => 'parse_ident', prorettype => '_text', proargtypes => 'text bool', + proargnames => '{str,strict}', prosrc => 'parse_ident' }, + +{ oid => '2246', descr => '(internal)', + proname => 'fmgr_internal_validator', provolatile => 's', + prorettype => 'void', proargtypes => 'oid', + prosrc => 'fmgr_internal_validator' }, +{ oid => '2247', descr => '(internal)', + proname => 'fmgr_c_validator', provolatile => 's', prorettype => 'void', + proargtypes => 'oid', prosrc => 'fmgr_c_validator' }, +{ oid => '2248', descr => '(internal)', + proname => 'fmgr_sql_validator', provolatile => 's', prorettype => 'void', + proargtypes => 'oid', prosrc => 'fmgr_sql_validator' }, + +{ oid => '2250', + descr => 'user privilege on database by username, database name', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', + prosrc => 'has_database_privilege_name_name' }, +{ oid => '2251', + descr => 'user privilege on database by username, database oid', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_database_privilege_name_id' }, +{ oid => '2252', + descr => 'user privilege on database by user oid, database name', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_database_privilege_id_name' }, +{ oid => '2253', + descr => 'user privilege on database by user oid, database oid', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_database_privilege_id_id' }, +{ oid => '2254', + descr => 'current user privilege on database by database name', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_database_privilege_name' }, +{ oid => '2255', + descr => 'current user privilege on database by database oid', + proname => 'has_database_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_database_privilege_id' }, + +{ oid => '2256', + descr => 'user privilege on function by username, function name', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', + prosrc => 'has_function_privilege_name_name' }, +{ oid => '2257', + descr => 'user privilege on function by username, function oid', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_function_privilege_name_id' }, +{ oid => '2258', + descr => 'user privilege on function by user oid, function name', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_function_privilege_id_name' }, +{ oid => '2259', + descr => 'user privilege on function by user oid, function oid', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_function_privilege_id_id' }, +{ oid => '2260', + descr => 'current user privilege on function by function name', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_function_privilege_name' }, +{ oid => '2261', + descr => 'current user privilege on function by function oid', + proname => 'has_function_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_function_privilege_id' }, + +{ oid => '2262', + descr => 'user privilege on language by username, language name', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', + prosrc => 'has_language_privilege_name_name' }, +{ oid => '2263', + descr => 'user privilege on language by username, language oid', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_language_privilege_name_id' }, +{ oid => '2264', + descr => 'user privilege on language by user oid, language name', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_language_privilege_id_name' }, +{ oid => '2265', + descr => 'user privilege on language by user oid, language oid', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_language_privilege_id_id' }, +{ oid => '2266', + descr => 'current user privilege on language by language name', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_language_privilege_name' }, +{ oid => '2267', + descr => 'current user privilege on language by language oid', + proname => 'has_language_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_language_privilege_id' }, + +{ oid => '2268', descr => 'user privilege on schema by username, schema name', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', prosrc => 'has_schema_privilege_name_name' }, +{ oid => '2269', descr => 'user privilege on schema by username, schema oid', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_schema_privilege_name_id' }, +{ oid => '2270', descr => 'user privilege on schema by user oid, schema name', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_schema_privilege_id_name' }, +{ oid => '2271', descr => 'user privilege on schema by user oid, schema oid', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_schema_privilege_id_id' }, +{ oid => '2272', descr => 'current user privilege on schema by schema name', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_schema_privilege_name' }, +{ oid => '2273', descr => 'current user privilege on schema by schema oid', + proname => 'has_schema_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_schema_privilege_id' }, + +{ oid => '2390', + descr => 'user privilege on tablespace by username, tablespace name', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'name text text', + prosrc => 'has_tablespace_privilege_name_name' }, +{ oid => '2391', + descr => 'user privilege on tablespace by username, tablespace oid', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'name oid text', + prosrc => 'has_tablespace_privilege_name_id' }, +{ oid => '2392', + descr => 'user privilege on tablespace by user oid, tablespace name', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text text', + prosrc => 'has_tablespace_privilege_id_name' }, +{ oid => '2393', + descr => 'user privilege on tablespace by user oid, tablespace oid', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid oid text', + prosrc => 'has_tablespace_privilege_id_id' }, +{ oid => '2394', + descr => 'current user privilege on tablespace by tablespace name', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'text text', + prosrc => 'has_tablespace_privilege_name' }, +{ oid => '2395', + descr => 'current user privilege on tablespace by tablespace oid', + proname => 'has_tablespace_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text', + prosrc => 'has_tablespace_privilege_id' }, + +{ oid => '3000', + descr => 'user privilege on foreign data wrapper by username, foreign data wrapper name', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'name text text', + prosrc => 'has_foreign_data_wrapper_privilege_name_name' }, +{ oid => '3001', + descr => 'user privilege on foreign data wrapper by username, foreign data wrapper oid', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'name oid text', + prosrc => 'has_foreign_data_wrapper_privilege_name_id' }, +{ oid => '3002', + descr => 'user privilege on foreign data wrapper by user oid, foreign data wrapper name', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text text', + prosrc => 'has_foreign_data_wrapper_privilege_id_name' }, +{ oid => '3003', + descr => 'user privilege on foreign data wrapper by user oid, foreign data wrapper oid', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid oid text', + prosrc => 'has_foreign_data_wrapper_privilege_id_id' }, +{ oid => '3004', + descr => 'current user privilege on foreign data wrapper by foreign data wrapper name', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'text text', + prosrc => 'has_foreign_data_wrapper_privilege_name' }, +{ oid => '3005', + descr => 'current user privilege on foreign data wrapper by foreign data wrapper oid', + proname => 'has_foreign_data_wrapper_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text', + prosrc => 'has_foreign_data_wrapper_privilege_id' }, + +{ oid => '3006', descr => 'user privilege on server by username, server name', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', prosrc => 'has_server_privilege_name_name' }, +{ oid => '3007', descr => 'user privilege on server by username, server oid', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_server_privilege_name_id' }, +{ oid => '3008', descr => 'user privilege on server by user oid, server name', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_server_privilege_id_name' }, +{ oid => '3009', descr => 'user privilege on server by user oid, server oid', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_server_privilege_id_id' }, +{ oid => '3010', descr => 'current user privilege on server by server name', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_server_privilege_name' }, +{ oid => '3011', descr => 'current user privilege on server by server oid', + proname => 'has_server_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_server_privilege_id' }, + +{ oid => '3138', descr => 'user privilege on type by username, type name', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', prosrc => 'has_type_privilege_name_name' }, +{ oid => '3139', descr => 'user privilege on type by username, type oid', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_type_privilege_name_id' }, +{ oid => '3140', descr => 'user privilege on type by user oid, type name', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_type_privilege_id_name' }, +{ oid => '3141', descr => 'user privilege on type by user oid, type oid', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_type_privilege_id_id' }, +{ oid => '3142', descr => 'current user privilege on type by type name', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_type_privilege_name' }, +{ oid => '3143', descr => 'current user privilege on type by type oid', + proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_type_privilege_id' }, + +{ oid => '6205', + descr => 'user privilege on parameter by username, parameter name', + proname => 'has_parameter_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'name text text', + prosrc => 'has_parameter_privilege_name_name' }, +{ oid => '6206', + descr => 'user privilege on parameter by user oid, parameter name', + proname => 'has_parameter_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'oid text text', + prosrc => 'has_parameter_privilege_id_name' }, +{ oid => '6207', + descr => 'current user privilege on parameter by parameter name', + proname => 'has_parameter_privilege', provolatile => 's', + prorettype => 'bool', proargtypes => 'text text', + prosrc => 'has_parameter_privilege_name' }, + +{ oid => '2705', descr => 'user privilege on role by username, role name', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'name name text', prosrc => 'pg_has_role_name_name' }, +{ oid => '2706', descr => 'user privilege on role by username, role oid', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'pg_has_role_name_id' }, +{ oid => '2707', descr => 'user privilege on role by user oid, role name', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid name text', prosrc => 'pg_has_role_id_name' }, +{ oid => '2708', descr => 'user privilege on role by user oid, role oid', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'pg_has_role_id_id' }, +{ oid => '2709', descr => 'current user privilege on role by role name', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text', prosrc => 'pg_has_role_name' }, +{ oid => '2710', descr => 'current user privilege on role by role oid', + proname => 'pg_has_role', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'pg_has_role_id' }, + +{ oid => '1269', + descr => 'bytes required to store the value, perhaps with compression', + proname => 'pg_column_size', provolatile => 's', prorettype => 'int4', + proargtypes => 'any', prosrc => 'pg_column_size' }, +{ oid => '2121', descr => 'compression method for the compressed datum', + proname => 'pg_column_compression', provolatile => 's', prorettype => 'text', + proargtypes => 'any', prosrc => 'pg_column_compression' }, +{ oid => '2322', + descr => 'total disk space usage for the specified tablespace', + proname => 'pg_tablespace_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'oid', prosrc => 'pg_tablespace_size_oid' }, +{ oid => '2323', + descr => 'total disk space usage for the specified tablespace', + proname => 'pg_tablespace_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'name', prosrc => 'pg_tablespace_size_name' }, +{ oid => '2324', descr => 'total disk space usage for the specified database', + proname => 'pg_database_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'oid', prosrc => 'pg_database_size_oid' }, +{ oid => '2168', descr => 'total disk space usage for the specified database', + proname => 'pg_database_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'name', prosrc => 'pg_database_size_name' }, +{ oid => '2325', + descr => 'disk space usage for the main fork of the specified table or index', + proname => 'pg_relation_size', prolang => 'sql', provolatile => 'v', + prorettype => 'int8', proargtypes => 'regclass', + prosrc => 'see system_functions.sql' }, +{ oid => '2332', + descr => 'disk space usage for the specified fork of a table or index', + proname => 'pg_relation_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'regclass text', prosrc => 'pg_relation_size' }, +{ oid => '2286', + descr => 'total disk space usage for the specified table and associated indexes', + proname => 'pg_total_relation_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'regclass', prosrc => 'pg_total_relation_size' }, +{ oid => '2288', + descr => 'convert a long int to a human readable text using size units', + proname => 'pg_size_pretty', prorettype => 'text', proargtypes => 'int8', + prosrc => 'pg_size_pretty' }, +{ oid => '3166', + descr => 'convert a numeric to a human readable text using size units', + proname => 'pg_size_pretty', prorettype => 'text', proargtypes => 'numeric', + prosrc => 'pg_size_pretty_numeric' }, +{ oid => '3334', + descr => 'convert a size in human-readable format with size units into bytes', + proname => 'pg_size_bytes', prorettype => 'int8', proargtypes => 'text', + prosrc => 'pg_size_bytes' }, +{ oid => '2997', + descr => 'disk space usage for the specified table, including TOAST, free space and visibility map', + proname => 'pg_table_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'regclass', prosrc => 'pg_table_size' }, +{ oid => '2998', + descr => 'disk space usage for all indexes attached to the specified table', + proname => 'pg_indexes_size', provolatile => 'v', prorettype => 'int8', + proargtypes => 'regclass', prosrc => 'pg_indexes_size' }, +{ oid => '2999', descr => 'filenode identifier of relation', + proname => 'pg_relation_filenode', provolatile => 's', prorettype => 'oid', + proargtypes => 'regclass', prosrc => 'pg_relation_filenode' }, +{ oid => '3454', descr => 'relation OID for filenode and tablespace', + proname => 'pg_filenode_relation', provolatile => 's', + prorettype => 'regclass', proargtypes => 'oid oid', + prosrc => 'pg_filenode_relation' }, +{ oid => '3034', descr => 'file path of relation', + proname => 'pg_relation_filepath', provolatile => 's', prorettype => 'text', + proargtypes => 'regclass', prosrc => 'pg_relation_filepath' }, + +{ oid => '2316', descr => '(internal)', + proname => 'postgresql_fdw_validator', prorettype => 'bool', + proargtypes => '_text oid', prosrc => 'postgresql_fdw_validator' }, + +{ oid => '2290', descr => 'I/O', + proname => 'record_in', provolatile => 's', prorettype => 'record', + proargtypes => 'cstring oid int4', prosrc => 'record_in' }, +{ oid => '2291', descr => 'I/O', + proname => 'record_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'record', prosrc => 'record_out' }, +{ oid => '2292', descr => 'I/O', + proname => 'cstring_in', prorettype => 'cstring', proargtypes => 'cstring', + prosrc => 'cstring_in' }, +{ oid => '2293', descr => 'I/O', + proname => 'cstring_out', prorettype => 'cstring', proargtypes => 'cstring', + prosrc => 'cstring_out' }, +{ oid => '2294', descr => 'I/O', + proname => 'any_in', prorettype => 'any', proargtypes => 'cstring', + prosrc => 'any_in' }, +{ oid => '2295', descr => 'I/O', + proname => 'any_out', prorettype => 'cstring', proargtypes => 'any', + prosrc => 'any_out' }, +{ oid => '2296', descr => 'I/O', + proname => 'anyarray_in', prorettype => 'anyarray', proargtypes => 'cstring', + prosrc => 'anyarray_in' }, +{ oid => '2297', descr => 'I/O', + proname => 'anyarray_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyarray', prosrc => 'anyarray_out' }, +{ oid => '2298', descr => 'I/O', + proname => 'void_in', prorettype => 'void', proargtypes => 'cstring', + prosrc => 'void_in' }, +{ oid => '2299', descr => 'I/O', + proname => 'void_out', prorettype => 'cstring', proargtypes => 'void', + prosrc => 'void_out' }, +{ oid => '2300', descr => 'I/O', + proname => 'trigger_in', proisstrict => 'f', prorettype => 'trigger', + proargtypes => 'cstring', prosrc => 'trigger_in' }, +{ oid => '2301', descr => 'I/O', + proname => 'trigger_out', prorettype => 'cstring', proargtypes => 'trigger', + prosrc => 'trigger_out' }, +{ oid => '3594', descr => 'I/O', + proname => 'event_trigger_in', proisstrict => 'f', + prorettype => 'event_trigger', proargtypes => 'cstring', + prosrc => 'event_trigger_in' }, +{ oid => '3595', descr => 'I/O', + proname => 'event_trigger_out', prorettype => 'cstring', + proargtypes => 'event_trigger', prosrc => 'event_trigger_out' }, +{ oid => '2302', descr => 'I/O', + proname => 'language_handler_in', proisstrict => 'f', + prorettype => 'language_handler', proargtypes => 'cstring', + prosrc => 'language_handler_in' }, +{ oid => '2303', descr => 'I/O', + proname => 'language_handler_out', prorettype => 'cstring', + proargtypes => 'language_handler', prosrc => 'language_handler_out' }, +{ oid => '2304', descr => 'I/O', + proname => 'internal_in', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'cstring', prosrc => 'internal_in' }, +{ oid => '2305', descr => 'I/O', + proname => 'internal_out', prorettype => 'cstring', proargtypes => 'internal', + prosrc => 'internal_out' }, +{ oid => '2312', descr => 'I/O', + proname => 'anyelement_in', prorettype => 'anyelement', + proargtypes => 'cstring', prosrc => 'anyelement_in' }, +{ oid => '2313', descr => 'I/O', + proname => 'anyelement_out', prorettype => 'cstring', + proargtypes => 'anyelement', prosrc => 'anyelement_out' }, +{ oid => '2398', descr => 'I/O', + proname => 'shell_in', proisstrict => 'f', prorettype => 'void', + proargtypes => 'cstring', prosrc => 'shell_in' }, +{ oid => '2399', descr => 'I/O', + proname => 'shell_out', prorettype => 'cstring', proargtypes => 'void', + prosrc => 'shell_out' }, +{ oid => '2597', descr => 'I/O', + proname => 'domain_in', proisstrict => 'f', provolatile => 's', + prorettype => 'any', proargtypes => 'cstring oid int4', + prosrc => 'domain_in' }, +{ oid => '2598', descr => 'I/O', + proname => 'domain_recv', proisstrict => 'f', provolatile => 's', + prorettype => 'any', proargtypes => 'internal oid int4', + prosrc => 'domain_recv' }, +{ oid => '2777', descr => 'I/O', + proname => 'anynonarray_in', prorettype => 'anynonarray', + proargtypes => 'cstring', prosrc => 'anynonarray_in' }, +{ oid => '2778', descr => 'I/O', + proname => 'anynonarray_out', prorettype => 'cstring', + proargtypes => 'anynonarray', prosrc => 'anynonarray_out' }, +{ oid => '3116', descr => 'I/O', + proname => 'fdw_handler_in', proisstrict => 'f', prorettype => 'fdw_handler', + proargtypes => 'cstring', prosrc => 'fdw_handler_in' }, +{ oid => '3117', descr => 'I/O', + proname => 'fdw_handler_out', prorettype => 'cstring', + proargtypes => 'fdw_handler', prosrc => 'fdw_handler_out' }, +{ oid => '326', descr => 'I/O', + proname => 'index_am_handler_in', proisstrict => 'f', + prorettype => 'index_am_handler', proargtypes => 'cstring', + prosrc => 'index_am_handler_in' }, +{ oid => '327', descr => 'I/O', + proname => 'index_am_handler_out', prorettype => 'cstring', + proargtypes => 'index_am_handler', prosrc => 'index_am_handler_out' }, +{ oid => '3311', descr => 'I/O', + proname => 'tsm_handler_in', proisstrict => 'f', prorettype => 'tsm_handler', + proargtypes => 'cstring', prosrc => 'tsm_handler_in' }, +{ oid => '3312', descr => 'I/O', + proname => 'tsm_handler_out', prorettype => 'cstring', + proargtypes => 'tsm_handler', prosrc => 'tsm_handler_out' }, +{ oid => '267', descr => 'I/O', + proname => 'table_am_handler_in', proisstrict => 'f', + prorettype => 'table_am_handler', proargtypes => 'cstring', + prosrc => 'table_am_handler_in' }, +{ oid => '268', descr => 'I/O', + proname => 'table_am_handler_out', prorettype => 'cstring', + proargtypes => 'table_am_handler', prosrc => 'table_am_handler_out' }, +{ oid => '5086', descr => 'I/O', + proname => 'anycompatible_in', prorettype => 'anycompatible', + proargtypes => 'cstring', prosrc => 'anycompatible_in' }, +{ oid => '5087', descr => 'I/O', + proname => 'anycompatible_out', prorettype => 'cstring', + proargtypes => 'anycompatible', prosrc => 'anycompatible_out' }, +{ oid => '5088', descr => 'I/O', + proname => 'anycompatiblearray_in', prorettype => 'anycompatiblearray', + proargtypes => 'cstring', prosrc => 'anycompatiblearray_in' }, +{ oid => '5089', descr => 'I/O', + proname => 'anycompatiblearray_out', provolatile => 's', + prorettype => 'cstring', proargtypes => 'anycompatiblearray', + prosrc => 'anycompatiblearray_out' }, +{ oid => '5090', descr => 'I/O', + proname => 'anycompatiblearray_recv', provolatile => 's', + prorettype => 'anycompatiblearray', proargtypes => 'internal', + prosrc => 'anycompatiblearray_recv' }, +{ oid => '5091', descr => 'I/O', + proname => 'anycompatiblearray_send', provolatile => 's', + prorettype => 'bytea', proargtypes => 'anycompatiblearray', + prosrc => 'anycompatiblearray_send' }, +{ oid => '5092', descr => 'I/O', + proname => 'anycompatiblenonarray_in', prorettype => 'anycompatiblenonarray', + proargtypes => 'cstring', prosrc => 'anycompatiblenonarray_in' }, +{ oid => '5093', descr => 'I/O', + proname => 'anycompatiblenonarray_out', prorettype => 'cstring', + proargtypes => 'anycompatiblenonarray', + prosrc => 'anycompatiblenonarray_out' }, +{ oid => '5094', descr => 'I/O', + proname => 'anycompatiblerange_in', provolatile => 's', + prorettype => 'anycompatiblerange', proargtypes => 'cstring oid int4', + prosrc => 'anycompatiblerange_in' }, +{ oid => '5095', descr => 'I/O', + proname => 'anycompatiblerange_out', provolatile => 's', + prorettype => 'cstring', proargtypes => 'anycompatiblerange', + prosrc => 'anycompatiblerange_out' }, +{ oid => '4226', descr => 'I/O', + proname => 'anycompatiblemultirange_in', provolatile => 's', + prorettype => 'anycompatiblemultirange', proargtypes => 'cstring oid int4', + prosrc => 'anycompatiblemultirange_in' }, +{ oid => '4227', descr => 'I/O', + proname => 'anycompatiblemultirange_out', provolatile => 's', + prorettype => 'cstring', proargtypes => 'anycompatiblemultirange', + prosrc => 'anycompatiblemultirange_out' }, + +# tablesample method handlers +{ oid => '3313', descr => 'BERNOULLI tablesample method handler', + proname => 'bernoulli', provolatile => 'v', prorettype => 'tsm_handler', + proargtypes => 'internal', prosrc => 'tsm_bernoulli_handler' }, +{ oid => '3314', descr => 'SYSTEM tablesample method handler', + proname => 'system', provolatile => 'v', prorettype => 'tsm_handler', + proargtypes => 'internal', prosrc => 'tsm_system_handler' }, + +# cryptographic +{ oid => '2311', descr => 'MD5 hash', + proname => 'md5', proleakproof => 't', prorettype => 'text', + proargtypes => 'text', prosrc => 'md5_text' }, +{ oid => '2321', descr => 'MD5 hash', + proname => 'md5', proleakproof => 't', prorettype => 'text', + proargtypes => 'bytea', prosrc => 'md5_bytea' }, +{ oid => '3419', descr => 'SHA-224 hash', + proname => 'sha224', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'sha224_bytea' }, +{ oid => '3420', descr => 'SHA-256 hash', + proname => 'sha256', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'sha256_bytea' }, +{ oid => '3421', descr => 'SHA-384 hash', + proname => 'sha384', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'sha384_bytea' }, +{ oid => '3422', descr => 'SHA-512 hash', + proname => 'sha512', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'sha512_bytea' }, + +# crosstype operations for date vs. timestamp and timestamptz +{ oid => '2338', + proname => 'date_lt_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_lt_timestamp' }, +{ oid => '2339', + proname => 'date_le_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_le_timestamp' }, +{ oid => '2340', + proname => 'date_eq_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_eq_timestamp' }, +{ oid => '2341', + proname => 'date_gt_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_gt_timestamp' }, +{ oid => '2342', + proname => 'date_ge_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_ge_timestamp' }, +{ oid => '2343', + proname => 'date_ne_timestamp', prorettype => 'bool', + proargtypes => 'date timestamp', prosrc => 'date_ne_timestamp' }, +{ oid => '2344', descr => 'less-equal-greater', + proname => 'date_cmp_timestamp', prorettype => 'int4', + proargtypes => 'date timestamp', prosrc => 'date_cmp_timestamp' }, + +{ oid => '2351', + proname => 'date_lt_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_lt_timestamptz' }, +{ oid => '2352', + proname => 'date_le_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_le_timestamptz' }, +{ oid => '2353', + proname => 'date_eq_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_eq_timestamptz' }, +{ oid => '2354', + proname => 'date_gt_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_gt_timestamptz' }, +{ oid => '2355', + proname => 'date_ge_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_ge_timestamptz' }, +{ oid => '2356', + proname => 'date_ne_timestamptz', provolatile => 's', prorettype => 'bool', + proargtypes => 'date timestamptz', prosrc => 'date_ne_timestamptz' }, +{ oid => '2357', descr => 'less-equal-greater', + proname => 'date_cmp_timestamptz', provolatile => 's', prorettype => 'int4', + proargtypes => 'date timestamptz', prosrc => 'date_cmp_timestamptz' }, + +{ oid => '2364', + proname => 'timestamp_lt_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_lt_date' }, +{ oid => '2365', + proname => 'timestamp_le_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_le_date' }, +{ oid => '2366', + proname => 'timestamp_eq_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_eq_date' }, +{ oid => '2367', + proname => 'timestamp_gt_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_gt_date' }, +{ oid => '2368', + proname => 'timestamp_ge_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_ge_date' }, +{ oid => '2369', + proname => 'timestamp_ne_date', prorettype => 'bool', + proargtypes => 'timestamp date', prosrc => 'timestamp_ne_date' }, +{ oid => '2370', descr => 'less-equal-greater', + proname => 'timestamp_cmp_date', prorettype => 'int4', + proargtypes => 'timestamp date', prosrc => 'timestamp_cmp_date' }, + +{ oid => '2377', + proname => 'timestamptz_lt_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_lt_date' }, +{ oid => '2378', + proname => 'timestamptz_le_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_le_date' }, +{ oid => '2379', + proname => 'timestamptz_eq_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_eq_date' }, +{ oid => '2380', + proname => 'timestamptz_gt_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_gt_date' }, +{ oid => '2381', + proname => 'timestamptz_ge_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_ge_date' }, +{ oid => '2382', + proname => 'timestamptz_ne_date', provolatile => 's', prorettype => 'bool', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_ne_date' }, +{ oid => '2383', descr => 'less-equal-greater', + proname => 'timestamptz_cmp_date', provolatile => 's', prorettype => 'int4', + proargtypes => 'timestamptz date', prosrc => 'timestamptz_cmp_date' }, + +# crosstype operations for timestamp vs. timestamptz +{ oid => '2520', + proname => 'timestamp_lt_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_lt_timestamptz' }, +{ oid => '2521', + proname => 'timestamp_le_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_le_timestamptz' }, +{ oid => '2522', + proname => 'timestamp_eq_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_eq_timestamptz' }, +{ oid => '2523', + proname => 'timestamp_gt_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_gt_timestamptz' }, +{ oid => '2524', + proname => 'timestamp_ge_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_ge_timestamptz' }, +{ oid => '2525', + proname => 'timestamp_ne_timestamptz', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_ne_timestamptz' }, +{ oid => '2526', descr => 'less-equal-greater', + proname => 'timestamp_cmp_timestamptz', provolatile => 's', + prorettype => 'int4', proargtypes => 'timestamp timestamptz', + prosrc => 'timestamp_cmp_timestamptz' }, + +{ oid => '2527', + proname => 'timestamptz_lt_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_lt_timestamp' }, +{ oid => '2528', + proname => 'timestamptz_le_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_le_timestamp' }, +{ oid => '2529', + proname => 'timestamptz_eq_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_eq_timestamp' }, +{ oid => '2530', + proname => 'timestamptz_gt_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_gt_timestamp' }, +{ oid => '2531', + proname => 'timestamptz_ge_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_ge_timestamp' }, +{ oid => '2532', + proname => 'timestamptz_ne_timestamp', provolatile => 's', + prorettype => 'bool', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_ne_timestamp' }, +{ oid => '2533', descr => 'less-equal-greater', + proname => 'timestamptz_cmp_timestamp', provolatile => 's', + prorettype => 'int4', proargtypes => 'timestamptz timestamp', + prosrc => 'timestamptz_cmp_timestamp' }, + +# send/receive functions +{ oid => '2400', descr => 'I/O', + proname => 'array_recv', provolatile => 's', prorettype => 'anyarray', + proargtypes => 'internal oid int4', prosrc => 'array_recv' }, +{ oid => '2401', descr => 'I/O', + proname => 'array_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'anyarray', prosrc => 'array_send' }, +{ oid => '2402', descr => 'I/O', + proname => 'record_recv', provolatile => 's', prorettype => 'record', + proargtypes => 'internal oid int4', prosrc => 'record_recv' }, +{ oid => '2403', descr => 'I/O', + proname => 'record_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'record', prosrc => 'record_send' }, +{ oid => '2404', descr => 'I/O', + proname => 'int2recv', prorettype => 'int2', proargtypes => 'internal', + prosrc => 'int2recv' }, +{ oid => '2405', descr => 'I/O', + proname => 'int2send', prorettype => 'bytea', proargtypes => 'int2', + prosrc => 'int2send' }, +{ oid => '2406', descr => 'I/O', + proname => 'int4recv', prorettype => 'int4', proargtypes => 'internal', + prosrc => 'int4recv' }, +{ oid => '2407', descr => 'I/O', + proname => 'int4send', prorettype => 'bytea', proargtypes => 'int4', + prosrc => 'int4send' }, +{ oid => '2408', descr => 'I/O', + proname => 'int8recv', prorettype => 'int8', proargtypes => 'internal', + prosrc => 'int8recv' }, +{ oid => '2409', descr => 'I/O', + proname => 'int8send', prorettype => 'bytea', proargtypes => 'int8', + prosrc => 'int8send' }, +{ oid => '2410', descr => 'I/O', + proname => 'int2vectorrecv', prorettype => 'int2vector', + proargtypes => 'internal', prosrc => 'int2vectorrecv' }, +{ oid => '2411', descr => 'I/O', + proname => 'int2vectorsend', prorettype => 'bytea', + proargtypes => 'int2vector', prosrc => 'int2vectorsend' }, +{ oid => '2412', descr => 'I/O', + proname => 'bytearecv', prorettype => 'bytea', proargtypes => 'internal', + prosrc => 'bytearecv' }, +{ oid => '2413', descr => 'I/O', + proname => 'byteasend', prorettype => 'bytea', proargtypes => 'bytea', + prosrc => 'byteasend' }, +{ oid => '2414', descr => 'I/O', + proname => 'textrecv', provolatile => 's', prorettype => 'text', + proargtypes => 'internal', prosrc => 'textrecv' }, +{ oid => '2415', descr => 'I/O', + proname => 'textsend', provolatile => 's', prorettype => 'bytea', + proargtypes => 'text', prosrc => 'textsend' }, +{ oid => '2416', descr => 'I/O', + proname => 'unknownrecv', prorettype => 'unknown', proargtypes => 'internal', + prosrc => 'unknownrecv' }, +{ oid => '2417', descr => 'I/O', + proname => 'unknownsend', prorettype => 'bytea', proargtypes => 'unknown', + prosrc => 'unknownsend' }, +{ oid => '2418', descr => 'I/O', + proname => 'oidrecv', prorettype => 'oid', proargtypes => 'internal', + prosrc => 'oidrecv' }, +{ oid => '2419', descr => 'I/O', + proname => 'oidsend', prorettype => 'bytea', proargtypes => 'oid', + prosrc => 'oidsend' }, +{ oid => '2420', descr => 'I/O', + proname => 'oidvectorrecv', prorettype => 'oidvector', + proargtypes => 'internal', prosrc => 'oidvectorrecv' }, +{ oid => '2421', descr => 'I/O', + proname => 'oidvectorsend', prorettype => 'bytea', proargtypes => 'oidvector', + prosrc => 'oidvectorsend' }, +{ oid => '2422', descr => 'I/O', + proname => 'namerecv', provolatile => 's', prorettype => 'name', + proargtypes => 'internal', prosrc => 'namerecv' }, +{ oid => '2423', descr => 'I/O', + proname => 'namesend', provolatile => 's', prorettype => 'bytea', + proargtypes => 'name', prosrc => 'namesend' }, +{ oid => '2424', descr => 'I/O', + proname => 'float4recv', prorettype => 'float4', proargtypes => 'internal', + prosrc => 'float4recv' }, +{ oid => '2425', descr => 'I/O', + proname => 'float4send', prorettype => 'bytea', proargtypes => 'float4', + prosrc => 'float4send' }, +{ oid => '2426', descr => 'I/O', + proname => 'float8recv', prorettype => 'float8', proargtypes => 'internal', + prosrc => 'float8recv' }, +{ oid => '2427', descr => 'I/O', + proname => 'float8send', prorettype => 'bytea', proargtypes => 'float8', + prosrc => 'float8send' }, +{ oid => '2428', descr => 'I/O', + proname => 'point_recv', prorettype => 'point', proargtypes => 'internal', + prosrc => 'point_recv' }, +{ oid => '2429', descr => 'I/O', + proname => 'point_send', prorettype => 'bytea', proargtypes => 'point', + prosrc => 'point_send' }, +{ oid => '2430', descr => 'I/O', + proname => 'bpcharrecv', provolatile => 's', prorettype => 'bpchar', + proargtypes => 'internal oid int4', prosrc => 'bpcharrecv' }, +{ oid => '2431', descr => 'I/O', + proname => 'bpcharsend', provolatile => 's', prorettype => 'bytea', + proargtypes => 'bpchar', prosrc => 'bpcharsend' }, +{ oid => '2432', descr => 'I/O', + proname => 'varcharrecv', provolatile => 's', prorettype => 'varchar', + proargtypes => 'internal oid int4', prosrc => 'varcharrecv' }, +{ oid => '2433', descr => 'I/O', + proname => 'varcharsend', provolatile => 's', prorettype => 'bytea', + proargtypes => 'varchar', prosrc => 'varcharsend' }, +{ oid => '2434', descr => 'I/O', + proname => 'charrecv', prorettype => 'char', proargtypes => 'internal', + prosrc => 'charrecv' }, +{ oid => '2435', descr => 'I/O', + proname => 'charsend', prorettype => 'bytea', proargtypes => 'char', + prosrc => 'charsend' }, +{ oid => '2436', descr => 'I/O', + proname => 'boolrecv', prorettype => 'bool', proargtypes => 'internal', + prosrc => 'boolrecv' }, +{ oid => '2437', descr => 'I/O', + proname => 'boolsend', prorettype => 'bytea', proargtypes => 'bool', + prosrc => 'boolsend' }, +{ oid => '2438', descr => 'I/O', + proname => 'tidrecv', prorettype => 'tid', proargtypes => 'internal', + prosrc => 'tidrecv' }, +{ oid => '2439', descr => 'I/O', + proname => 'tidsend', prorettype => 'bytea', proargtypes => 'tid', + prosrc => 'tidsend' }, +{ oid => '2440', descr => 'I/O', + proname => 'xidrecv', prorettype => 'xid', proargtypes => 'internal', + prosrc => 'xidrecv' }, +{ oid => '2441', descr => 'I/O', + proname => 'xidsend', prorettype => 'bytea', proargtypes => 'xid', + prosrc => 'xidsend' }, +{ oid => '2442', descr => 'I/O', + proname => 'cidrecv', prorettype => 'cid', proargtypes => 'internal', + prosrc => 'cidrecv' }, +{ oid => '2443', descr => 'I/O', + proname => 'cidsend', prorettype => 'bytea', proargtypes => 'cid', + prosrc => 'cidsend' }, +{ oid => '2444', descr => 'I/O', + proname => 'regprocrecv', prorettype => 'regproc', proargtypes => 'internal', + prosrc => 'regprocrecv' }, +{ oid => '2445', descr => 'I/O', + proname => 'regprocsend', prorettype => 'bytea', proargtypes => 'regproc', + prosrc => 'regprocsend' }, +{ oid => '2446', descr => 'I/O', + proname => 'regprocedurerecv', prorettype => 'regprocedure', + proargtypes => 'internal', prosrc => 'regprocedurerecv' }, +{ oid => '2447', descr => 'I/O', + proname => 'regproceduresend', prorettype => 'bytea', + proargtypes => 'regprocedure', prosrc => 'regproceduresend' }, +{ oid => '2448', descr => 'I/O', + proname => 'regoperrecv', prorettype => 'regoper', proargtypes => 'internal', + prosrc => 'regoperrecv' }, +{ oid => '2449', descr => 'I/O', + proname => 'regopersend', prorettype => 'bytea', proargtypes => 'regoper', + prosrc => 'regopersend' }, +{ oid => '2450', descr => 'I/O', + proname => 'regoperatorrecv', prorettype => 'regoperator', + proargtypes => 'internal', prosrc => 'regoperatorrecv' }, +{ oid => '2451', descr => 'I/O', + proname => 'regoperatorsend', prorettype => 'bytea', + proargtypes => 'regoperator', prosrc => 'regoperatorsend' }, +{ oid => '2452', descr => 'I/O', + proname => 'regclassrecv', prorettype => 'regclass', + proargtypes => 'internal', prosrc => 'regclassrecv' }, +{ oid => '2453', descr => 'I/O', + proname => 'regclasssend', prorettype => 'bytea', proargtypes => 'regclass', + prosrc => 'regclasssend' }, +{ oid => '4196', descr => 'I/O', + proname => 'regcollationrecv', prorettype => 'regcollation', + proargtypes => 'internal', prosrc => 'regcollationrecv' }, +{ oid => '4197', descr => 'I/O', + proname => 'regcollationsend', prorettype => 'bytea', + proargtypes => 'regcollation', prosrc => 'regcollationsend' }, +{ oid => '2454', descr => 'I/O', + proname => 'regtyperecv', prorettype => 'regtype', proargtypes => 'internal', + prosrc => 'regtyperecv' }, +{ oid => '2455', descr => 'I/O', + proname => 'regtypesend', prorettype => 'bytea', proargtypes => 'regtype', + prosrc => 'regtypesend' }, + +{ oid => '4094', descr => 'I/O', + proname => 'regrolerecv', prorettype => 'regrole', proargtypes => 'internal', + prosrc => 'regrolerecv' }, +{ oid => '4095', descr => 'I/O', + proname => 'regrolesend', prorettype => 'bytea', proargtypes => 'regrole', + prosrc => 'regrolesend' }, +{ oid => '4087', descr => 'I/O', + proname => 'regnamespacerecv', prorettype => 'regnamespace', + proargtypes => 'internal', prosrc => 'regnamespacerecv' }, +{ oid => '4088', descr => 'I/O', + proname => 'regnamespacesend', prorettype => 'bytea', + proargtypes => 'regnamespace', prosrc => 'regnamespacesend' }, +{ oid => '2456', descr => 'I/O', + proname => 'bit_recv', prorettype => 'bit', + proargtypes => 'internal oid int4', prosrc => 'bit_recv' }, +{ oid => '2457', descr => 'I/O', + proname => 'bit_send', prorettype => 'bytea', proargtypes => 'bit', + prosrc => 'bit_send' }, +{ oid => '2458', descr => 'I/O', + proname => 'varbit_recv', prorettype => 'varbit', + proargtypes => 'internal oid int4', prosrc => 'varbit_recv' }, +{ oid => '2459', descr => 'I/O', + proname => 'varbit_send', prorettype => 'bytea', proargtypes => 'varbit', + prosrc => 'varbit_send' }, +{ oid => '2460', descr => 'I/O', + proname => 'numeric_recv', prorettype => 'numeric', + proargtypes => 'internal oid int4', prosrc => 'numeric_recv' }, +{ oid => '2461', descr => 'I/O', + proname => 'numeric_send', prorettype => 'bytea', proargtypes => 'numeric', + prosrc => 'numeric_send' }, +{ oid => '2468', descr => 'I/O', + proname => 'date_recv', prorettype => 'date', proargtypes => 'internal', + prosrc => 'date_recv' }, +{ oid => '2469', descr => 'I/O', + proname => 'date_send', prorettype => 'bytea', proargtypes => 'date', + prosrc => 'date_send' }, +{ oid => '2470', descr => 'I/O', + proname => 'time_recv', prorettype => 'time', + proargtypes => 'internal oid int4', prosrc => 'time_recv' }, +{ oid => '2471', descr => 'I/O', + proname => 'time_send', prorettype => 'bytea', proargtypes => 'time', + prosrc => 'time_send' }, +{ oid => '2472', descr => 'I/O', + proname => 'timetz_recv', prorettype => 'timetz', + proargtypes => 'internal oid int4', prosrc => 'timetz_recv' }, +{ oid => '2473', descr => 'I/O', + proname => 'timetz_send', prorettype => 'bytea', proargtypes => 'timetz', + prosrc => 'timetz_send' }, +{ oid => '2474', descr => 'I/O', + proname => 'timestamp_recv', prorettype => 'timestamp', + proargtypes => 'internal oid int4', prosrc => 'timestamp_recv' }, +{ oid => '2475', descr => 'I/O', + proname => 'timestamp_send', prorettype => 'bytea', + proargtypes => 'timestamp', prosrc => 'timestamp_send' }, +{ oid => '2476', descr => 'I/O', + proname => 'timestamptz_recv', prorettype => 'timestamptz', + proargtypes => 'internal oid int4', prosrc => 'timestamptz_recv' }, +{ oid => '2477', descr => 'I/O', + proname => 'timestamptz_send', prorettype => 'bytea', + proargtypes => 'timestamptz', prosrc => 'timestamptz_send' }, +{ oid => '2478', descr => 'I/O', + proname => 'interval_recv', prorettype => 'interval', + proargtypes => 'internal oid int4', prosrc => 'interval_recv' }, +{ oid => '2479', descr => 'I/O', + proname => 'interval_send', prorettype => 'bytea', proargtypes => 'interval', + prosrc => 'interval_send' }, +{ oid => '2480', descr => 'I/O', + proname => 'lseg_recv', prorettype => 'lseg', proargtypes => 'internal', + prosrc => 'lseg_recv' }, +{ oid => '2481', descr => 'I/O', + proname => 'lseg_send', prorettype => 'bytea', proargtypes => 'lseg', + prosrc => 'lseg_send' }, +{ oid => '2482', descr => 'I/O', + proname => 'path_recv', prorettype => 'path', proargtypes => 'internal', + prosrc => 'path_recv' }, +{ oid => '2483', descr => 'I/O', + proname => 'path_send', prorettype => 'bytea', proargtypes => 'path', + prosrc => 'path_send' }, +{ oid => '2484', descr => 'I/O', + proname => 'box_recv', prorettype => 'box', proargtypes => 'internal', + prosrc => 'box_recv' }, +{ oid => '2485', descr => 'I/O', + proname => 'box_send', prorettype => 'bytea', proargtypes => 'box', + prosrc => 'box_send' }, +{ oid => '2486', descr => 'I/O', + proname => 'poly_recv', prorettype => 'polygon', proargtypes => 'internal', + prosrc => 'poly_recv' }, +{ oid => '2487', descr => 'I/O', + proname => 'poly_send', prorettype => 'bytea', proargtypes => 'polygon', + prosrc => 'poly_send' }, +{ oid => '2488', descr => 'I/O', + proname => 'line_recv', prorettype => 'line', proargtypes => 'internal', + prosrc => 'line_recv' }, +{ oid => '2489', descr => 'I/O', + proname => 'line_send', prorettype => 'bytea', proargtypes => 'line', + prosrc => 'line_send' }, +{ oid => '2490', descr => 'I/O', + proname => 'circle_recv', prorettype => 'circle', proargtypes => 'internal', + prosrc => 'circle_recv' }, +{ oid => '2491', descr => 'I/O', + proname => 'circle_send', prorettype => 'bytea', proargtypes => 'circle', + prosrc => 'circle_send' }, +{ oid => '2492', descr => 'I/O', + proname => 'cash_recv', prorettype => 'money', proargtypes => 'internal', + prosrc => 'cash_recv' }, +{ oid => '2493', descr => 'I/O', + proname => 'cash_send', prorettype => 'bytea', proargtypes => 'money', + prosrc => 'cash_send' }, +{ oid => '2494', descr => 'I/O', + proname => 'macaddr_recv', prorettype => 'macaddr', proargtypes => 'internal', + prosrc => 'macaddr_recv' }, +{ oid => '2495', descr => 'I/O', + proname => 'macaddr_send', prorettype => 'bytea', proargtypes => 'macaddr', + prosrc => 'macaddr_send' }, +{ oid => '2496', descr => 'I/O', + proname => 'inet_recv', prorettype => 'inet', proargtypes => 'internal', + prosrc => 'inet_recv' }, +{ oid => '2497', descr => 'I/O', + proname => 'inet_send', prorettype => 'bytea', proargtypes => 'inet', + prosrc => 'inet_send' }, +{ oid => '2498', descr => 'I/O', + proname => 'cidr_recv', prorettype => 'cidr', proargtypes => 'internal', + prosrc => 'cidr_recv' }, +{ oid => '2499', descr => 'I/O', + proname => 'cidr_send', prorettype => 'bytea', proargtypes => 'cidr', + prosrc => 'cidr_send' }, +{ oid => '2500', descr => 'I/O', + proname => 'cstring_recv', provolatile => 's', prorettype => 'cstring', + proargtypes => 'internal', prosrc => 'cstring_recv' }, +{ oid => '2501', descr => 'I/O', + proname => 'cstring_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'cstring', prosrc => 'cstring_send' }, +{ oid => '2502', descr => 'I/O', + proname => 'anyarray_recv', provolatile => 's', prorettype => 'anyarray', + proargtypes => 'internal', prosrc => 'anyarray_recv' }, +{ oid => '2503', descr => 'I/O', + proname => 'anyarray_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'anyarray', prosrc => 'anyarray_send' }, +{ oid => '3120', descr => 'I/O', + proname => 'void_recv', prorettype => 'void', proargtypes => 'internal', + prosrc => 'void_recv' }, +{ oid => '3121', descr => 'I/O', + proname => 'void_send', prorettype => 'bytea', proargtypes => 'void', + prosrc => 'void_send' }, +{ oid => '3446', descr => 'I/O', + proname => 'macaddr8_recv', prorettype => 'macaddr8', + proargtypes => 'internal', prosrc => 'macaddr8_recv' }, +{ oid => '3447', descr => 'I/O', + proname => 'macaddr8_send', prorettype => 'bytea', proargtypes => 'macaddr8', + prosrc => 'macaddr8_send' }, + +# System-view support functions with pretty-print option +{ oid => '2504', descr => 'source text of a rule with pretty-print option', + proname => 'pg_get_ruledef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid bool', prosrc => 'pg_get_ruledef_ext' }, +{ oid => '2505', + descr => 'select statement of a view with pretty-print option', + proname => 'pg_get_viewdef', provolatile => 's', proparallel => 'r', + prorettype => 'text', proargtypes => 'text bool', + prosrc => 'pg_get_viewdef_name_ext' }, +{ oid => '2506', + descr => 'select statement of a view with pretty-print option', + proname => 'pg_get_viewdef', provolatile => 's', proparallel => 'r', + prorettype => 'text', proargtypes => 'oid bool', + prosrc => 'pg_get_viewdef_ext' }, +{ oid => '3159', + descr => 'select statement of a view with pretty-printing and specified line wrapping', + proname => 'pg_get_viewdef', provolatile => 's', proparallel => 'r', + prorettype => 'text', proargtypes => 'oid int4', + prosrc => 'pg_get_viewdef_wrap' }, +{ oid => '2507', + descr => 'index description (full create statement or single expression) with pretty-print option', + proname => 'pg_get_indexdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid int4 bool', prosrc => 'pg_get_indexdef_ext' }, +{ oid => '2508', descr => 'constraint description with pretty-print option', + proname => 'pg_get_constraintdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid bool', prosrc => 'pg_get_constraintdef_ext' }, +{ oid => '2509', + descr => 'deparse an encoded expression with pretty-print option', + proname => 'pg_get_expr', provolatile => 's', prorettype => 'text', + proargtypes => 'pg_node_tree oid bool', prosrc => 'pg_get_expr_ext' }, +{ oid => '2510', descr => 'get the prepared statements for this session', + proname => 'pg_prepared_statement', prorows => '1000', proretset => 't', + provolatile => 's', proparallel => 'r', prorettype => 'record', + proargtypes => '', + proallargtypes => '{text,text,timestamptz,_regtype,bool,int8,int8}', + proargmodes => '{o,o,o,o,o,o,o}', + proargnames => '{name,statement,prepare_time,parameter_types,from_sql,generic_plans,custom_plans}', + prosrc => 'pg_prepared_statement' }, +{ oid => '2511', descr => 'get the open cursors for this session', + proname => 'pg_cursor', prorows => '1000', proretset => 't', + provolatile => 's', proparallel => 'r', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,text,bool,bool,bool,timestamptz}', + proargmodes => '{o,o,o,o,o,o}', + proargnames => '{name,statement,is_holdable,is_binary,is_scrollable,creation_time}', + prosrc => 'pg_cursor' }, +{ oid => '2599', descr => 'get the available time zone abbreviations', + proname => 'pg_timezone_abbrevs', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,interval,bool}', proargmodes => '{o,o,o}', + proargnames => '{abbrev,utc_offset,is_dst}', + prosrc => 'pg_timezone_abbrevs' }, +{ oid => '2856', descr => 'get the available time zone names', + proname => 'pg_timezone_names', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,text,interval,bool}', proargmodes => '{o,o,o,o}', + proargnames => '{name,abbrev,utc_offset,is_dst}', + prosrc => 'pg_timezone_names' }, +{ oid => '2730', descr => 'trigger description with pretty-print option', + proname => 'pg_get_triggerdef', provolatile => 's', prorettype => 'text', + proargtypes => 'oid bool', prosrc => 'pg_get_triggerdef_ext' }, + +# asynchronous notifications +{ oid => '3035', + descr => 'get the channels that the current backend listens to', + proname => 'pg_listening_channels', prorows => '10', proretset => 't', + provolatile => 's', proparallel => 'r', prorettype => 'text', + proargtypes => '', prosrc => 'pg_listening_channels' }, +{ oid => '3036', descr => 'send a notification event', + proname => 'pg_notify', proisstrict => 'f', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'text text', + prosrc => 'pg_notify' }, +{ oid => '3296', + descr => 'get the fraction of the asynchronous notification queue currently in use', + proname => 'pg_notification_queue_usage', provolatile => 'v', + proparallel => 'r', prorettype => 'float8', proargtypes => '', + prosrc => 'pg_notification_queue_usage' }, + +# shared memory usage +{ oid => '5052', descr => 'allocations from the main shared memory segment', + proname => 'pg_get_shmem_allocations', prorows => '50', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8,int8,int8}', proargmodes => '{o,o,o,o}', + proargnames => '{name,off,size,allocated_size}', + prosrc => 'pg_get_shmem_allocations' }, + +# memory context of local backend +{ oid => '2282', + descr => 'information about all memory contexts of local backend', + proname => 'pg_get_backend_memory_contexts', prorows => '100', + proretset => 't', provolatile => 'v', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{text,text,text,int4,int8,int8,int8,int8,int8}', + proargmodes => '{o,o,o,o,o,o,o,o,o}', + proargnames => '{name, ident, parent, level, total_bytes, total_nblocks, free_bytes, free_chunks, used_bytes}', + prosrc => 'pg_get_backend_memory_contexts' }, + +# logging memory contexts of the specified backend +{ oid => '4543', descr => 'log memory contexts of the specified backend', + proname => 'pg_log_backend_memory_contexts', provolatile => 'v', + prorettype => 'bool', proargtypes => 'int4', + prosrc => 'pg_log_backend_memory_contexts' }, + +# non-persistent series generator +{ oid => '1066', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_int4_support', proretset => 't', + prorettype => 'int4', proargtypes => 'int4 int4 int4', + prosrc => 'generate_series_step_int4' }, +{ oid => '1067', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_int4_support', proretset => 't', + prorettype => 'int4', proargtypes => 'int4 int4', + prosrc => 'generate_series_int4' }, +{ oid => '3994', descr => 'planner support for generate_series', + proname => 'generate_series_int4_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'generate_series_int4_support' }, +{ oid => '1068', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_int8_support', proretset => 't', + prorettype => 'int8', proargtypes => 'int8 int8 int8', + prosrc => 'generate_series_step_int8' }, +{ oid => '1069', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_int8_support', proretset => 't', + prorettype => 'int8', proargtypes => 'int8 int8', + prosrc => 'generate_series_int8' }, +{ oid => '3995', descr => 'planner support for generate_series', + proname => 'generate_series_int8_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'generate_series_int8_support' }, +{ oid => '3259', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', proretset => 't', + prorettype => 'numeric', proargtypes => 'numeric numeric numeric', + prosrc => 'generate_series_step_numeric' }, +{ oid => '3260', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', proretset => 't', + prorettype => 'numeric', proargtypes => 'numeric numeric', + prosrc => 'generate_series_numeric' }, +{ oid => '938', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', proretset => 't', + prorettype => 'timestamp', proargtypes => 'timestamp timestamp interval', + prosrc => 'generate_series_timestamp' }, +{ oid => '939', descr => 'non-persistent series generator', + proname => 'generate_series', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'timestamptz', + proargtypes => 'timestamptz timestamptz interval', + prosrc => 'generate_series_timestamptz' }, + +# boolean aggregates +{ oid => '2515', descr => 'aggregate transition function', + proname => 'booland_statefunc', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'booland_statefunc' }, +{ oid => '2516', descr => 'aggregate transition function', + proname => 'boolor_statefunc', prorettype => 'bool', + proargtypes => 'bool bool', prosrc => 'boolor_statefunc' }, +{ oid => '3496', descr => 'aggregate transition function', + proname => 'bool_accum', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal bool', prosrc => 'bool_accum' }, +{ oid => '3497', descr => 'aggregate transition function', + proname => 'bool_accum_inv', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal bool', prosrc => 'bool_accum_inv' }, +{ oid => '3498', descr => 'aggregate final function', + proname => 'bool_alltrue', prorettype => 'bool', proargtypes => 'internal', + prosrc => 'bool_alltrue' }, +{ oid => '3499', descr => 'aggregate final function', + proname => 'bool_anytrue', prorettype => 'bool', proargtypes => 'internal', + prosrc => 'bool_anytrue' }, +{ oid => '2517', descr => 'boolean-and aggregate', + proname => 'bool_and', prokind => 'a', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'bool', prosrc => 'aggregate_dummy' }, + +# ANY, SOME? These names conflict with subquery operators. See doc. +{ oid => '2518', descr => 'boolean-or aggregate', + proname => 'bool_or', prokind => 'a', proisstrict => 'f', + prorettype => 'bool', proargtypes => 'bool', prosrc => 'aggregate_dummy' }, +{ oid => '2519', descr => 'boolean-and aggregate', + proname => 'every', prokind => 'a', proisstrict => 'f', prorettype => 'bool', + proargtypes => 'bool', prosrc => 'aggregate_dummy' }, + +# bitwise integer aggregates +{ oid => '2236', descr => 'bitwise-and smallint aggregate', + proname => 'bit_and', prokind => 'a', proisstrict => 'f', + prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2237', descr => 'bitwise-or smallint aggregate', + proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int2', + proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '6164', descr => 'bitwise-xor smallint aggregate', + proname => 'bit_xor', prokind => 'a', proisstrict => 'f', + prorettype => 'int2', proargtypes => 'int2', prosrc => 'aggregate_dummy' }, +{ oid => '2238', descr => 'bitwise-and integer aggregate', + proname => 'bit_and', prokind => 'a', proisstrict => 'f', + prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2239', descr => 'bitwise-or integer aggregate', + proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int4', + proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '6165', descr => 'bitwise-xor integer aggregate', + proname => 'bit_xor', prokind => 'a', proisstrict => 'f', + prorettype => 'int4', proargtypes => 'int4', prosrc => 'aggregate_dummy' }, +{ oid => '2240', descr => 'bitwise-and bigint aggregate', + proname => 'bit_and', prokind => 'a', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2241', descr => 'bitwise-or bigint aggregate', + proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'int8', + proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '6166', descr => 'bitwise-xor bigint aggregate', + proname => 'bit_xor', prokind => 'a', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'int8', prosrc => 'aggregate_dummy' }, +{ oid => '2242', descr => 'bitwise-and bit aggregate', + proname => 'bit_and', prokind => 'a', proisstrict => 'f', prorettype => 'bit', + proargtypes => 'bit', prosrc => 'aggregate_dummy' }, +{ oid => '2243', descr => 'bitwise-or bit aggregate', + proname => 'bit_or', prokind => 'a', proisstrict => 'f', prorettype => 'bit', + proargtypes => 'bit', prosrc => 'aggregate_dummy' }, +{ oid => '6167', descr => 'bitwise-xor bit aggregate', + proname => 'bit_xor', prokind => 'a', proisstrict => 'f', prorettype => 'bit', + proargtypes => 'bit', prosrc => 'aggregate_dummy' }, + +# formerly-missing interval + datetime operators +{ oid => '2546', + proname => 'interval_pl_date', prolang => 'sql', prorettype => 'timestamp', + proargtypes => 'interval date', prosrc => 'see system_functions.sql' }, +{ oid => '2547', + proname => 'interval_pl_timetz', prolang => 'sql', prorettype => 'timetz', + proargtypes => 'interval timetz', prosrc => 'see system_functions.sql' }, +{ oid => '2548', + proname => 'interval_pl_timestamp', prolang => 'sql', + prorettype => 'timestamp', proargtypes => 'interval timestamp', + prosrc => 'see system_functions.sql' }, +{ oid => '2549', + proname => 'interval_pl_timestamptz', prolang => 'sql', provolatile => 's', + prorettype => 'timestamptz', proargtypes => 'interval timestamptz', + prosrc => 'see system_functions.sql' }, +{ oid => '2550', + proname => 'integer_pl_date', prolang => 'sql', prorettype => 'date', + proargtypes => 'int4 date', prosrc => 'see system_functions.sql' }, + +{ oid => '2556', descr => 'get OIDs of databases in a tablespace', + proname => 'pg_tablespace_databases', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'oid', proargtypes => 'oid', + prosrc => 'pg_tablespace_databases' }, + +{ oid => '2557', descr => 'convert int4 to boolean', + proname => 'bool', proleakproof => 't', prorettype => 'bool', + proargtypes => 'int4', prosrc => 'int4_bool' }, +{ oid => '2558', descr => 'convert boolean to int4', + proname => 'int4', proleakproof => 't', prorettype => 'int4', + proargtypes => 'bool', prosrc => 'bool_int4' }, +{ oid => '2559', descr => 'current value from last used sequence', + proname => 'lastval', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => '', prosrc => 'lastval' }, + +# start time function +{ oid => '2560', descr => 'postmaster start time', + proname => 'pg_postmaster_start_time', provolatile => 's', + prorettype => 'timestamptz', proargtypes => '', + prosrc => 'pg_postmaster_start_time' }, + +# config reload time function +{ oid => '2034', descr => 'configuration load time', + proname => 'pg_conf_load_time', provolatile => 's', proparallel => 'r', + prorettype => 'timestamptz', proargtypes => '', + prosrc => 'pg_conf_load_time' }, + +# new functions for Y-direction rtree opclasses +{ oid => '2562', + proname => 'box_below', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_below' }, +{ oid => '2563', + proname => 'box_overbelow', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_overbelow' }, +{ oid => '2564', + proname => 'box_overabove', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_overabove' }, +{ oid => '2565', + proname => 'box_above', prorettype => 'bool', proargtypes => 'box box', + prosrc => 'box_above' }, +{ oid => '2566', + proname => 'poly_below', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_below' }, +{ oid => '2567', + proname => 'poly_overbelow', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_overbelow' }, +{ oid => '2568', + proname => 'poly_overabove', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_overabove' }, +{ oid => '2569', + proname => 'poly_above', prorettype => 'bool', + proargtypes => 'polygon polygon', prosrc => 'poly_above' }, +{ oid => '2587', + proname => 'circle_overbelow', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_overbelow' }, +{ oid => '2588', + proname => 'circle_overabove', prorettype => 'bool', + proargtypes => 'circle circle', prosrc => 'circle_overabove' }, + +# support functions for GiST r-tree emulation +{ oid => '2578', descr => 'GiST support', + proname => 'gist_box_consistent', prorettype => 'bool', + proargtypes => 'internal box int2 oid internal', + prosrc => 'gist_box_consistent' }, +{ oid => '2581', descr => 'GiST support', + proname => 'gist_box_penalty', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'gist_box_penalty' }, +{ oid => '2582', descr => 'GiST support', + proname => 'gist_box_picksplit', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'gist_box_picksplit' }, +{ oid => '2583', descr => 'GiST support', + proname => 'gist_box_union', prorettype => 'box', + proargtypes => 'internal internal', prosrc => 'gist_box_union' }, +{ oid => '2584', descr => 'GiST support', + proname => 'gist_box_same', prorettype => 'internal', + proargtypes => 'box box internal', prosrc => 'gist_box_same' }, +{ oid => '3998', descr => 'GiST support', + proname => 'gist_box_distance', prorettype => 'float8', + proargtypes => 'internal box int2 oid internal', + prosrc => 'gist_box_distance' }, +{ oid => '2585', descr => 'GiST support', + proname => 'gist_poly_consistent', prorettype => 'bool', + proargtypes => 'internal polygon int2 oid internal', + prosrc => 'gist_poly_consistent' }, +{ oid => '2586', descr => 'GiST support', + proname => 'gist_poly_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gist_poly_compress' }, +{ oid => '2591', descr => 'GiST support', + proname => 'gist_circle_consistent', prorettype => 'bool', + proargtypes => 'internal circle int2 oid internal', + prosrc => 'gist_circle_consistent' }, +{ oid => '2592', descr => 'GiST support', + proname => 'gist_circle_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gist_circle_compress' }, +{ oid => '1030', descr => 'GiST support', + proname => 'gist_point_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gist_point_compress' }, +{ oid => '3282', descr => 'GiST support', + proname => 'gist_point_fetch', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gist_point_fetch' }, +{ oid => '2179', descr => 'GiST support', + proname => 'gist_point_consistent', prorettype => 'bool', + proargtypes => 'internal point int2 oid internal', + prosrc => 'gist_point_consistent' }, +{ oid => '3064', descr => 'GiST support', + proname => 'gist_point_distance', prorettype => 'float8', + proargtypes => 'internal point int2 oid internal', + prosrc => 'gist_point_distance' }, +{ oid => '3280', descr => 'GiST support', + proname => 'gist_circle_distance', prorettype => 'float8', + proargtypes => 'internal circle int2 oid internal', + prosrc => 'gist_circle_distance' }, +{ oid => '3288', descr => 'GiST support', + proname => 'gist_poly_distance', prorettype => 'float8', + proargtypes => 'internal polygon int2 oid internal', + prosrc => 'gist_poly_distance' }, +{ oid => '3435', descr => 'sort support', + proname => 'gist_point_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'gist_point_sortsupport' }, + +# GIN array support +{ oid => '2743', descr => 'GIN array support', + proname => 'ginarrayextract', prorettype => 'internal', + proargtypes => 'anyarray internal internal', prosrc => 'ginarrayextract' }, +{ oid => '2774', descr => 'GIN array support', + proname => 'ginqueryarrayextract', prorettype => 'internal', + proargtypes => 'anyarray internal int2 internal internal internal internal', + prosrc => 'ginqueryarrayextract' }, +{ oid => '2744', descr => 'GIN array support', + proname => 'ginarrayconsistent', prorettype => 'bool', + proargtypes => 'internal int2 anyarray int4 internal internal internal internal', + prosrc => 'ginarrayconsistent' }, +{ oid => '3920', descr => 'GIN array support', + proname => 'ginarraytriconsistent', prorettype => 'char', + proargtypes => 'internal int2 anyarray int4 internal internal internal', + prosrc => 'ginarraytriconsistent' }, +{ oid => '3076', descr => 'GIN array support (obsolete)', + proname => 'ginarrayextract', prorettype => 'internal', + proargtypes => 'anyarray internal', prosrc => 'ginarrayextract_2args' }, + +# overlap/contains/contained +{ oid => '2747', + proname => 'arrayoverlap', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'arrayoverlap' }, +{ oid => '2748', + proname => 'arraycontains', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'arraycontains' }, +{ oid => '2749', + proname => 'arraycontained', prorettype => 'bool', + proargtypes => 'anyarray anyarray', prosrc => 'arraycontained' }, + +# BRIN minmax +{ oid => '3383', descr => 'BRIN minmax support', + proname => 'brin_minmax_opcinfo', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'brin_minmax_opcinfo' }, +{ oid => '3384', descr => 'BRIN minmax support', + proname => 'brin_minmax_add_value', prorettype => 'bool', + proargtypes => 'internal internal internal internal', + prosrc => 'brin_minmax_add_value' }, +{ oid => '3385', descr => 'BRIN minmax support', + proname => 'brin_minmax_consistent', prorettype => 'bool', + proargtypes => 'internal internal internal', + prosrc => 'brin_minmax_consistent' }, +{ oid => '3386', descr => 'BRIN minmax support', + proname => 'brin_minmax_union', prorettype => 'bool', + proargtypes => 'internal internal internal', prosrc => 'brin_minmax_union' }, + +# BRIN minmax multi +{ oid => '4616', descr => 'BRIN multi minmax support', + proname => 'brin_minmax_multi_opcinfo', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'brin_minmax_multi_opcinfo' }, +{ oid => '4617', descr => 'BRIN multi minmax support', + proname => 'brin_minmax_multi_add_value', prorettype => 'bool', + proargtypes => 'internal internal internal internal', + prosrc => 'brin_minmax_multi_add_value' }, +{ oid => '4618', descr => 'BRIN multi minmax support', + proname => 'brin_minmax_multi_consistent', prorettype => 'bool', + proargtypes => 'internal internal internal int4', + prosrc => 'brin_minmax_multi_consistent' }, +{ oid => '4619', descr => 'BRIN multi minmax support', + proname => 'brin_minmax_multi_union', prorettype => 'bool', + proargtypes => 'internal internal internal', + prosrc => 'brin_minmax_multi_union' }, +{ oid => '4620', descr => 'BRIN multi minmax support', + proname => 'brin_minmax_multi_options', proisstrict => 'f', + prorettype => 'void', proargtypes => 'internal', + prosrc => 'brin_minmax_multi_options' }, + +{ oid => '4621', descr => 'BRIN multi minmax int2 distance', + proname => 'brin_minmax_multi_distance_int2', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_int2' }, +{ oid => '4622', descr => 'BRIN multi minmax int4 distance', + proname => 'brin_minmax_multi_distance_int4', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_int4' }, +{ oid => '4623', descr => 'BRIN multi minmax int8 distance', + proname => 'brin_minmax_multi_distance_int8', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_int8' }, +{ oid => '4624', descr => 'BRIN multi minmax float4 distance', + proname => 'brin_minmax_multi_distance_float4', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_float4' }, +{ oid => '4625', descr => 'BRIN multi minmax float8 distance', + proname => 'brin_minmax_multi_distance_float8', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_float8' }, +{ oid => '4626', descr => 'BRIN multi minmax numeric distance', + proname => 'brin_minmax_multi_distance_numeric', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_numeric' }, +{ oid => '4627', descr => 'BRIN multi minmax tid distance', + proname => 'brin_minmax_multi_distance_tid', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_tid' }, +{ oid => '4628', descr => 'BRIN multi minmax uuid distance', + proname => 'brin_minmax_multi_distance_uuid', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_uuid' }, +{ oid => '4629', descr => 'BRIN multi minmax date distance', + proname => 'brin_minmax_multi_distance_date', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_date' }, +{ oid => '4630', descr => 'BRIN multi minmax time distance', + proname => 'brin_minmax_multi_distance_time', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_time' }, +{ oid => '4631', descr => 'BRIN multi minmax interval distance', + proname => 'brin_minmax_multi_distance_interval', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_interval' }, +{ oid => '4632', descr => 'BRIN multi minmax timetz distance', + proname => 'brin_minmax_multi_distance_timetz', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_timetz' }, +{ oid => '4633', descr => 'BRIN multi minmax pg_lsn distance', + proname => 'brin_minmax_multi_distance_pg_lsn', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_pg_lsn' }, +{ oid => '4634', descr => 'BRIN multi minmax macaddr distance', + proname => 'brin_minmax_multi_distance_macaddr', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_macaddr' }, +{ oid => '4635', descr => 'BRIN multi minmax macaddr8 distance', + proname => 'brin_minmax_multi_distance_macaddr8', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_macaddr8' }, +{ oid => '4636', descr => 'BRIN multi minmax inet distance', + proname => 'brin_minmax_multi_distance_inet', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_inet' }, +{ oid => '4637', descr => 'BRIN multi minmax timestamp distance', + proname => 'brin_minmax_multi_distance_timestamp', prorettype => 'float8', + proargtypes => 'internal internal', + prosrc => 'brin_minmax_multi_distance_timestamp' }, + +# BRIN inclusion +{ oid => '4105', descr => 'BRIN inclusion support', + proname => 'brin_inclusion_opcinfo', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'brin_inclusion_opcinfo' }, +{ oid => '4106', descr => 'BRIN inclusion support', + proname => 'brin_inclusion_add_value', prorettype => 'bool', + proargtypes => 'internal internal internal internal', + prosrc => 'brin_inclusion_add_value' }, +{ oid => '4107', descr => 'BRIN inclusion support', + proname => 'brin_inclusion_consistent', prorettype => 'bool', + proargtypes => 'internal internal internal', + prosrc => 'brin_inclusion_consistent' }, +{ oid => '4108', descr => 'BRIN inclusion support', + proname => 'brin_inclusion_union', prorettype => 'bool', + proargtypes => 'internal internal internal', + prosrc => 'brin_inclusion_union' }, + +# BRIN bloom +{ oid => '4591', descr => 'BRIN bloom support', + proname => 'brin_bloom_opcinfo', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'brin_bloom_opcinfo' }, +{ oid => '4592', descr => 'BRIN bloom support', + proname => 'brin_bloom_add_value', prorettype => 'bool', + proargtypes => 'internal internal internal internal', + prosrc => 'brin_bloom_add_value' }, +{ oid => '4593', descr => 'BRIN bloom support', + proname => 'brin_bloom_consistent', prorettype => 'bool', + proargtypes => 'internal internal internal int4', + prosrc => 'brin_bloom_consistent' }, +{ oid => '4594', descr => 'BRIN bloom support', + proname => 'brin_bloom_union', prorettype => 'bool', + proargtypes => 'internal internal internal', prosrc => 'brin_bloom_union' }, +{ oid => '4595', descr => 'BRIN bloom support', + proname => 'brin_bloom_options', proisstrict => 'f', prorettype => 'void', + proargtypes => 'internal', prosrc => 'brin_bloom_options' }, + +# userlock replacements +{ oid => '2880', descr => 'obtain exclusive advisory lock', + proname => 'pg_advisory_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int8', + prosrc => 'pg_advisory_lock_int8' }, +{ oid => '3089', descr => 'obtain exclusive advisory lock', + proname => 'pg_advisory_xact_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int8', + prosrc => 'pg_advisory_xact_lock_int8' }, +{ oid => '2881', descr => 'obtain shared advisory lock', + proname => 'pg_advisory_lock_shared', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int8', + prosrc => 'pg_advisory_lock_shared_int8' }, +{ oid => '3090', descr => 'obtain shared advisory lock', + proname => 'pg_advisory_xact_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'int8', + prosrc => 'pg_advisory_xact_lock_shared_int8' }, +{ oid => '2882', descr => 'obtain exclusive advisory lock if available', + proname => 'pg_try_advisory_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_try_advisory_lock_int8' }, +{ oid => '3091', descr => 'obtain exclusive advisory lock if available', + proname => 'pg_try_advisory_xact_lock', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_try_advisory_xact_lock_int8' }, +{ oid => '2883', descr => 'obtain shared advisory lock if available', + proname => 'pg_try_advisory_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_try_advisory_lock_shared_int8' }, +{ oid => '3092', descr => 'obtain shared advisory lock if available', + proname => 'pg_try_advisory_xact_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_try_advisory_xact_lock_shared_int8' }, +{ oid => '2884', descr => 'release exclusive advisory lock', + proname => 'pg_advisory_unlock', provolatile => 'v', proparallel => 'r', + prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_advisory_unlock_int8' }, +{ oid => '2885', descr => 'release shared advisory lock', + proname => 'pg_advisory_unlock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int8', + prosrc => 'pg_advisory_unlock_shared_int8' }, +{ oid => '2886', descr => 'obtain exclusive advisory lock', + proname => 'pg_advisory_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_lock_int4' }, +{ oid => '3093', descr => 'obtain exclusive advisory lock', + proname => 'pg_advisory_xact_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_xact_lock_int4' }, +{ oid => '2887', descr => 'obtain shared advisory lock', + proname => 'pg_advisory_lock_shared', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_lock_shared_int4' }, +{ oid => '3094', descr => 'obtain shared advisory lock', + proname => 'pg_advisory_xact_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_xact_lock_shared_int4' }, +{ oid => '2888', descr => 'obtain exclusive advisory lock if available', + proname => 'pg_try_advisory_lock', provolatile => 'v', proparallel => 'r', + prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_try_advisory_lock_int4' }, +{ oid => '3095', descr => 'obtain exclusive advisory lock if available', + proname => 'pg_try_advisory_xact_lock', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_try_advisory_xact_lock_int4' }, +{ oid => '2889', descr => 'obtain shared advisory lock if available', + proname => 'pg_try_advisory_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_try_advisory_lock_shared_int4' }, +{ oid => '3096', descr => 'obtain shared advisory lock if available', + proname => 'pg_try_advisory_xact_lock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_try_advisory_xact_lock_shared_int4' }, +{ oid => '2890', descr => 'release exclusive advisory lock', + proname => 'pg_advisory_unlock', provolatile => 'v', proparallel => 'r', + prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_unlock_int4' }, +{ oid => '2891', descr => 'release shared advisory lock', + proname => 'pg_advisory_unlock_shared', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => 'int4 int4', + prosrc => 'pg_advisory_unlock_shared_int4' }, +{ oid => '2892', descr => 'release all advisory locks', + proname => 'pg_advisory_unlock_all', provolatile => 'v', proparallel => 'r', + prorettype => 'void', proargtypes => '', prosrc => 'pg_advisory_unlock_all' }, + +# XML support +{ oid => '2893', descr => 'I/O', + proname => 'xml_in', provolatile => 's', prorettype => 'xml', + proargtypes => 'cstring', prosrc => 'xml_in' }, +{ oid => '2894', descr => 'I/O', + proname => 'xml_out', prorettype => 'cstring', proargtypes => 'xml', + prosrc => 'xml_out' }, +{ oid => '2895', descr => 'generate XML comment', + proname => 'xmlcomment', prorettype => 'xml', proargtypes => 'text', + prosrc => 'xmlcomment' }, +{ oid => '2896', + descr => 'perform a non-validating parse of a character string to produce an XML value', + proname => 'xml', provolatile => 's', prorettype => 'xml', + proargtypes => 'text', prosrc => 'texttoxml' }, +{ oid => '2897', descr => 'validate an XML value', + proname => 'xmlvalidate', prorettype => 'bool', proargtypes => 'xml text', + prosrc => 'xmlvalidate' }, +{ oid => '2898', descr => 'I/O', + proname => 'xml_recv', provolatile => 's', prorettype => 'xml', + proargtypes => 'internal', prosrc => 'xml_recv' }, +{ oid => '2899', descr => 'I/O', + proname => 'xml_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'xml', prosrc => 'xml_send' }, +{ oid => '2900', descr => 'aggregate transition function', + proname => 'xmlconcat2', proisstrict => 'f', prorettype => 'xml', + proargtypes => 'xml xml', prosrc => 'xmlconcat2' }, +{ oid => '2901', descr => 'concatenate XML values', + proname => 'xmlagg', prokind => 'a', proisstrict => 'f', prorettype => 'xml', + proargtypes => 'xml', prosrc => 'aggregate_dummy' }, +{ oid => '2922', descr => 'serialize an XML value to a character string', + proname => 'text', prorettype => 'text', proargtypes => 'xml', + prosrc => 'xmltotext' }, + +{ oid => '2923', descr => 'map table contents to XML', + proname => 'table_to_xml', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', + proargtypes => 'regclass bool bool text', + proargnames => '{tbl,nulls,tableforest,targetns}', prosrc => 'table_to_xml' }, +{ oid => '2924', descr => 'map query result to XML', + proname => 'query_to_xml', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'xml', proargtypes => 'text bool bool text', + proargnames => '{query,nulls,tableforest,targetns}', + prosrc => 'query_to_xml' }, +{ oid => '2925', descr => 'map rows from cursor to XML', + proname => 'cursor_to_xml', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'xml', + proargtypes => 'refcursor int4 bool bool text', + proargnames => '{cursor,count,nulls,tableforest,targetns}', + prosrc => 'cursor_to_xml' }, +{ oid => '2926', descr => 'map table structure to XML Schema', + proname => 'table_to_xmlschema', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', + proargtypes => 'regclass bool bool text', + proargnames => '{tbl,nulls,tableforest,targetns}', + prosrc => 'table_to_xmlschema' }, +{ oid => '2927', descr => 'map query result structure to XML Schema', + proname => 'query_to_xmlschema', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'xml', proargtypes => 'text bool bool text', + proargnames => '{query,nulls,tableforest,targetns}', + prosrc => 'query_to_xmlschema' }, +{ oid => '2928', descr => 'map cursor structure to XML Schema', + proname => 'cursor_to_xmlschema', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'xml', + proargtypes => 'refcursor bool bool text', + proargnames => '{cursor,nulls,tableforest,targetns}', + prosrc => 'cursor_to_xmlschema' }, +{ oid => '2929', + descr => 'map table contents and structure to XML and XML Schema', + proname => 'table_to_xml_and_xmlschema', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', + proargtypes => 'regclass bool bool text', + proargnames => '{tbl,nulls,tableforest,targetns}', + prosrc => 'table_to_xml_and_xmlschema' }, +{ oid => '2930', + descr => 'map query result and structure to XML and XML Schema', + proname => 'query_to_xml_and_xmlschema', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'xml', proargtypes => 'text bool bool text', + proargnames => '{query,nulls,tableforest,targetns}', + prosrc => 'query_to_xml_and_xmlschema' }, + +{ oid => '2933', descr => 'map schema contents to XML', + proname => 'schema_to_xml', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', proargtypes => 'name bool bool text', + proargnames => '{schema,nulls,tableforest,targetns}', + prosrc => 'schema_to_xml' }, +{ oid => '2934', descr => 'map schema structure to XML Schema', + proname => 'schema_to_xmlschema', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', proargtypes => 'name bool bool text', + proargnames => '{schema,nulls,tableforest,targetns}', + prosrc => 'schema_to_xmlschema' }, +{ oid => '2935', + descr => 'map schema contents and structure to XML and XML Schema', + proname => 'schema_to_xml_and_xmlschema', procost => '100', + provolatile => 's', proparallel => 'r', prorettype => 'xml', + proargtypes => 'name bool bool text', + proargnames => '{schema,nulls,tableforest,targetns}', + prosrc => 'schema_to_xml_and_xmlschema' }, + +{ oid => '2936', descr => 'map database contents to XML', + proname => 'database_to_xml', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', proargtypes => 'bool bool text', + proargnames => '{nulls,tableforest,targetns}', prosrc => 'database_to_xml' }, +{ oid => '2937', descr => 'map database structure to XML Schema', + proname => 'database_to_xmlschema', procost => '100', provolatile => 's', + proparallel => 'r', prorettype => 'xml', proargtypes => 'bool bool text', + proargnames => '{nulls,tableforest,targetns}', + prosrc => 'database_to_xmlschema' }, +{ oid => '2938', + descr => 'map database contents and structure to XML and XML Schema', + proname => 'database_to_xml_and_xmlschema', procost => '100', + provolatile => 's', proparallel => 'r', prorettype => 'xml', + proargtypes => 'bool bool text', + proargnames => '{nulls,tableforest,targetns}', + prosrc => 'database_to_xml_and_xmlschema' }, + +{ oid => '2931', + descr => 'evaluate XPath expression, with namespaces support', + proname => 'xpath', prorettype => '_xml', proargtypes => 'text xml _text', + prosrc => 'xpath' }, +{ oid => '2932', descr => 'evaluate XPath expression', + proname => 'xpath', prolang => 'sql', prorettype => '_xml', + proargtypes => 'text xml', prosrc => 'see system_functions.sql' }, + +{ oid => '2614', descr => 'test XML value against XPath expression', + proname => 'xmlexists', prorettype => 'bool', proargtypes => 'text xml', + prosrc => 'xmlexists' }, + +{ oid => '3049', + descr => 'test XML value against XPath expression, with namespace support', + proname => 'xpath_exists', prorettype => 'bool', + proargtypes => 'text xml _text', prosrc => 'xpath_exists' }, +{ oid => '3050', descr => 'test XML value against XPath expression', + proname => 'xpath_exists', prolang => 'sql', prorettype => 'bool', + proargtypes => 'text xml', prosrc => 'see system_functions.sql' }, +{ oid => '3051', descr => 'determine if a string is well formed XML', + proname => 'xml_is_well_formed', provolatile => 's', prorettype => 'bool', + proargtypes => 'text', prosrc => 'xml_is_well_formed' }, +{ oid => '3052', descr => 'determine if a string is well formed XML document', + proname => 'xml_is_well_formed_document', prorettype => 'bool', + proargtypes => 'text', prosrc => 'xml_is_well_formed_document' }, +{ oid => '3053', descr => 'determine if a string is well formed XML content', + proname => 'xml_is_well_formed_content', prorettype => 'bool', + proargtypes => 'text', prosrc => 'xml_is_well_formed_content' }, + +# json +{ oid => '321', descr => 'I/O', + proname => 'json_in', prorettype => 'json', proargtypes => 'cstring', + prosrc => 'json_in' }, +{ oid => '322', descr => 'I/O', + proname => 'json_out', prorettype => 'cstring', proargtypes => 'json', + prosrc => 'json_out' }, +{ oid => '323', descr => 'I/O', + proname => 'json_recv', prorettype => 'json', proargtypes => 'internal', + prosrc => 'json_recv' }, +{ oid => '324', descr => 'I/O', + proname => 'json_send', prorettype => 'bytea', proargtypes => 'json', + prosrc => 'json_send' }, +{ oid => '3153', descr => 'map array to json', + proname => 'array_to_json', provolatile => 's', prorettype => 'json', + proargtypes => 'anyarray', prosrc => 'array_to_json' }, +{ oid => '3154', descr => 'map array to json with optional pretty printing', + proname => 'array_to_json', provolatile => 's', prorettype => 'json', + proargtypes => 'anyarray bool', prosrc => 'array_to_json_pretty' }, +{ oid => '3155', descr => 'map row to json', + proname => 'row_to_json', provolatile => 's', prorettype => 'json', + proargtypes => 'record', prosrc => 'row_to_json' }, +{ oid => '3156', descr => 'map row to json with optional pretty printing', + proname => 'row_to_json', provolatile => 's', prorettype => 'json', + proargtypes => 'record bool', prosrc => 'row_to_json_pretty' }, +{ oid => '3173', descr => 'json aggregate transition function', + proname => 'json_agg_transfn', proisstrict => 'f', provolatile => 's', + prorettype => 'internal', proargtypes => 'internal anyelement', + prosrc => 'json_agg_transfn' }, +{ oid => '3174', descr => 'json aggregate final function', + proname => 'json_agg_finalfn', proisstrict => 'f', prorettype => 'json', + proargtypes => 'internal', prosrc => 'json_agg_finalfn' }, +{ oid => '3175', descr => 'aggregate input into json', + proname => 'json_agg', prokind => 'a', proisstrict => 'f', provolatile => 's', + prorettype => 'json', proargtypes => 'anyelement', + prosrc => 'aggregate_dummy' }, +{ oid => '3180', descr => 'json object aggregate transition function', + proname => 'json_object_agg_transfn', proisstrict => 'f', provolatile => 's', + prorettype => 'internal', proargtypes => 'internal any any', + prosrc => 'json_object_agg_transfn' }, +{ oid => '3196', descr => 'json object aggregate final function', + proname => 'json_object_agg_finalfn', proisstrict => 'f', + prorettype => 'json', proargtypes => 'internal', + prosrc => 'json_object_agg_finalfn' }, +{ oid => '3197', descr => 'aggregate input into a json object', + proname => 'json_object_agg', prokind => 'a', proisstrict => 'f', + provolatile => 's', prorettype => 'json', proargtypes => 'any any', + prosrc => 'aggregate_dummy' }, +{ oid => '3198', descr => 'build a json array from any inputs', + proname => 'json_build_array', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'json', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'json_build_array' }, +{ oid => '3199', descr => 'build an empty json array', + proname => 'json_build_array', proisstrict => 'f', provolatile => 's', + prorettype => 'json', proargtypes => '', + prosrc => 'json_build_array_noargs' }, +{ oid => '3200', + descr => 'build a json object from pairwise key/value inputs', + proname => 'json_build_object', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'json', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'json_build_object' }, +{ oid => '3201', descr => 'build an empty json object', + proname => 'json_build_object', proisstrict => 'f', provolatile => 's', + prorettype => 'json', proargtypes => '', + prosrc => 'json_build_object_noargs' }, +{ oid => '3202', descr => 'map text array of key value pairs to json object', + proname => 'json_object', prorettype => 'json', proargtypes => '_text', + prosrc => 'json_object' }, +{ oid => '3203', descr => 'map text arrays of keys and values to json object', + proname => 'json_object', prorettype => 'json', proargtypes => '_text _text', + prosrc => 'json_object_two_arg' }, +{ oid => '3176', descr => 'map input to json', + proname => 'to_json', provolatile => 's', prorettype => 'json', + proargtypes => 'anyelement', prosrc => 'to_json' }, +{ oid => '3261', descr => 'remove object fields with null values from json', + proname => 'json_strip_nulls', prorettype => 'json', proargtypes => 'json', + prosrc => 'json_strip_nulls' }, + +{ oid => '3947', + proname => 'json_object_field', prorettype => 'json', + proargtypes => 'json text', proargnames => '{from_json, field_name}', + prosrc => 'json_object_field' }, +{ oid => '3948', + proname => 'json_object_field_text', prorettype => 'text', + proargtypes => 'json text', proargnames => '{from_json, field_name}', + prosrc => 'json_object_field_text' }, +{ oid => '3949', + proname => 'json_array_element', prorettype => 'json', + proargtypes => 'json int4', proargnames => '{from_json, element_index}', + prosrc => 'json_array_element' }, +{ oid => '3950', + proname => 'json_array_element_text', prorettype => 'text', + proargtypes => 'json int4', proargnames => '{from_json, element_index}', + prosrc => 'json_array_element_text' }, +{ oid => '3951', descr => 'get value from json with path elements', + proname => 'json_extract_path', provariadic => 'text', prorettype => 'json', + proargtypes => 'json _text', proallargtypes => '{json,_text}', + proargmodes => '{i,v}', proargnames => '{from_json,path_elems}', + prosrc => 'json_extract_path' }, +{ oid => '3953', descr => 'get value from json as text with path elements', + proname => 'json_extract_path_text', provariadic => 'text', + prorettype => 'text', proargtypes => 'json _text', + proallargtypes => '{json,_text}', proargmodes => '{i,v}', + proargnames => '{from_json,path_elems}', prosrc => 'json_extract_path_text' }, +{ oid => '3955', descr => 'key value pairs of a json object', + proname => 'json_array_elements', prorows => '100', proretset => 't', + prorettype => 'json', proargtypes => 'json', proallargtypes => '{json,json}', + proargmodes => '{i,o}', proargnames => '{from_json,value}', + prosrc => 'json_array_elements' }, +{ oid => '3969', descr => 'elements of json array', + proname => 'json_array_elements_text', prorows => '100', proretset => 't', + prorettype => 'text', proargtypes => 'json', proallargtypes => '{json,text}', + proargmodes => '{i,o}', proargnames => '{from_json,value}', + prosrc => 'json_array_elements_text' }, +{ oid => '3956', descr => 'length of json array', + proname => 'json_array_length', prorettype => 'int4', proargtypes => 'json', + prosrc => 'json_array_length' }, +{ oid => '3957', descr => 'get json object keys', + proname => 'json_object_keys', prorows => '100', proretset => 't', + prorettype => 'text', proargtypes => 'json', prosrc => 'json_object_keys' }, +{ oid => '3958', descr => 'key value pairs of a json object', + proname => 'json_each', prorows => '100', proretset => 't', + prorettype => 'record', proargtypes => 'json', + proallargtypes => '{json,text,json}', proargmodes => '{i,o,o}', + proargnames => '{from_json,key,value}', prosrc => 'json_each' }, +{ oid => '3959', descr => 'key value pairs of a json object', + proname => 'json_each_text', prorows => '100', proretset => 't', + prorettype => 'record', proargtypes => 'json', + proallargtypes => '{json,text,text}', proargmodes => '{i,o,o}', + proargnames => '{from_json,key,value}', prosrc => 'json_each_text' }, +{ oid => '3960', descr => 'get record fields from a json object', + proname => 'json_populate_record', proisstrict => 'f', provolatile => 's', + prorettype => 'anyelement', proargtypes => 'anyelement json bool', + prosrc => 'json_populate_record' }, +{ oid => '3961', + descr => 'get set of records with fields from a json array of objects', + proname => 'json_populate_recordset', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement json bool', prosrc => 'json_populate_recordset' }, +{ oid => '3204', descr => 'get record fields from a json object', + proname => 'json_to_record', provolatile => 's', prorettype => 'record', + proargtypes => 'json', prosrc => 'json_to_record' }, +{ oid => '3205', + descr => 'get set of records with fields from a json array of objects', + proname => 'json_to_recordset', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => 'json', prosrc => 'json_to_recordset' }, +{ oid => '3968', descr => 'get the type of a json value', + proname => 'json_typeof', prorettype => 'text', proargtypes => 'json', + prosrc => 'json_typeof' }, + +# uuid +{ oid => '2952', descr => 'I/O', + proname => 'uuid_in', prorettype => 'uuid', proargtypes => 'cstring', + prosrc => 'uuid_in' }, +{ oid => '2953', descr => 'I/O', + proname => 'uuid_out', prorettype => 'cstring', proargtypes => 'uuid', + prosrc => 'uuid_out' }, +{ oid => '2954', + proname => 'uuid_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_lt' }, +{ oid => '2955', + proname => 'uuid_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_le' }, +{ oid => '2956', + proname => 'uuid_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_eq' }, +{ oid => '2957', + proname => 'uuid_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_ge' }, +{ oid => '2958', + proname => 'uuid_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_gt' }, +{ oid => '2959', + proname => 'uuid_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'uuid uuid', prosrc => 'uuid_ne' }, +{ oid => '2960', descr => 'less-equal-greater', + proname => 'uuid_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'uuid uuid', prosrc => 'uuid_cmp' }, +{ oid => '3300', descr => 'sort support', + proname => 'uuid_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'uuid_sortsupport' }, +{ oid => '2961', descr => 'I/O', + proname => 'uuid_recv', prorettype => 'uuid', proargtypes => 'internal', + prosrc => 'uuid_recv' }, +{ oid => '2962', descr => 'I/O', + proname => 'uuid_send', prorettype => 'bytea', proargtypes => 'uuid', + prosrc => 'uuid_send' }, +{ oid => '2963', descr => 'hash', + proname => 'uuid_hash', prorettype => 'int4', proargtypes => 'uuid', + prosrc => 'uuid_hash' }, +{ oid => '3412', descr => 'hash', + proname => 'uuid_hash_extended', prorettype => 'int8', + proargtypes => 'uuid int8', prosrc => 'uuid_hash_extended' }, +{ oid => '3432', descr => 'generate random UUID', + proname => 'gen_random_uuid', proleakproof => 't', provolatile => 'v', + prorettype => 'uuid', proargtypes => '', prosrc => 'gen_random_uuid' }, + +# pg_lsn +{ oid => '3229', descr => 'I/O', + proname => 'pg_lsn_in', prorettype => 'pg_lsn', proargtypes => 'cstring', + prosrc => 'pg_lsn_in' }, +{ oid => '3230', descr => 'I/O', + proname => 'pg_lsn_out', prorettype => 'cstring', proargtypes => 'pg_lsn', + prosrc => 'pg_lsn_out' }, +{ oid => '3231', + proname => 'pg_lsn_lt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_lt' }, +{ oid => '3232', + proname => 'pg_lsn_le', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_le' }, +{ oid => '3233', + proname => 'pg_lsn_eq', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_eq' }, +{ oid => '3234', + proname => 'pg_lsn_ge', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_ge' }, +{ oid => '3235', + proname => 'pg_lsn_gt', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_gt' }, +{ oid => '3236', + proname => 'pg_lsn_ne', proleakproof => 't', prorettype => 'bool', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_ne' }, +{ oid => '3237', + proname => 'pg_lsn_mi', prorettype => 'numeric', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_mi' }, +{ oid => '3238', descr => 'I/O', + proname => 'pg_lsn_recv', prorettype => 'pg_lsn', proargtypes => 'internal', + prosrc => 'pg_lsn_recv' }, +{ oid => '3239', descr => 'I/O', + proname => 'pg_lsn_send', prorettype => 'bytea', proargtypes => 'pg_lsn', + prosrc => 'pg_lsn_send' }, +{ oid => '3251', descr => 'less-equal-greater', + proname => 'pg_lsn_cmp', proleakproof => 't', prorettype => 'int4', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_cmp' }, +{ oid => '3252', descr => 'hash', + proname => 'pg_lsn_hash', prorettype => 'int4', proargtypes => 'pg_lsn', + prosrc => 'pg_lsn_hash' }, +{ oid => '3413', descr => 'hash', + proname => 'pg_lsn_hash_extended', prorettype => 'int8', + proargtypes => 'pg_lsn int8', prosrc => 'pg_lsn_hash_extended' }, +{ oid => '4187', descr => 'larger of two', + proname => 'pg_lsn_larger', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_larger' }, +{ oid => '4188', descr => 'smaller of two', + proname => 'pg_lsn_smaller', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn pg_lsn', prosrc => 'pg_lsn_smaller' }, +{ oid => '5022', + proname => 'pg_lsn_pli', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn numeric', prosrc => 'pg_lsn_pli' }, +{ oid => '5023', + proname => 'numeric_pl_pg_lsn', prolang => 'sql', prorettype => 'pg_lsn', + proargtypes => 'numeric pg_lsn', prosrc => 'see system_functions.sql' }, +{ oid => '5024', + proname => 'pg_lsn_mii', prorettype => 'pg_lsn', + proargtypes => 'pg_lsn numeric', prosrc => 'pg_lsn_mii' }, + +# enum related procs +{ oid => '3504', descr => 'I/O', + proname => 'anyenum_in', prorettype => 'anyenum', proargtypes => 'cstring', + prosrc => 'anyenum_in' }, +{ oid => '3505', descr => 'I/O', + proname => 'anyenum_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyenum', prosrc => 'anyenum_out' }, +{ oid => '3506', descr => 'I/O', + proname => 'enum_in', provolatile => 's', prorettype => 'anyenum', + proargtypes => 'cstring oid', prosrc => 'enum_in' }, +{ oid => '3507', descr => 'I/O', + proname => 'enum_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyenum', prosrc => 'enum_out' }, +{ oid => '3508', + proname => 'enum_eq', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_eq' }, +{ oid => '3509', + proname => 'enum_ne', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_ne' }, +{ oid => '3510', + proname => 'enum_lt', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_lt' }, +{ oid => '3511', + proname => 'enum_gt', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_gt' }, +{ oid => '3512', + proname => 'enum_le', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_le' }, +{ oid => '3513', + proname => 'enum_ge', prorettype => 'bool', proargtypes => 'anyenum anyenum', + prosrc => 'enum_ge' }, +{ oid => '3514', descr => 'less-equal-greater', + proname => 'enum_cmp', prorettype => 'int4', proargtypes => 'anyenum anyenum', + prosrc => 'enum_cmp' }, +{ oid => '3515', descr => 'hash', + proname => 'hashenum', prorettype => 'int4', proargtypes => 'anyenum', + prosrc => 'hashenum' }, +{ oid => '3414', descr => 'hash', + proname => 'hashenumextended', prorettype => 'int8', + proargtypes => 'anyenum int8', prosrc => 'hashenumextended' }, +{ oid => '3524', descr => 'smaller of two', + proname => 'enum_smaller', prorettype => 'anyenum', + proargtypes => 'anyenum anyenum', prosrc => 'enum_smaller' }, +{ oid => '3525', descr => 'larger of two', + proname => 'enum_larger', prorettype => 'anyenum', + proargtypes => 'anyenum anyenum', prosrc => 'enum_larger' }, +{ oid => '3526', descr => 'maximum value of all enum input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum', + proargtypes => 'anyenum', prosrc => 'aggregate_dummy' }, +{ oid => '3527', descr => 'minimum value of all enum input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum', + proargtypes => 'anyenum', prosrc => 'aggregate_dummy' }, +{ oid => '3528', descr => 'first value of the input enum type', + proname => 'enum_first', proisstrict => 'f', provolatile => 's', + prorettype => 'anyenum', proargtypes => 'anyenum', prosrc => 'enum_first' }, +{ oid => '3529', descr => 'last value of the input enum type', + proname => 'enum_last', proisstrict => 'f', provolatile => 's', + prorettype => 'anyenum', proargtypes => 'anyenum', prosrc => 'enum_last' }, +{ oid => '3530', + descr => 'range between the two given enum values, as an ordered array', + proname => 'enum_range', proisstrict => 'f', provolatile => 's', + prorettype => 'anyarray', proargtypes => 'anyenum anyenum', + prosrc => 'enum_range_bounds' }, +{ oid => '3531', descr => 'range of the given enum type, as an ordered array', + proname => 'enum_range', proisstrict => 'f', provolatile => 's', + prorettype => 'anyarray', proargtypes => 'anyenum', + prosrc => 'enum_range_all' }, +{ oid => '3532', descr => 'I/O', + proname => 'enum_recv', provolatile => 's', prorettype => 'anyenum', + proargtypes => 'internal oid', prosrc => 'enum_recv' }, +{ oid => '3533', descr => 'I/O', + proname => 'enum_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'anyenum', prosrc => 'enum_send' }, + +# text search stuff +{ oid => '3610', descr => 'I/O', + proname => 'tsvectorin', prorettype => 'tsvector', proargtypes => 'cstring', + prosrc => 'tsvectorin' }, +{ oid => '3639', descr => 'I/O', + proname => 'tsvectorrecv', prorettype => 'tsvector', + proargtypes => 'internal', prosrc => 'tsvectorrecv' }, +{ oid => '3611', descr => 'I/O', + proname => 'tsvectorout', prorettype => 'cstring', proargtypes => 'tsvector', + prosrc => 'tsvectorout' }, +{ oid => '3638', descr => 'I/O', + proname => 'tsvectorsend', prorettype => 'bytea', proargtypes => 'tsvector', + prosrc => 'tsvectorsend' }, +{ oid => '3612', descr => 'I/O', + proname => 'tsqueryin', prorettype => 'tsquery', proargtypes => 'cstring', + prosrc => 'tsqueryin' }, +{ oid => '3641', descr => 'I/O', + proname => 'tsqueryrecv', prorettype => 'tsquery', proargtypes => 'internal', + prosrc => 'tsqueryrecv' }, +{ oid => '3613', descr => 'I/O', + proname => 'tsqueryout', prorettype => 'cstring', proargtypes => 'tsquery', + prosrc => 'tsqueryout' }, +{ oid => '3640', descr => 'I/O', + proname => 'tsquerysend', prorettype => 'bytea', proargtypes => 'tsquery', + prosrc => 'tsquerysend' }, +{ oid => '3646', descr => 'I/O', + proname => 'gtsvectorin', prorettype => 'gtsvector', proargtypes => 'cstring', + prosrc => 'gtsvectorin' }, +{ oid => '3647', descr => 'I/O', + proname => 'gtsvectorout', prorettype => 'cstring', + proargtypes => 'gtsvector', prosrc => 'gtsvectorout' }, + +{ oid => '3616', + proname => 'tsvector_lt', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_lt' }, +{ oid => '3617', + proname => 'tsvector_le', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_le' }, +{ oid => '3618', + proname => 'tsvector_eq', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_eq' }, +{ oid => '3619', + proname => 'tsvector_ne', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_ne' }, +{ oid => '3620', + proname => 'tsvector_ge', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_ge' }, +{ oid => '3621', + proname => 'tsvector_gt', prorettype => 'bool', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_gt' }, +{ oid => '3622', descr => 'less-equal-greater', + proname => 'tsvector_cmp', prorettype => 'int4', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_cmp' }, + +{ oid => '3711', descr => 'number of lexemes', + proname => 'length', prorettype => 'int4', proargtypes => 'tsvector', + prosrc => 'tsvector_length' }, +{ oid => '3623', descr => 'strip position information', + proname => 'strip', prorettype => 'tsvector', proargtypes => 'tsvector', + prosrc => 'tsvector_strip' }, +{ oid => '3624', descr => 'set given weight for whole tsvector', + proname => 'setweight', prorettype => 'tsvector', + proargtypes => 'tsvector char', prosrc => 'tsvector_setweight' }, +{ oid => '3320', descr => 'set given weight for given lexemes', + proname => 'setweight', prorettype => 'tsvector', + proargtypes => 'tsvector char _text', + prosrc => 'tsvector_setweight_by_filter' }, +{ oid => '3625', + proname => 'tsvector_concat', prorettype => 'tsvector', + proargtypes => 'tsvector tsvector', prosrc => 'tsvector_concat' }, +{ oid => '3321', descr => 'delete lexeme', + proname => 'ts_delete', prorettype => 'tsvector', + proargtypes => 'tsvector text', prosrc => 'tsvector_delete_str' }, +{ oid => '3323', descr => 'delete given lexemes', + proname => 'ts_delete', prorettype => 'tsvector', + proargtypes => 'tsvector _text', prosrc => 'tsvector_delete_arr' }, +{ oid => '3322', descr => 'expand tsvector to set of rows', + proname => 'unnest', prorows => '10', proretset => 't', + prorettype => 'record', proargtypes => 'tsvector', + proallargtypes => '{tsvector,text,_int2,_text}', proargmodes => '{i,o,o,o}', + proargnames => '{tsvector,lexeme,positions,weights}', + prosrc => 'tsvector_unnest' }, +{ oid => '3326', descr => 'convert tsvector to array of lexemes', + proname => 'tsvector_to_array', prorettype => '_text', + proargtypes => 'tsvector', prosrc => 'tsvector_to_array' }, +{ oid => '3327', descr => 'build tsvector from array of lexemes', + proname => 'array_to_tsvector', prorettype => 'tsvector', + proargtypes => '_text', prosrc => 'array_to_tsvector' }, +{ oid => '3319', + descr => 'delete lexemes that do not have one of the given weights', + proname => 'ts_filter', prorettype => 'tsvector', + proargtypes => 'tsvector _char', prosrc => 'tsvector_filter' }, + +{ oid => '3634', + proname => 'ts_match_vq', prorettype => 'bool', + proargtypes => 'tsvector tsquery', prosrc => 'ts_match_vq' }, +{ oid => '3635', + proname => 'ts_match_qv', prorettype => 'bool', + proargtypes => 'tsquery tsvector', prosrc => 'ts_match_qv' }, +{ oid => '3760', + proname => 'ts_match_tt', procost => '100', provolatile => 's', + prorettype => 'bool', proargtypes => 'text text', prosrc => 'ts_match_tt' }, +{ oid => '3761', + proname => 'ts_match_tq', procost => '100', provolatile => 's', + prorettype => 'bool', proargtypes => 'text tsquery', + prosrc => 'ts_match_tq' }, + +{ oid => '3648', descr => 'GiST tsvector support', + proname => 'gtsvector_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gtsvector_compress' }, +{ oid => '3649', descr => 'GiST tsvector support', + proname => 'gtsvector_decompress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gtsvector_decompress' }, +{ oid => '3650', descr => 'GiST tsvector support', + proname => 'gtsvector_picksplit', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'gtsvector_picksplit' }, +{ oid => '3651', descr => 'GiST tsvector support', + proname => 'gtsvector_union', prorettype => 'gtsvector', + proargtypes => 'internal internal', prosrc => 'gtsvector_union' }, +{ oid => '3652', descr => 'GiST tsvector support', + proname => 'gtsvector_same', prorettype => 'internal', + proargtypes => 'gtsvector gtsvector internal', prosrc => 'gtsvector_same' }, +{ oid => '3653', descr => 'GiST tsvector support', + proname => 'gtsvector_penalty', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'gtsvector_penalty' }, +{ oid => '3654', descr => 'GiST tsvector support', + proname => 'gtsvector_consistent', prorettype => 'bool', + proargtypes => 'internal tsvector int2 oid internal', + prosrc => 'gtsvector_consistent' }, +{ oid => '3790', descr => 'GiST tsvector support (obsolete)', + proname => 'gtsvector_consistent', prorettype => 'bool', + proargtypes => 'internal gtsvector int4 oid internal', + prosrc => 'gtsvector_consistent_oldsig' }, +{ oid => '3434', descr => 'GiST tsvector support', + proname => 'gtsvector_options', proisstrict => 'f', prorettype => 'void', + proargtypes => 'internal', prosrc => 'gtsvector_options' }, + +{ oid => '3656', descr => 'GIN tsvector support', + proname => 'gin_extract_tsvector', prorettype => 'internal', + proargtypes => 'tsvector internal internal', + prosrc => 'gin_extract_tsvector' }, +{ oid => '3657', descr => 'GIN tsvector support', + proname => 'gin_extract_tsquery', prorettype => 'internal', + proargtypes => 'tsvector internal int2 internal internal internal internal', + prosrc => 'gin_extract_tsquery' }, +{ oid => '3658', descr => 'GIN tsvector support', + proname => 'gin_tsquery_consistent', prorettype => 'bool', + proargtypes => 'internal int2 tsvector int4 internal internal internal internal', + prosrc => 'gin_tsquery_consistent' }, +{ oid => '3921', descr => 'GIN tsvector support', + proname => 'gin_tsquery_triconsistent', prorettype => 'char', + proargtypes => 'internal int2 tsvector int4 internal internal internal', + prosrc => 'gin_tsquery_triconsistent' }, +{ oid => '3724', descr => 'GIN tsvector support', + proname => 'gin_cmp_tslexeme', prorettype => 'int4', + proargtypes => 'text text', prosrc => 'gin_cmp_tslexeme' }, +{ oid => '2700', descr => 'GIN tsvector support', + proname => 'gin_cmp_prefix', prorettype => 'int4', + proargtypes => 'text text int2 internal', prosrc => 'gin_cmp_prefix' }, +{ oid => '3077', descr => 'GIN tsvector support (obsolete)', + proname => 'gin_extract_tsvector', prorettype => 'internal', + proargtypes => 'tsvector internal', prosrc => 'gin_extract_tsvector_2args' }, +{ oid => '3087', descr => 'GIN tsvector support (obsolete)', + proname => 'gin_extract_tsquery', prorettype => 'internal', + proargtypes => 'tsquery internal int2 internal internal', + prosrc => 'gin_extract_tsquery_5args' }, +{ oid => '3088', descr => 'GIN tsvector support (obsolete)', + proname => 'gin_tsquery_consistent', prorettype => 'bool', + proargtypes => 'internal int2 tsquery int4 internal internal', + prosrc => 'gin_tsquery_consistent_6args' }, +{ oid => '3791', descr => 'GIN tsvector support (obsolete)', + proname => 'gin_extract_tsquery', prorettype => 'internal', + proargtypes => 'tsquery internal int2 internal internal internal internal', + prosrc => 'gin_extract_tsquery_oldsig' }, +{ oid => '3792', descr => 'GIN tsvector support (obsolete)', + proname => 'gin_tsquery_consistent', prorettype => 'bool', + proargtypes => 'internal int2 tsquery int4 internal internal internal internal', + prosrc => 'gin_tsquery_consistent_oldsig' }, + +{ oid => '3789', descr => 'clean up GIN pending list', + proname => 'gin_clean_pending_list', provolatile => 'v', proparallel => 'u', + prorettype => 'int8', proargtypes => 'regclass', + prosrc => 'gin_clean_pending_list' }, + +{ oid => '3662', + proname => 'tsquery_lt', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_lt' }, +{ oid => '3663', + proname => 'tsquery_le', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_le' }, +{ oid => '3664', + proname => 'tsquery_eq', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_eq' }, +{ oid => '3665', + proname => 'tsquery_ne', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_ne' }, +{ oid => '3666', + proname => 'tsquery_ge', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_ge' }, +{ oid => '3667', + proname => 'tsquery_gt', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_gt' }, +{ oid => '3668', descr => 'less-equal-greater', + proname => 'tsquery_cmp', prorettype => 'int4', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_cmp' }, + +{ oid => '3669', + proname => 'tsquery_and', prorettype => 'tsquery', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_and' }, +{ oid => '3670', + proname => 'tsquery_or', prorettype => 'tsquery', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_or' }, +{ oid => '5003', + proname => 'tsquery_phrase', prorettype => 'tsquery', + proargtypes => 'tsquery tsquery', prosrc => 'tsquery_phrase' }, +{ oid => '5004', descr => 'phrase-concatenate with distance', + proname => 'tsquery_phrase', prorettype => 'tsquery', + proargtypes => 'tsquery tsquery int4', prosrc => 'tsquery_phrase_distance' }, +{ oid => '3671', + proname => 'tsquery_not', prorettype => 'tsquery', proargtypes => 'tsquery', + prosrc => 'tsquery_not' }, + +{ oid => '3691', + proname => 'tsq_mcontains', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsq_mcontains' }, +{ oid => '3692', + proname => 'tsq_mcontained', prorettype => 'bool', + proargtypes => 'tsquery tsquery', prosrc => 'tsq_mcontained' }, + +{ oid => '3672', descr => 'number of nodes', + proname => 'numnode', prorettype => 'int4', proargtypes => 'tsquery', + prosrc => 'tsquery_numnode' }, +{ oid => '3673', descr => 'show real useful query for GiST index', + proname => 'querytree', prorettype => 'text', proargtypes => 'tsquery', + prosrc => 'tsquerytree' }, + +{ oid => '3684', descr => 'rewrite tsquery', + proname => 'ts_rewrite', prorettype => 'tsquery', + proargtypes => 'tsquery tsquery tsquery', prosrc => 'tsquery_rewrite' }, +{ oid => '3685', descr => 'rewrite tsquery', + proname => 'ts_rewrite', procost => '100', provolatile => 'v', + proparallel => 'u', prorettype => 'tsquery', proargtypes => 'tsquery text', + prosrc => 'tsquery_rewrite_query' }, + +{ oid => '3695', descr => 'GiST tsquery support', + proname => 'gtsquery_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'gtsquery_compress' }, +{ oid => '3697', descr => 'GiST tsquery support', + proname => 'gtsquery_picksplit', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'gtsquery_picksplit' }, +{ oid => '3698', descr => 'GiST tsquery support', + proname => 'gtsquery_union', prorettype => 'int8', + proargtypes => 'internal internal', prosrc => 'gtsquery_union' }, +{ oid => '3699', descr => 'GiST tsquery support', + proname => 'gtsquery_same', prorettype => 'internal', + proargtypes => 'int8 int8 internal', prosrc => 'gtsquery_same' }, +{ oid => '3700', descr => 'GiST tsquery support', + proname => 'gtsquery_penalty', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'gtsquery_penalty' }, +{ oid => '3701', descr => 'GiST tsquery support', + proname => 'gtsquery_consistent', prorettype => 'bool', + proargtypes => 'internal tsquery int2 oid internal', + prosrc => 'gtsquery_consistent' }, +{ oid => '3793', descr => 'GiST tsquery support (obsolete)', + proname => 'gtsquery_consistent', prorettype => 'bool', + proargtypes => 'internal internal int4 oid internal', + prosrc => 'gtsquery_consistent_oldsig' }, + +{ oid => '3686', descr => 'restriction selectivity of tsvector @@ tsquery', + proname => 'tsmatchsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'tsmatchsel' }, +{ oid => '3687', descr => 'join selectivity of tsvector @@ tsquery', + proname => 'tsmatchjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'tsmatchjoinsel' }, +{ oid => '3688', descr => 'tsvector typanalyze', + proname => 'ts_typanalyze', provolatile => 's', prorettype => 'bool', + proargtypes => 'internal', prosrc => 'ts_typanalyze' }, + +{ oid => '3689', descr => 'statistics of tsvector column', + proname => 'ts_stat', procost => '10', prorows => '10000', proretset => 't', + provolatile => 'v', proparallel => 'u', prorettype => 'record', + proargtypes => 'text', proallargtypes => '{text,text,int4,int4}', + proargmodes => '{i,o,o,o}', proargnames => '{query,word,ndoc,nentry}', + prosrc => 'ts_stat1' }, +{ oid => '3690', descr => 'statistics of tsvector column', + proname => 'ts_stat', procost => '10', prorows => '10000', proretset => 't', + provolatile => 'v', proparallel => 'u', prorettype => 'record', + proargtypes => 'text text', proallargtypes => '{text,text,text,int4,int4}', + proargmodes => '{i,i,o,o,o}', + proargnames => '{query,weights,word,ndoc,nentry}', prosrc => 'ts_stat2' }, + +{ oid => '3703', descr => 'relevance', + proname => 'ts_rank', prorettype => 'float4', + proargtypes => '_float4 tsvector tsquery int4', prosrc => 'ts_rank_wttf' }, +{ oid => '3704', descr => 'relevance', + proname => 'ts_rank', prorettype => 'float4', + proargtypes => '_float4 tsvector tsquery', prosrc => 'ts_rank_wtt' }, +{ oid => '3705', descr => 'relevance', + proname => 'ts_rank', prorettype => 'float4', + proargtypes => 'tsvector tsquery int4', prosrc => 'ts_rank_ttf' }, +{ oid => '3706', descr => 'relevance', + proname => 'ts_rank', prorettype => 'float4', + proargtypes => 'tsvector tsquery', prosrc => 'ts_rank_tt' }, +{ oid => '3707', descr => 'relevance', + proname => 'ts_rank_cd', prorettype => 'float4', + proargtypes => '_float4 tsvector tsquery int4', prosrc => 'ts_rankcd_wttf' }, +{ oid => '3708', descr => 'relevance', + proname => 'ts_rank_cd', prorettype => 'float4', + proargtypes => '_float4 tsvector tsquery', prosrc => 'ts_rankcd_wtt' }, +{ oid => '3709', descr => 'relevance', + proname => 'ts_rank_cd', prorettype => 'float4', + proargtypes => 'tsvector tsquery int4', prosrc => 'ts_rankcd_ttf' }, +{ oid => '3710', descr => 'relevance', + proname => 'ts_rank_cd', prorettype => 'float4', + proargtypes => 'tsvector tsquery', prosrc => 'ts_rankcd_tt' }, + +{ oid => '3713', descr => 'get parser\'s token types', + proname => 'ts_token_type', prorows => '16', proretset => 't', + prorettype => 'record', proargtypes => 'oid', + proallargtypes => '{oid,int4,text,text}', proargmodes => '{i,o,o,o}', + proargnames => '{parser_oid,tokid,alias,description}', + prosrc => 'ts_token_type_byid' }, +{ oid => '3714', descr => 'get parser\'s token types', + proname => 'ts_token_type', prorows => '16', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'text', + proallargtypes => '{text,int4,text,text}', proargmodes => '{i,o,o,o}', + proargnames => '{parser_name,tokid,alias,description}', + prosrc => 'ts_token_type_byname' }, +{ oid => '3715', descr => 'parse text to tokens', + proname => 'ts_parse', prorows => '1000', proretset => 't', + prorettype => 'record', proargtypes => 'oid text', + proallargtypes => '{oid,text,int4,text}', proargmodes => '{i,i,o,o}', + proargnames => '{parser_oid,txt,tokid,token}', prosrc => 'ts_parse_byid' }, +{ oid => '3716', descr => 'parse text to tokens', + proname => 'ts_parse', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'text text', + proallargtypes => '{text,text,int4,text}', proargmodes => '{i,i,o,o}', + proargnames => '{parser_name,txt,tokid,token}', prosrc => 'ts_parse_byname' }, + +{ oid => '3717', descr => '(internal)', + proname => 'prsd_start', prorettype => 'internal', + proargtypes => 'internal int4', prosrc => 'prsd_start' }, +{ oid => '3718', descr => '(internal)', + proname => 'prsd_nexttoken', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'prsd_nexttoken' }, +{ oid => '3719', descr => '(internal)', + proname => 'prsd_end', prorettype => 'void', proargtypes => 'internal', + prosrc => 'prsd_end' }, +{ oid => '3720', descr => '(internal)', + proname => 'prsd_headline', prorettype => 'internal', + proargtypes => 'internal internal tsquery', prosrc => 'prsd_headline' }, +{ oid => '3721', descr => '(internal)', + proname => 'prsd_lextype', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'prsd_lextype' }, + +{ oid => '3723', descr => 'normalize one word by dictionary', + proname => 'ts_lexize', prorettype => '_text', + proargtypes => 'regdictionary text', prosrc => 'ts_lexize' }, + +{ oid => '6183', descr => 'debug function for text search configuration', + proname => 'ts_debug', prolang => 'sql', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'regconfig text', + proallargtypes => '{regconfig,text,text,text,text,_regdictionary,regdictionary,_text}', + proargmodes => '{i,i,o,o,o,o,o,o}', + proargnames => '{config,document,alias,description,token,dictionaries,dictionary,lexemes}', + prosrc => 'see system_functions.sql' }, + +{ oid => '6184', + descr => 'debug function for current text search configuration', + proname => 'ts_debug', prolang => 'sql', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'text', + proallargtypes => '{text,text,text,text,_regdictionary,regdictionary,_text}', + proargmodes => '{i,o,o,o,o,o,o}', + proargnames => '{document,alias,description,token,dictionaries,dictionary,lexemes}', + prosrc => 'see system_functions.sql' }, + +{ oid => '3725', descr => '(internal)', + proname => 'dsimple_init', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'dsimple_init' }, +{ oid => '3726', descr => '(internal)', + proname => 'dsimple_lexize', prorettype => 'internal', + proargtypes => 'internal internal internal internal', + prosrc => 'dsimple_lexize' }, + +{ oid => '3728', descr => '(internal)', + proname => 'dsynonym_init', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'dsynonym_init' }, +{ oid => '3729', descr => '(internal)', + proname => 'dsynonym_lexize', prorettype => 'internal', + proargtypes => 'internal internal internal internal', + prosrc => 'dsynonym_lexize' }, + +{ oid => '3731', descr => '(internal)', + proname => 'dispell_init', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'dispell_init' }, +{ oid => '3732', descr => '(internal)', + proname => 'dispell_lexize', prorettype => 'internal', + proargtypes => 'internal internal internal internal', + prosrc => 'dispell_lexize' }, + +{ oid => '3740', descr => '(internal)', + proname => 'thesaurus_init', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'thesaurus_init' }, +{ oid => '3741', descr => '(internal)', + proname => 'thesaurus_lexize', prorettype => 'internal', + proargtypes => 'internal internal internal internal', + prosrc => 'thesaurus_lexize' }, + +{ oid => '3743', descr => 'generate headline', + proname => 'ts_headline', procost => '100', prorettype => 'text', + proargtypes => 'regconfig text tsquery text', + prosrc => 'ts_headline_byid_opt' }, +{ oid => '3744', descr => 'generate headline', + proname => 'ts_headline', procost => '100', prorettype => 'text', + proargtypes => 'regconfig text tsquery', prosrc => 'ts_headline_byid' }, +{ oid => '3754', descr => 'generate headline', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'text', proargtypes => 'text tsquery text', + prosrc => 'ts_headline_opt' }, +{ oid => '3755', descr => 'generate headline', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'text', proargtypes => 'text tsquery', + prosrc => 'ts_headline' }, + +{ oid => '4201', descr => 'generate headline from jsonb', + proname => 'ts_headline', procost => '100', prorettype => 'jsonb', + proargtypes => 'regconfig jsonb tsquery text', + prosrc => 'ts_headline_jsonb_byid_opt' }, +{ oid => '4202', descr => 'generate headline from jsonb', + proname => 'ts_headline', procost => '100', prorettype => 'jsonb', + proargtypes => 'regconfig jsonb tsquery', + prosrc => 'ts_headline_jsonb_byid' }, +{ oid => '4203', descr => 'generate headline from jsonb', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'jsonb tsquery text', + prosrc => 'ts_headline_jsonb_opt' }, +{ oid => '4204', descr => 'generate headline from jsonb', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'jsonb tsquery', + prosrc => 'ts_headline_jsonb' }, + +{ oid => '4205', descr => 'generate headline from json', + proname => 'ts_headline', procost => '100', prorettype => 'json', + proargtypes => 'regconfig json tsquery text', + prosrc => 'ts_headline_json_byid_opt' }, +{ oid => '4206', descr => 'generate headline from json', + proname => 'ts_headline', procost => '100', prorettype => 'json', + proargtypes => 'regconfig json tsquery', prosrc => 'ts_headline_json_byid' }, +{ oid => '4207', descr => 'generate headline from json', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'json', proargtypes => 'json tsquery text', + prosrc => 'ts_headline_json_opt' }, +{ oid => '4208', descr => 'generate headline from json', + proname => 'ts_headline', procost => '100', provolatile => 's', + prorettype => 'json', proargtypes => 'json tsquery', + prosrc => 'ts_headline_json' }, + +{ oid => '3745', descr => 'transform to tsvector', + proname => 'to_tsvector', procost => '100', prorettype => 'tsvector', + proargtypes => 'regconfig text', prosrc => 'to_tsvector_byid' }, +{ oid => '3746', descr => 'make tsquery', + proname => 'to_tsquery', procost => '100', prorettype => 'tsquery', + proargtypes => 'regconfig text', prosrc => 'to_tsquery_byid' }, +{ oid => '3747', descr => 'transform to tsquery', + proname => 'plainto_tsquery', procost => '100', prorettype => 'tsquery', + proargtypes => 'regconfig text', prosrc => 'plainto_tsquery_byid' }, +{ oid => '5006', descr => 'transform to tsquery', + proname => 'phraseto_tsquery', procost => '100', prorettype => 'tsquery', + proargtypes => 'regconfig text', prosrc => 'phraseto_tsquery_byid' }, +{ oid => '5007', descr => 'transform to tsquery', + proname => 'websearch_to_tsquery', procost => '100', prorettype => 'tsquery', + proargtypes => 'regconfig text', prosrc => 'websearch_to_tsquery_byid' }, +{ oid => '3749', descr => 'transform to tsvector', + proname => 'to_tsvector', procost => '100', provolatile => 's', + prorettype => 'tsvector', proargtypes => 'text', prosrc => 'to_tsvector' }, +{ oid => '3750', descr => 'make tsquery', + proname => 'to_tsquery', procost => '100', provolatile => 's', + prorettype => 'tsquery', proargtypes => 'text', prosrc => 'to_tsquery' }, +{ oid => '3751', descr => 'transform to tsquery', + proname => 'plainto_tsquery', procost => '100', provolatile => 's', + prorettype => 'tsquery', proargtypes => 'text', prosrc => 'plainto_tsquery' }, +{ oid => '5001', descr => 'transform to tsquery', + proname => 'phraseto_tsquery', procost => '100', provolatile => 's', + prorettype => 'tsquery', proargtypes => 'text', + prosrc => 'phraseto_tsquery' }, +{ oid => '5009', descr => 'transform to tsquery', + proname => 'websearch_to_tsquery', procost => '100', provolatile => 's', + prorettype => 'tsquery', proargtypes => 'text', + prosrc => 'websearch_to_tsquery' }, +{ oid => '4209', descr => 'transform string values from jsonb to tsvector', + proname => 'to_tsvector', procost => '100', provolatile => 's', + prorettype => 'tsvector', proargtypes => 'jsonb', + prosrc => 'jsonb_string_to_tsvector' }, +{ oid => '4213', descr => 'transform specified values from jsonb to tsvector', + proname => 'jsonb_to_tsvector', procost => '100', provolatile => 's', + prorettype => 'tsvector', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_to_tsvector' }, +{ oid => '4210', descr => 'transform string values from json to tsvector', + proname => 'to_tsvector', procost => '100', provolatile => 's', + prorettype => 'tsvector', proargtypes => 'json', + prosrc => 'json_string_to_tsvector' }, +{ oid => '4215', descr => 'transform specified values from json to tsvector', + proname => 'json_to_tsvector', procost => '100', provolatile => 's', + prorettype => 'tsvector', proargtypes => 'json jsonb', + prosrc => 'json_to_tsvector' }, +{ oid => '4211', descr => 'transform string values from jsonb to tsvector', + proname => 'to_tsvector', procost => '100', prorettype => 'tsvector', + proargtypes => 'regconfig jsonb', prosrc => 'jsonb_string_to_tsvector_byid' }, +{ oid => '4214', descr => 'transform specified values from jsonb to tsvector', + proname => 'jsonb_to_tsvector', procost => '100', prorettype => 'tsvector', + proargtypes => 'regconfig jsonb jsonb', prosrc => 'jsonb_to_tsvector_byid' }, +{ oid => '4212', descr => 'transform string values from json to tsvector', + proname => 'to_tsvector', procost => '100', prorettype => 'tsvector', + proargtypes => 'regconfig json', prosrc => 'json_string_to_tsvector_byid' }, +{ oid => '4216', descr => 'transform specified values from json to tsvector', + proname => 'json_to_tsvector', procost => '100', prorettype => 'tsvector', + proargtypes => 'regconfig json jsonb', prosrc => 'json_to_tsvector_byid' }, + +{ oid => '3752', descr => 'trigger for automatic update of tsvector column', + proname => 'tsvector_update_trigger', proisstrict => 'f', provolatile => 'v', + prorettype => 'trigger', proargtypes => '', + prosrc => 'tsvector_update_trigger_byid' }, +{ oid => '3753', descr => 'trigger for automatic update of tsvector column', + proname => 'tsvector_update_trigger_column', proisstrict => 'f', + provolatile => 'v', prorettype => 'trigger', proargtypes => '', + prosrc => 'tsvector_update_trigger_bycolumn' }, + +{ oid => '3759', descr => 'get current tsearch configuration', + proname => 'get_current_ts_config', provolatile => 's', + prorettype => 'regconfig', proargtypes => '', + prosrc => 'get_current_ts_config' }, + +{ oid => '3736', descr => 'I/O', + proname => 'regconfigin', provolatile => 's', prorettype => 'regconfig', + proargtypes => 'cstring', prosrc => 'regconfigin' }, +{ oid => '3737', descr => 'I/O', + proname => 'regconfigout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regconfig', prosrc => 'regconfigout' }, +{ oid => '3738', descr => 'I/O', + proname => 'regconfigrecv', prorettype => 'regconfig', + proargtypes => 'internal', prosrc => 'regconfigrecv' }, +{ oid => '3739', descr => 'I/O', + proname => 'regconfigsend', prorettype => 'bytea', proargtypes => 'regconfig', + prosrc => 'regconfigsend' }, + +{ oid => '3771', descr => 'I/O', + proname => 'regdictionaryin', provolatile => 's', + prorettype => 'regdictionary', proargtypes => 'cstring', + prosrc => 'regdictionaryin' }, +{ oid => '3772', descr => 'I/O', + proname => 'regdictionaryout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regdictionary', prosrc => 'regdictionaryout' }, +{ oid => '3773', descr => 'I/O', + proname => 'regdictionaryrecv', prorettype => 'regdictionary', + proargtypes => 'internal', prosrc => 'regdictionaryrecv' }, +{ oid => '3774', descr => 'I/O', + proname => 'regdictionarysend', prorettype => 'bytea', + proargtypes => 'regdictionary', prosrc => 'regdictionarysend' }, + +# jsonb +{ oid => '3806', descr => 'I/O', + proname => 'jsonb_in', prorettype => 'jsonb', proargtypes => 'cstring', + prosrc => 'jsonb_in' }, +{ oid => '3805', descr => 'I/O', + proname => 'jsonb_recv', prorettype => 'jsonb', proargtypes => 'internal', + prosrc => 'jsonb_recv' }, +{ oid => '3804', descr => 'I/O', + proname => 'jsonb_out', prorettype => 'cstring', proargtypes => 'jsonb', + prosrc => 'jsonb_out' }, +{ oid => '3803', descr => 'I/O', + proname => 'jsonb_send', prorettype => 'bytea', proargtypes => 'jsonb', + prosrc => 'jsonb_send' }, + +{ oid => '3263', descr => 'map text array of key value pairs to jsonb object', + proname => 'jsonb_object', prorettype => 'jsonb', proargtypes => '_text', + prosrc => 'jsonb_object' }, +{ oid => '3264', descr => 'map text array of key value pairs to jsonb object', + proname => 'jsonb_object', prorettype => 'jsonb', + proargtypes => '_text _text', prosrc => 'jsonb_object_two_arg' }, +{ oid => '3787', descr => 'map input to jsonb', + proname => 'to_jsonb', provolatile => 's', prorettype => 'jsonb', + proargtypes => 'anyelement', prosrc => 'to_jsonb' }, +{ oid => '3265', descr => 'jsonb aggregate transition function', + proname => 'jsonb_agg_transfn', proisstrict => 'f', provolatile => 's', + prorettype => 'internal', proargtypes => 'internal anyelement', + prosrc => 'jsonb_agg_transfn' }, +{ oid => '3266', descr => 'jsonb aggregate final function', + proname => 'jsonb_agg_finalfn', proisstrict => 'f', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'internal', + prosrc => 'jsonb_agg_finalfn' }, +{ oid => '3267', descr => 'aggregate input into jsonb', + proname => 'jsonb_agg', prokind => 'a', proisstrict => 'f', + provolatile => 's', prorettype => 'jsonb', proargtypes => 'anyelement', + prosrc => 'aggregate_dummy' }, +{ oid => '3268', descr => 'jsonb object aggregate transition function', + proname => 'jsonb_object_agg_transfn', proisstrict => 'f', provolatile => 's', + prorettype => 'internal', proargtypes => 'internal any any', + prosrc => 'jsonb_object_agg_transfn' }, +{ oid => '3269', descr => 'jsonb object aggregate final function', + proname => 'jsonb_object_agg_finalfn', proisstrict => 'f', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'internal', + prosrc => 'jsonb_object_agg_finalfn' }, +{ oid => '3270', descr => 'aggregate inputs into jsonb object', + proname => 'jsonb_object_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'jsonb', proargtypes => 'any any', + prosrc => 'aggregate_dummy' }, +{ oid => '3271', descr => 'build a jsonb array from any inputs', + proname => 'jsonb_build_array', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'jsonb', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'jsonb_build_array' }, +{ oid => '3272', descr => 'build an empty jsonb array', + proname => 'jsonb_build_array', proisstrict => 'f', provolatile => 's', + prorettype => 'jsonb', proargtypes => '', + prosrc => 'jsonb_build_array_noargs' }, +{ oid => '3273', + descr => 'build a jsonb object from pairwise key/value inputs', + proname => 'jsonb_build_object', provariadic => 'any', proisstrict => 'f', + provolatile => 's', prorettype => 'jsonb', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'jsonb_build_object' }, +{ oid => '3274', descr => 'build an empty jsonb object', + proname => 'jsonb_build_object', proisstrict => 'f', provolatile => 's', + prorettype => 'jsonb', proargtypes => '', + prosrc => 'jsonb_build_object_noargs' }, +{ oid => '3262', descr => 'remove object fields with null values from jsonb', + proname => 'jsonb_strip_nulls', prorettype => 'jsonb', proargtypes => 'jsonb', + prosrc => 'jsonb_strip_nulls' }, + +{ oid => '3478', + proname => 'jsonb_object_field', prorettype => 'jsonb', + proargtypes => 'jsonb text', proargnames => '{from_json, field_name}', + prosrc => 'jsonb_object_field' }, +{ oid => '3214', + proname => 'jsonb_object_field_text', prorettype => 'text', + proargtypes => 'jsonb text', proargnames => '{from_json, field_name}', + prosrc => 'jsonb_object_field_text' }, +{ oid => '3215', + proname => 'jsonb_array_element', prorettype => 'jsonb', + proargtypes => 'jsonb int4', proargnames => '{from_json, element_index}', + prosrc => 'jsonb_array_element' }, +{ oid => '3216', + proname => 'jsonb_array_element_text', prorettype => 'text', + proargtypes => 'jsonb int4', proargnames => '{from_json, element_index}', + prosrc => 'jsonb_array_element_text' }, +{ oid => '3217', descr => 'get value from jsonb with path elements', + proname => 'jsonb_extract_path', provariadic => 'text', prorettype => 'jsonb', + proargtypes => 'jsonb _text', proallargtypes => '{jsonb,_text}', + proargmodes => '{i,v}', proargnames => '{from_json,path_elems}', + prosrc => 'jsonb_extract_path' }, +{ oid => '3940', descr => 'get value from jsonb as text with path elements', + proname => 'jsonb_extract_path_text', provariadic => 'text', + prorettype => 'text', proargtypes => 'jsonb _text', + proallargtypes => '{jsonb,_text}', proargmodes => '{i,v}', + proargnames => '{from_json,path_elems}', + prosrc => 'jsonb_extract_path_text' }, +{ oid => '3219', descr => 'elements of a jsonb array', + proname => 'jsonb_array_elements', prorows => '100', proretset => 't', + prorettype => 'jsonb', proargtypes => 'jsonb', + proallargtypes => '{jsonb,jsonb}', proargmodes => '{i,o}', + proargnames => '{from_json,value}', prosrc => 'jsonb_array_elements' }, +{ oid => '3465', descr => 'elements of jsonb array', + proname => 'jsonb_array_elements_text', prorows => '100', proretset => 't', + prorettype => 'text', proargtypes => 'jsonb', + proallargtypes => '{jsonb,text}', proargmodes => '{i,o}', + proargnames => '{from_json,value}', prosrc => 'jsonb_array_elements_text' }, +{ oid => '3207', descr => 'length of jsonb array', + proname => 'jsonb_array_length', prorettype => 'int4', proargtypes => 'jsonb', + prosrc => 'jsonb_array_length' }, +{ oid => '3931', descr => 'get jsonb object keys', + proname => 'jsonb_object_keys', prorows => '100', proretset => 't', + prorettype => 'text', proargtypes => 'jsonb', prosrc => 'jsonb_object_keys' }, +{ oid => '3208', descr => 'key value pairs of a jsonb object', + proname => 'jsonb_each', prorows => '100', proretset => 't', + prorettype => 'record', proargtypes => 'jsonb', + proallargtypes => '{jsonb,text,jsonb}', proargmodes => '{i,o,o}', + proargnames => '{from_json,key,value}', prosrc => 'jsonb_each' }, +{ oid => '3932', descr => 'key value pairs of a jsonb object', + proname => 'jsonb_each_text', prorows => '100', proretset => 't', + prorettype => 'record', proargtypes => 'jsonb', + proallargtypes => '{jsonb,text,text}', proargmodes => '{i,o,o}', + proargnames => '{from_json,key,value}', prosrc => 'jsonb_each_text' }, +{ oid => '3209', descr => 'get record fields from a jsonb object', + proname => 'jsonb_populate_record', proisstrict => 'f', provolatile => 's', + prorettype => 'anyelement', proargtypes => 'anyelement jsonb', + prosrc => 'jsonb_populate_record' }, +{ oid => '3475', + descr => 'get set of records with fields from a jsonb array of objects', + proname => 'jsonb_populate_recordset', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', prorettype => 'anyelement', + proargtypes => 'anyelement jsonb', prosrc => 'jsonb_populate_recordset' }, +{ oid => '3490', descr => 'get record fields from a jsonb object', + proname => 'jsonb_to_record', provolatile => 's', prorettype => 'record', + proargtypes => 'jsonb', prosrc => 'jsonb_to_record' }, +{ oid => '3491', + descr => 'get set of records with fields from a jsonb array of objects', + proname => 'jsonb_to_recordset', prorows => '100', proisstrict => 'f', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => 'jsonb', prosrc => 'jsonb_to_recordset' }, +{ oid => '3210', descr => 'get the type of a jsonb value', + proname => 'jsonb_typeof', prorettype => 'text', proargtypes => 'jsonb', + prosrc => 'jsonb_typeof' }, +{ oid => '4038', + proname => 'jsonb_ne', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_ne' }, +{ oid => '4039', + proname => 'jsonb_lt', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_lt' }, +{ oid => '4040', + proname => 'jsonb_gt', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_gt' }, +{ oid => '4041', + proname => 'jsonb_le', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_le' }, +{ oid => '4042', + proname => 'jsonb_ge', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_ge' }, +{ oid => '4043', + proname => 'jsonb_eq', prorettype => 'bool', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_eq' }, +{ oid => '4044', descr => 'less-equal-greater', + proname => 'jsonb_cmp', prorettype => 'int4', proargtypes => 'jsonb jsonb', + prosrc => 'jsonb_cmp' }, +{ oid => '4045', descr => 'hash', + proname => 'jsonb_hash', prorettype => 'int4', proargtypes => 'jsonb', + prosrc => 'jsonb_hash' }, +{ oid => '3416', descr => 'hash', + proname => 'jsonb_hash_extended', prorettype => 'int8', + proargtypes => 'jsonb int8', prosrc => 'jsonb_hash_extended' }, +{ oid => '4046', + proname => 'jsonb_contains', prorettype => 'bool', + proargtypes => 'jsonb jsonb', prosrc => 'jsonb_contains' }, +{ oid => '4047', + proname => 'jsonb_exists', prorettype => 'bool', proargtypes => 'jsonb text', + prosrc => 'jsonb_exists' }, +{ oid => '4048', + proname => 'jsonb_exists_any', prorettype => 'bool', + proargtypes => 'jsonb _text', prosrc => 'jsonb_exists_any' }, +{ oid => '4049', + proname => 'jsonb_exists_all', prorettype => 'bool', + proargtypes => 'jsonb _text', prosrc => 'jsonb_exists_all' }, +{ oid => '4050', + proname => 'jsonb_contained', prorettype => 'bool', + proargtypes => 'jsonb jsonb', prosrc => 'jsonb_contained' }, +{ oid => '3480', descr => 'GIN support', + proname => 'gin_compare_jsonb', prorettype => 'int4', + proargtypes => 'text text', prosrc => 'gin_compare_jsonb' }, +{ oid => '3482', descr => 'GIN support', + proname => 'gin_extract_jsonb', prorettype => 'internal', + proargtypes => 'jsonb internal internal', prosrc => 'gin_extract_jsonb' }, +{ oid => '3483', descr => 'GIN support', + proname => 'gin_extract_jsonb_query', prorettype => 'internal', + proargtypes => 'jsonb internal int2 internal internal internal internal', + prosrc => 'gin_extract_jsonb_query' }, +{ oid => '3484', descr => 'GIN support', + proname => 'gin_consistent_jsonb', prorettype => 'bool', + proargtypes => 'internal int2 jsonb int4 internal internal internal internal', + prosrc => 'gin_consistent_jsonb' }, +{ oid => '3488', descr => 'GIN support', + proname => 'gin_triconsistent_jsonb', prorettype => 'char', + proargtypes => 'internal int2 jsonb int4 internal internal internal', + prosrc => 'gin_triconsistent_jsonb' }, +{ oid => '3485', descr => 'GIN support', + proname => 'gin_extract_jsonb_path', prorettype => 'internal', + proargtypes => 'jsonb internal internal', + prosrc => 'gin_extract_jsonb_path' }, +{ oid => '3486', descr => 'GIN support', + proname => 'gin_extract_jsonb_query_path', prorettype => 'internal', + proargtypes => 'jsonb internal int2 internal internal internal internal', + prosrc => 'gin_extract_jsonb_query_path' }, +{ oid => '3487', descr => 'GIN support', + proname => 'gin_consistent_jsonb_path', prorettype => 'bool', + proargtypes => 'internal int2 jsonb int4 internal internal internal internal', + prosrc => 'gin_consistent_jsonb_path' }, +{ oid => '3489', descr => 'GIN support', + proname => 'gin_triconsistent_jsonb_path', prorettype => 'char', + proargtypes => 'internal int2 jsonb int4 internal internal internal', + prosrc => 'gin_triconsistent_jsonb_path' }, +{ oid => '3301', + proname => 'jsonb_concat', prorettype => 'jsonb', + proargtypes => 'jsonb jsonb', prosrc => 'jsonb_concat' }, +{ oid => '3302', + proname => 'jsonb_delete', prorettype => 'jsonb', proargtypes => 'jsonb text', + prosrc => 'jsonb_delete' }, +{ oid => '3303', + proname => 'jsonb_delete', prorettype => 'jsonb', proargtypes => 'jsonb int4', + prosrc => 'jsonb_delete_idx' }, +{ oid => '3343', + proname => 'jsonb_delete', provariadic => 'text', prorettype => 'jsonb', + proargtypes => 'jsonb _text', proallargtypes => '{jsonb,_text}', + proargmodes => '{i,v}', proargnames => '{from_json,path_elems}', + prosrc => 'jsonb_delete_array' }, +{ oid => '3304', + proname => 'jsonb_delete_path', prorettype => 'jsonb', + proargtypes => 'jsonb _text', prosrc => 'jsonb_delete_path' }, +{ oid => '5054', descr => 'Set part of a jsonb, handle NULL value', + proname => 'jsonb_set_lax', proisstrict => 'f', prorettype => 'jsonb', + proargtypes => 'jsonb _text jsonb bool text', prosrc => 'jsonb_set_lax' }, +{ oid => '3305', descr => 'Set part of a jsonb', + proname => 'jsonb_set', prorettype => 'jsonb', + proargtypes => 'jsonb _text jsonb bool', prosrc => 'jsonb_set' }, +{ oid => '3306', descr => 'Indented text from jsonb', + proname => 'jsonb_pretty', prorettype => 'text', proargtypes => 'jsonb', + prosrc => 'jsonb_pretty' }, +{ oid => '3579', descr => 'Insert value into a jsonb', + proname => 'jsonb_insert', prorettype => 'jsonb', + proargtypes => 'jsonb _text jsonb bool', prosrc => 'jsonb_insert' }, + +# jsonpath +{ oid => '4001', descr => 'I/O', + proname => 'jsonpath_in', prorettype => 'jsonpath', proargtypes => 'cstring', + prosrc => 'jsonpath_in' }, +{ oid => '4002', descr => 'I/O', + proname => 'jsonpath_recv', prorettype => 'jsonpath', + proargtypes => 'internal', prosrc => 'jsonpath_recv' }, +{ oid => '4003', descr => 'I/O', + proname => 'jsonpath_out', prorettype => 'cstring', proargtypes => 'jsonpath', + prosrc => 'jsonpath_out' }, +{ oid => '4004', descr => 'I/O', + proname => 'jsonpath_send', prorettype => 'bytea', proargtypes => 'jsonpath', + prosrc => 'jsonpath_send' }, + +{ oid => '4005', descr => 'jsonpath exists test', + proname => 'jsonb_path_exists', prorettype => 'bool', + proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_exists' }, +{ oid => '4006', descr => 'jsonpath query', + proname => 'jsonb_path_query', prorows => '1000', proretset => 't', + prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_query' }, +{ oid => '4007', descr => 'jsonpath query wrapped into array', + proname => 'jsonb_path_query_array', prorettype => 'jsonb', + proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_query_array' }, +{ oid => '4008', descr => 'jsonpath query first item', + proname => 'jsonb_path_query_first', prorettype => 'jsonb', + proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_query_first' }, +{ oid => '4009', descr => 'jsonpath match', + proname => 'jsonb_path_match', prorettype => 'bool', + proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_match' }, + +{ oid => '1177', descr => 'jsonpath exists test with timezone', + proname => 'jsonb_path_exists_tz', provolatile => 's', prorettype => 'bool', + proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_exists_tz' }, +{ oid => '1179', descr => 'jsonpath query with timezone', + proname => 'jsonb_path_query_tz', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'jsonb', + proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_query_tz' }, +{ oid => '1180', descr => 'jsonpath query wrapped into array with timezone', + proname => 'jsonb_path_query_array_tz', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_query_array_tz' }, +{ oid => '2023', descr => 'jsonpath query first item with timezone', + proname => 'jsonb_path_query_first_tz', provolatile => 's', + prorettype => 'jsonb', proargtypes => 'jsonb jsonpath jsonb bool', + prosrc => 'jsonb_path_query_first_tz' }, +{ oid => '2030', descr => 'jsonpath match with timezone', + proname => 'jsonb_path_match_tz', provolatile => 's', prorettype => 'bool', + proargtypes => 'jsonb jsonpath jsonb bool', prosrc => 'jsonb_path_match_tz' }, + +{ oid => '4010', descr => 'implementation of @? operator', + proname => 'jsonb_path_exists_opr', prorettype => 'bool', + proargtypes => 'jsonb jsonpath', prosrc => 'jsonb_path_exists_opr' }, +{ oid => '4011', descr => 'implementation of @@ operator', + proname => 'jsonb_path_match_opr', prorettype => 'bool', + proargtypes => 'jsonb jsonpath', prosrc => 'jsonb_path_match_opr' }, + +# historical int8/txid_snapshot variants of xid8 functions +{ oid => '2939', descr => 'I/O', + proname => 'txid_snapshot_in', prorettype => 'txid_snapshot', + proargtypes => 'cstring', prosrc => 'pg_snapshot_in' }, +{ oid => '2940', descr => 'I/O', + proname => 'txid_snapshot_out', prorettype => 'cstring', + proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_out' }, +{ oid => '2941', descr => 'I/O', + proname => 'txid_snapshot_recv', prorettype => 'txid_snapshot', + proargtypes => 'internal', prosrc => 'pg_snapshot_recv' }, +{ oid => '2942', descr => 'I/O', + proname => 'txid_snapshot_send', prorettype => 'bytea', + proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_send' }, +{ oid => '2943', descr => 'get current transaction ID', + proname => 'txid_current', provolatile => 's', proparallel => 'u', + prorettype => 'int8', proargtypes => '', prosrc => 'pg_current_xact_id' }, +{ oid => '3348', descr => 'get current transaction ID', + proname => 'txid_current_if_assigned', provolatile => 's', proparallel => 'u', + prorettype => 'int8', proargtypes => '', + prosrc => 'pg_current_xact_id_if_assigned' }, +{ oid => '2944', descr => 'get current snapshot', + proname => 'txid_current_snapshot', provolatile => 's', + prorettype => 'txid_snapshot', proargtypes => '', + prosrc => 'pg_current_snapshot' }, +{ oid => '2945', descr => 'get xmin of snapshot', + proname => 'txid_snapshot_xmin', prorettype => 'int8', + proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_xmin' }, +{ oid => '2946', descr => 'get xmax of snapshot', + proname => 'txid_snapshot_xmax', prorettype => 'int8', + proargtypes => 'txid_snapshot', prosrc => 'pg_snapshot_xmax' }, +{ oid => '2947', descr => 'get set of in-progress txids in snapshot', + proname => 'txid_snapshot_xip', prorows => '50', proretset => 't', + prorettype => 'int8', proargtypes => 'txid_snapshot', + prosrc => 'pg_snapshot_xip' }, +{ oid => '2948', descr => 'is txid visible in snapshot?', + proname => 'txid_visible_in_snapshot', prorettype => 'bool', + proargtypes => 'int8 txid_snapshot', prosrc => 'pg_visible_in_snapshot' }, +{ oid => '3360', descr => 'commit status of transaction', + proname => 'txid_status', provolatile => 'v', prorettype => 'text', + proargtypes => 'int8', prosrc => 'pg_xact_status' }, + +# pg_snapshot functions +{ oid => '5055', descr => 'I/O', + proname => 'pg_snapshot_in', prorettype => 'pg_snapshot', + proargtypes => 'cstring', prosrc => 'pg_snapshot_in' }, +{ oid => '5056', descr => 'I/O', + proname => 'pg_snapshot_out', prorettype => 'cstring', + proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_out' }, +{ oid => '5057', descr => 'I/O', + proname => 'pg_snapshot_recv', prorettype => 'pg_snapshot', + proargtypes => 'internal', prosrc => 'pg_snapshot_recv' }, +{ oid => '5058', descr => 'I/O', + proname => 'pg_snapshot_send', prorettype => 'bytea', + proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_send' }, +{ oid => '5061', descr => 'get current snapshot', + proname => 'pg_current_snapshot', provolatile => 's', + prorettype => 'pg_snapshot', proargtypes => '', + prosrc => 'pg_current_snapshot' }, +{ oid => '5062', descr => 'get xmin of snapshot', + proname => 'pg_snapshot_xmin', prorettype => 'xid8', + proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_xmin' }, +{ oid => '5063', descr => 'get xmax of snapshot', + proname => 'pg_snapshot_xmax', prorettype => 'xid8', + proargtypes => 'pg_snapshot', prosrc => 'pg_snapshot_xmax' }, +{ oid => '5064', descr => 'get set of in-progress transactions in snapshot', + proname => 'pg_snapshot_xip', prorows => '50', proretset => 't', + prorettype => 'xid8', proargtypes => 'pg_snapshot', + prosrc => 'pg_snapshot_xip' }, +{ oid => '5065', descr => 'is xid8 visible in snapshot?', + proname => 'pg_visible_in_snapshot', prorettype => 'bool', + proargtypes => 'xid8 pg_snapshot', prosrc => 'pg_visible_in_snapshot' }, + +# transaction ID and status functions +{ oid => '5059', descr => 'get current transaction ID', + proname => 'pg_current_xact_id', provolatile => 's', proparallel => 'u', + prorettype => 'xid8', proargtypes => '', prosrc => 'pg_current_xact_id' }, +{ oid => '5060', descr => 'get current transaction ID', + proname => 'pg_current_xact_id_if_assigned', provolatile => 's', + proparallel => 'u', prorettype => 'xid8', proargtypes => '', + prosrc => 'pg_current_xact_id_if_assigned' }, +{ oid => '5066', descr => 'commit status of transaction', + proname => 'pg_xact_status', provolatile => 'v', prorettype => 'text', + proargtypes => 'xid8', prosrc => 'pg_xact_status' }, + +# record comparison using normal comparison rules +{ oid => '2981', + proname => 'record_eq', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_eq' }, +{ oid => '2982', + proname => 'record_ne', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_ne' }, +{ oid => '2983', + proname => 'record_lt', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_lt' }, +{ oid => '2984', + proname => 'record_gt', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_gt' }, +{ oid => '2985', + proname => 'record_le', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_le' }, +{ oid => '2986', + proname => 'record_ge', prorettype => 'bool', proargtypes => 'record record', + prosrc => 'record_ge' }, +{ oid => '2987', descr => 'less-equal-greater', + proname => 'btrecordcmp', prorettype => 'int4', + proargtypes => 'record record', prosrc => 'btrecordcmp' }, + +{ oid => '6192', descr => 'hash', + proname => 'hash_record', prorettype => 'int4', proargtypes => 'record', + prosrc => 'hash_record' }, +{ oid => '6193', descr => 'hash', + proname => 'hash_record_extended', prorettype => 'int8', + proargtypes => 'record int8', prosrc => 'hash_record_extended' }, + +# record comparison using raw byte images +{ oid => '3181', + proname => 'record_image_eq', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_eq' }, +{ oid => '3182', + proname => 'record_image_ne', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_ne' }, +{ oid => '3183', + proname => 'record_image_lt', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_lt' }, +{ oid => '3184', + proname => 'record_image_gt', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_gt' }, +{ oid => '3185', + proname => 'record_image_le', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_le' }, +{ oid => '3186', + proname => 'record_image_ge', prorettype => 'bool', + proargtypes => 'record record', prosrc => 'record_image_ge' }, +{ oid => '3187', descr => 'less-equal-greater based on byte images', + proname => 'btrecordimagecmp', prorettype => 'int4', + proargtypes => 'record record', prosrc => 'btrecordimagecmp' }, +{ oid => '5051', descr => 'equal image', + proname => 'btequalimage', prorettype => 'bool', proargtypes => 'oid', + prosrc => 'btequalimage' }, + +# Extensions +{ oid => '3082', descr => 'list available extensions', + proname => 'pg_available_extensions', procost => '10', prorows => '100', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => '', proallargtypes => '{name,text,text}', + proargmodes => '{o,o,o}', proargnames => '{name,default_version,comment}', + prosrc => 'pg_available_extensions' }, +{ oid => '3083', descr => 'list available extension versions', + proname => 'pg_available_extension_versions', procost => '10', + prorows => '100', proretset => 't', provolatile => 's', + prorettype => 'record', proargtypes => '', + proallargtypes => '{name,text,bool,bool,bool,name,_name,text}', + proargmodes => '{o,o,o,o,o,o,o,o}', + proargnames => '{name,version,superuser,trusted,relocatable,schema,requires,comment}', + prosrc => 'pg_available_extension_versions' }, +{ oid => '3084', descr => 'list an extension\'s version update paths', + proname => 'pg_extension_update_paths', procost => '10', prorows => '100', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => 'name', proallargtypes => '{name,text,text,text}', + proargmodes => '{i,o,o,o}', proargnames => '{name,source,target,path}', + prosrc => 'pg_extension_update_paths' }, +{ oid => '3086', + descr => 'flag an extension\'s table contents to be emitted by pg_dump', + proname => 'pg_extension_config_dump', provolatile => 'v', proparallel => 'u', + prorettype => 'void', proargtypes => 'regclass text', + prosrc => 'pg_extension_config_dump' }, + +# SQL-spec window functions +{ oid => '3100', descr => 'row number within partition', + proname => 'row_number', prosupport => 'window_row_number_support', + prokind => 'w', proisstrict => 'f', prorettype => 'int8', proargtypes => '', + prosrc => 'window_row_number' }, +{ oid => '6233', descr => 'planner support for row_number run condition', + proname => 'window_row_number_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'window_row_number_support' }, +{ oid => '3101', descr => 'integer rank with gaps', + proname => 'rank', prosupport => 'window_rank_support', prokind => 'w', + proisstrict => 'f', prorettype => 'int8', proargtypes => '', + prosrc => 'window_rank' }, +{ oid => '6234', descr => 'planner support for rank run condition', + proname => 'window_rank_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'window_rank_support' }, +{ oid => '3102', descr => 'integer rank without gaps', + proname => 'dense_rank', prosupport => 'window_dense_rank_support', + prokind => 'w', proisstrict => 'f', prorettype => 'int8', proargtypes => '', + prosrc => 'window_dense_rank' }, +{ oid => '6235', descr => 'planner support for dense rank run condition', + proname => 'window_dense_rank_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'window_dense_rank_support' }, +{ oid => '3103', descr => 'fractional rank within partition', + proname => 'percent_rank', prokind => 'w', proisstrict => 'f', + prorettype => 'float8', proargtypes => '', prosrc => 'window_percent_rank' }, +{ oid => '3104', descr => 'fractional row number within partition', + proname => 'cume_dist', prokind => 'w', proisstrict => 'f', + prorettype => 'float8', proargtypes => '', prosrc => 'window_cume_dist' }, +{ oid => '3105', descr => 'split rows into N groups', + proname => 'ntile', prokind => 'w', prorettype => 'int4', + proargtypes => 'int4', prosrc => 'window_ntile' }, +{ oid => '3106', descr => 'fetch the preceding row value', + proname => 'lag', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_lag' }, +{ oid => '3107', descr => 'fetch the Nth preceding row value', + proname => 'lag', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement int4', prosrc => 'window_lag_with_offset' }, +{ oid => '3108', descr => 'fetch the Nth preceding row value with default', + proname => 'lag', prokind => 'w', prorettype => 'anycompatible', + proargtypes => 'anycompatible int4 anycompatible', + prosrc => 'window_lag_with_offset_and_default' }, +{ oid => '3109', descr => 'fetch the following row value', + proname => 'lead', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_lead' }, +{ oid => '3110', descr => 'fetch the Nth following row value', + proname => 'lead', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement int4', prosrc => 'window_lead_with_offset' }, +{ oid => '3111', descr => 'fetch the Nth following row value with default', + proname => 'lead', prokind => 'w', prorettype => 'anycompatible', + proargtypes => 'anycompatible int4 anycompatible', + prosrc => 'window_lead_with_offset_and_default' }, +{ oid => '3112', descr => 'fetch the first row value', + proname => 'first_value', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_first_value' }, +{ oid => '3113', descr => 'fetch the last row value', + proname => 'last_value', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement', prosrc => 'window_last_value' }, +{ oid => '3114', descr => 'fetch the Nth row value', + proname => 'nth_value', prokind => 'w', prorettype => 'anyelement', + proargtypes => 'anyelement int4', prosrc => 'window_nth_value' }, + +# functions for range types +{ oid => '3832', descr => 'I/O', + proname => 'anyrange_in', provolatile => 's', prorettype => 'anyrange', + proargtypes => 'cstring oid int4', prosrc => 'anyrange_in' }, +{ oid => '3833', descr => 'I/O', + proname => 'anyrange_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyrange', prosrc => 'anyrange_out' }, +{ oid => '3834', descr => 'I/O', + proname => 'range_in', provolatile => 's', prorettype => 'anyrange', + proargtypes => 'cstring oid int4', prosrc => 'range_in' }, +{ oid => '3835', descr => 'I/O', + proname => 'range_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anyrange', prosrc => 'range_out' }, +{ oid => '3836', descr => 'I/O', + proname => 'range_recv', provolatile => 's', prorettype => 'anyrange', + proargtypes => 'internal oid int4', prosrc => 'range_recv' }, +{ oid => '3837', descr => 'I/O', + proname => 'range_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'anyrange', prosrc => 'range_send' }, +{ oid => '3848', descr => 'lower bound of range', + proname => 'lower', prorettype => 'anyelement', proargtypes => 'anyrange', + prosrc => 'range_lower' }, +{ oid => '3849', descr => 'upper bound of range', + proname => 'upper', prorettype => 'anyelement', proargtypes => 'anyrange', + prosrc => 'range_upper' }, +{ oid => '3850', descr => 'is the range empty?', + proname => 'isempty', prorettype => 'bool', proargtypes => 'anyrange', + prosrc => 'range_empty' }, +{ oid => '3851', descr => 'is the range\'s lower bound inclusive?', + proname => 'lower_inc', prorettype => 'bool', proargtypes => 'anyrange', + prosrc => 'range_lower_inc' }, +{ oid => '3852', descr => 'is the range\'s upper bound inclusive?', + proname => 'upper_inc', prorettype => 'bool', proargtypes => 'anyrange', + prosrc => 'range_upper_inc' }, +{ oid => '3853', descr => 'is the range\'s lower bound infinite?', + proname => 'lower_inf', prorettype => 'bool', proargtypes => 'anyrange', + prosrc => 'range_lower_inf' }, +{ oid => '3854', descr => 'is the range\'s upper bound infinite?', + proname => 'upper_inf', prorettype => 'bool', proargtypes => 'anyrange', + prosrc => 'range_upper_inf' }, +{ oid => '3855', + proname => 'range_eq', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_eq' }, +{ oid => '3856', + proname => 'range_ne', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_ne' }, +{ oid => '3857', + proname => 'range_overlaps', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_overlaps' }, +{ oid => '3858', + proname => 'range_contains_elem', prorettype => 'bool', + proargtypes => 'anyrange anyelement', prosrc => 'range_contains_elem' }, +{ oid => '3859', + proname => 'range_contains', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_contains' }, +{ oid => '3860', + proname => 'elem_contained_by_range', prorettype => 'bool', + proargtypes => 'anyelement anyrange', prosrc => 'elem_contained_by_range' }, +{ oid => '3861', + proname => 'range_contained_by', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_contained_by' }, +{ oid => '3862', + proname => 'range_adjacent', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_adjacent' }, +{ oid => '3863', + proname => 'range_before', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_before' }, +{ oid => '3864', + proname => 'range_after', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_after' }, +{ oid => '3865', + proname => 'range_overleft', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_overleft' }, +{ oid => '3866', + proname => 'range_overright', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_overright' }, +{ oid => '3867', + proname => 'range_union', prorettype => 'anyrange', + proargtypes => 'anyrange anyrange', prosrc => 'range_union' }, +{ oid => '4057', + descr => 'the smallest range which includes both of the given ranges', + proname => 'range_merge', prorettype => 'anyrange', + proargtypes => 'anyrange anyrange', prosrc => 'range_merge' }, +{ oid => '4228', + descr => 'the smallest range which includes the whole multirange', + proname => 'range_merge', prorettype => 'anyrange', + proargtypes => 'anymultirange', prosrc => 'range_merge_from_multirange' }, +{ oid => '3868', + proname => 'range_intersect', prorettype => 'anyrange', + proargtypes => 'anyrange anyrange', prosrc => 'range_intersect' }, +{ oid => '3869', + proname => 'range_minus', prorettype => 'anyrange', + proargtypes => 'anyrange anyrange', prosrc => 'range_minus' }, +{ oid => '3870', descr => 'less-equal-greater', + proname => 'range_cmp', prorettype => 'int4', + proargtypes => 'anyrange anyrange', prosrc => 'range_cmp' }, +{ oid => '3871', + proname => 'range_lt', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_lt' }, +{ oid => '3872', + proname => 'range_le', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_le' }, +{ oid => '3873', + proname => 'range_ge', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_ge' }, +{ oid => '3874', + proname => 'range_gt', prorettype => 'bool', + proargtypes => 'anyrange anyrange', prosrc => 'range_gt' }, +{ oid => '3875', descr => 'GiST support', + proname => 'range_gist_consistent', prorettype => 'bool', + proargtypes => 'internal anyrange int2 oid internal', + prosrc => 'range_gist_consistent' }, +{ oid => '3876', descr => 'GiST support', + proname => 'range_gist_union', prorettype => 'anyrange', + proargtypes => 'internal internal', prosrc => 'range_gist_union' }, +{ oid => '3879', descr => 'GiST support', + proname => 'range_gist_penalty', prorettype => 'internal', + proargtypes => 'internal internal internal', prosrc => 'range_gist_penalty' }, +{ oid => '3880', descr => 'GiST support', + proname => 'range_gist_picksplit', prorettype => 'internal', + proargtypes => 'internal internal', prosrc => 'range_gist_picksplit' }, +{ oid => '3881', descr => 'GiST support', + proname => 'range_gist_same', prorettype => 'internal', + proargtypes => 'anyrange anyrange internal', prosrc => 'range_gist_same' }, +{ oid => '6154', descr => 'GiST support', + proname => 'multirange_gist_consistent', prorettype => 'bool', + proargtypes => 'internal anymultirange int2 oid internal', + prosrc => 'multirange_gist_consistent' }, +{ oid => '6156', descr => 'GiST support', + proname => 'multirange_gist_compress', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'multirange_gist_compress' }, +{ oid => '3902', descr => 'hash a range', + proname => 'hash_range', prorettype => 'int4', proargtypes => 'anyrange', + prosrc => 'hash_range' }, +{ oid => '3417', descr => 'hash a range', + proname => 'hash_range_extended', prorettype => 'int8', + proargtypes => 'anyrange int8', prosrc => 'hash_range_extended' }, +{ oid => '3916', descr => 'range typanalyze', + proname => 'range_typanalyze', provolatile => 's', prorettype => 'bool', + proargtypes => 'internal', prosrc => 'range_typanalyze' }, +{ oid => '3169', descr => 'restriction selectivity for range operators', + proname => 'rangesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'rangesel' }, +{ oid => '4401', descr => 'range aggregate by intersecting', + proname => 'range_intersect_agg_transfn', prorettype => 'anyrange', + proargtypes => 'anyrange anyrange', prosrc => 'range_intersect_agg_transfn' }, +{ oid => '4450', descr => 'range aggregate by intersecting', + proname => 'range_intersect_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anyrange', proargtypes => 'anyrange', + prosrc => 'aggregate_dummy' }, + +{ oid => '3914', descr => 'convert an int4 range to canonical form', + proname => 'int4range_canonical', prorettype => 'int4range', + proargtypes => 'int4range', prosrc => 'int4range_canonical' }, +{ oid => '3928', descr => 'convert an int8 range to canonical form', + proname => 'int8range_canonical', prorettype => 'int8range', + proargtypes => 'int8range', prosrc => 'int8range_canonical' }, +{ oid => '3915', descr => 'convert a date range to canonical form', + proname => 'daterange_canonical', prorettype => 'daterange', + proargtypes => 'daterange', prosrc => 'daterange_canonical' }, +{ oid => '3922', descr => 'float8 difference of two int4 values', + proname => 'int4range_subdiff', prorettype => 'float8', + proargtypes => 'int4 int4', prosrc => 'int4range_subdiff' }, +{ oid => '3923', descr => 'float8 difference of two int8 values', + proname => 'int8range_subdiff', prorettype => 'float8', + proargtypes => 'int8 int8', prosrc => 'int8range_subdiff' }, +{ oid => '3924', descr => 'float8 difference of two numeric values', + proname => 'numrange_subdiff', prorettype => 'float8', + proargtypes => 'numeric numeric', prosrc => 'numrange_subdiff' }, +{ oid => '3925', descr => 'float8 difference of two date values', + proname => 'daterange_subdiff', prorettype => 'float8', + proargtypes => 'date date', prosrc => 'daterange_subdiff' }, +{ oid => '3929', descr => 'float8 difference of two timestamp values', + proname => 'tsrange_subdiff', prorettype => 'float8', + proargtypes => 'timestamp timestamp', prosrc => 'tsrange_subdiff' }, +{ oid => '3930', + descr => 'float8 difference of two timestamp with time zone values', + proname => 'tstzrange_subdiff', prorettype => 'float8', + proargtypes => 'timestamptz timestamptz', prosrc => 'tstzrange_subdiff' }, + +{ oid => '3840', descr => 'int4range constructor', + proname => 'int4range', proisstrict => 'f', prorettype => 'int4range', + proargtypes => 'int4 int4', prosrc => 'range_constructor2' }, +{ oid => '3841', descr => 'int4range constructor', + proname => 'int4range', proisstrict => 'f', prorettype => 'int4range', + proargtypes => 'int4 int4 text', prosrc => 'range_constructor3' }, +{ oid => '3844', descr => 'numrange constructor', + proname => 'numrange', proisstrict => 'f', prorettype => 'numrange', + proargtypes => 'numeric numeric', prosrc => 'range_constructor2' }, +{ oid => '3845', descr => 'numrange constructor', + proname => 'numrange', proisstrict => 'f', prorettype => 'numrange', + proargtypes => 'numeric numeric text', prosrc => 'range_constructor3' }, +{ oid => '3933', descr => 'tsrange constructor', + proname => 'tsrange', proisstrict => 'f', prorettype => 'tsrange', + proargtypes => 'timestamp timestamp', prosrc => 'range_constructor2' }, +{ oid => '3934', descr => 'tsrange constructor', + proname => 'tsrange', proisstrict => 'f', prorettype => 'tsrange', + proargtypes => 'timestamp timestamp text', prosrc => 'range_constructor3' }, +{ oid => '3937', descr => 'tstzrange constructor', + proname => 'tstzrange', proisstrict => 'f', prorettype => 'tstzrange', + proargtypes => 'timestamptz timestamptz', prosrc => 'range_constructor2' }, +{ oid => '3938', descr => 'tstzrange constructor', + proname => 'tstzrange', proisstrict => 'f', prorettype => 'tstzrange', + proargtypes => 'timestamptz timestamptz text', + prosrc => 'range_constructor3' }, +{ oid => '3941', descr => 'daterange constructor', + proname => 'daterange', proisstrict => 'f', prorettype => 'daterange', + proargtypes => 'date date', prosrc => 'range_constructor2' }, +{ oid => '3942', descr => 'daterange constructor', + proname => 'daterange', proisstrict => 'f', prorettype => 'daterange', + proargtypes => 'date date text', prosrc => 'range_constructor3' }, +{ oid => '3945', descr => 'int8range constructor', + proname => 'int8range', proisstrict => 'f', prorettype => 'int8range', + proargtypes => 'int8 int8', prosrc => 'range_constructor2' }, +{ oid => '3946', descr => 'int8range constructor', + proname => 'int8range', proisstrict => 'f', prorettype => 'int8range', + proargtypes => 'int8 int8 text', prosrc => 'range_constructor3' }, + +# functions for multiranges +{ oid => '4229', descr => 'I/O', + proname => 'anymultirange_in', provolatile => 's', + prorettype => 'anymultirange', proargtypes => 'cstring oid int4', + prosrc => 'anymultirange_in' }, +{ oid => '4230', descr => 'I/O', + proname => 'anymultirange_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anymultirange', prosrc => 'anymultirange_out' }, +{ oid => '4231', descr => 'I/O', + proname => 'multirange_in', provolatile => 's', prorettype => 'anymultirange', + proargtypes => 'cstring oid int4', prosrc => 'multirange_in' }, +{ oid => '4232', descr => 'I/O', + proname => 'multirange_out', provolatile => 's', prorettype => 'cstring', + proargtypes => 'anymultirange', prosrc => 'multirange_out' }, +{ oid => '4233', descr => 'I/O', + proname => 'multirange_recv', provolatile => 's', + prorettype => 'anymultirange', proargtypes => 'internal oid int4', + prosrc => 'multirange_recv' }, +{ oid => '4234', descr => 'I/O', + proname => 'multirange_send', provolatile => 's', prorettype => 'bytea', + proargtypes => 'anymultirange', prosrc => 'multirange_send' }, +{ oid => '4235', descr => 'lower bound of multirange', + proname => 'lower', prorettype => 'anyelement', + proargtypes => 'anymultirange', prosrc => 'multirange_lower' }, +{ oid => '4236', descr => 'upper bound of multirange', + proname => 'upper', prorettype => 'anyelement', + proargtypes => 'anymultirange', prosrc => 'multirange_upper' }, +{ oid => '4237', descr => 'is the multirange empty?', + proname => 'isempty', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_empty' }, +{ oid => '4238', descr => 'is the multirange\'s lower bound inclusive?', + proname => 'lower_inc', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_lower_inc' }, +{ oid => '4239', descr => 'is the multirange\'s upper bound inclusive?', + proname => 'upper_inc', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_upper_inc' }, +{ oid => '4240', descr => 'is the multirange\'s lower bound infinite?', + proname => 'lower_inf', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_lower_inf' }, +{ oid => '4241', descr => 'is the multirange\'s upper bound infinite?', + proname => 'upper_inf', prorettype => 'bool', proargtypes => 'anymultirange', + prosrc => 'multirange_upper_inf' }, +{ oid => '4242', descr => 'multirange typanalyze', + proname => 'multirange_typanalyze', provolatile => 's', prorettype => 'bool', + proargtypes => 'internal', prosrc => 'multirange_typanalyze' }, +{ oid => '4243', descr => 'restriction selectivity for multirange operators', + proname => 'multirangesel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'multirangesel' }, +{ oid => '4244', + proname => 'multirange_eq', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_eq' }, +{ oid => '4245', + proname => 'multirange_ne', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_ne' }, +{ oid => '4246', + proname => 'range_overlaps_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overlaps_multirange' }, +{ oid => '4247', + proname => 'multirange_overlaps_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overlaps_range' }, +{ oid => '4248', + proname => 'multirange_overlaps_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overlaps_multirange' }, +{ oid => '4249', + proname => 'multirange_contains_elem', prorettype => 'bool', + proargtypes => 'anymultirange anyelement', + prosrc => 'multirange_contains_elem' }, +{ oid => '4250', + proname => 'multirange_contains_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_contains_range' }, +{ oid => '4251', + proname => 'multirange_contains_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_contains_multirange' }, +{ oid => '4252', + proname => 'elem_contained_by_multirange', prorettype => 'bool', + proargtypes => 'anyelement anymultirange', + prosrc => 'elem_contained_by_multirange' }, +{ oid => '4253', + proname => 'range_contained_by_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_contained_by_multirange' }, +{ oid => '4541', + proname => 'range_contains_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_contains_multirange' }, +{ oid => '4542', + proname => 'multirange_contained_by_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_contained_by_range' }, +{ oid => '4254', + proname => 'multirange_contained_by_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_contained_by_multirange' }, +{ oid => '4255', + proname => 'range_adjacent_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_adjacent_multirange' }, +{ oid => '4256', + proname => 'multirange_adjacent_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_adjacent_multirange' }, +{ oid => '4257', + proname => 'multirange_adjacent_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_adjacent_range' }, +{ oid => '4258', + proname => 'range_before_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_before_multirange' }, +{ oid => '4259', + proname => 'multirange_before_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_before_range' }, +{ oid => '4260', + proname => 'multirange_before_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_before_multirange' }, +{ oid => '4261', + proname => 'range_after_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', prosrc => 'range_after_multirange' }, +{ oid => '4262', + proname => 'multirange_after_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', prosrc => 'multirange_after_range' }, +{ oid => '4263', + proname => 'multirange_after_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_after_multirange' }, +{ oid => '4264', + proname => 'range_overleft_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overleft_multirange' }, +{ oid => '4265', + proname => 'multirange_overleft_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overleft_range' }, +{ oid => '4266', + proname => 'multirange_overleft_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overleft_multirange' }, +{ oid => '4267', + proname => 'range_overright_multirange', prorettype => 'bool', + proargtypes => 'anyrange anymultirange', + prosrc => 'range_overright_multirange' }, +{ oid => '4268', + proname => 'multirange_overright_range', prorettype => 'bool', + proargtypes => 'anymultirange anyrange', + prosrc => 'multirange_overright_range' }, +{ oid => '4269', + proname => 'multirange_overright_multirange', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_overright_multirange' }, +{ oid => '4270', + proname => 'multirange_union', prorettype => 'anymultirange', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_union' }, +{ oid => '4271', + proname => 'multirange_minus', prorettype => 'anymultirange', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_minus' }, +{ oid => '4272', + proname => 'multirange_intersect', prorettype => 'anymultirange', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_intersect' }, +{ oid => '4273', descr => 'less-equal-greater', + proname => 'multirange_cmp', prorettype => 'int4', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_cmp' }, +{ oid => '4274', + proname => 'multirange_lt', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_lt' }, +{ oid => '4275', + proname => 'multirange_le', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_le' }, +{ oid => '4276', + proname => 'multirange_ge', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_ge' }, +{ oid => '4277', + proname => 'multirange_gt', prorettype => 'bool', + proargtypes => 'anymultirange anymultirange', prosrc => 'multirange_gt' }, +{ oid => '4278', descr => 'hash a multirange', + proname => 'hash_multirange', prorettype => 'int4', + proargtypes => 'anymultirange', prosrc => 'hash_multirange' }, +{ oid => '4279', descr => 'hash a multirange', + proname => 'hash_multirange_extended', prorettype => 'int8', + proargtypes => 'anymultirange int8', prosrc => 'hash_multirange_extended' }, + +{ oid => '4280', descr => 'int4multirange constructor', + proname => 'int4multirange', prorettype => 'int4multirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, +{ oid => '4281', descr => 'int4multirange constructor', + proname => 'int4multirange', prorettype => 'int4multirange', + proargtypes => 'int4range', prosrc => 'multirange_constructor1' }, +{ oid => '4282', descr => 'int4multirange constructor', + proname => 'int4multirange', provariadic => 'int4range', + prorettype => 'int4multirange', proargtypes => '_int4range', + proallargtypes => '{_int4range}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4283', descr => 'nummultirange constructor', + proname => 'nummultirange', prorettype => 'nummultirange', proargtypes => '', + prosrc => 'multirange_constructor0' }, +{ oid => '4284', descr => 'nummultirange constructor', + proname => 'nummultirange', prorettype => 'nummultirange', + proargtypes => 'numrange', prosrc => 'multirange_constructor1' }, +{ oid => '4285', descr => 'nummultirange constructor', + proname => 'nummultirange', provariadic => 'numrange', + prorettype => 'nummultirange', proargtypes => '_numrange', + proallargtypes => '{_numrange}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4286', descr => 'tsmultirange constructor', + proname => 'tsmultirange', prorettype => 'tsmultirange', proargtypes => '', + prosrc => 'multirange_constructor0' }, +{ oid => '4287', descr => 'tsmultirange constructor', + proname => 'tsmultirange', prorettype => 'tsmultirange', + proargtypes => 'tsrange', prosrc => 'multirange_constructor1' }, +{ oid => '4288', descr => 'tsmultirange constructor', + proname => 'tsmultirange', provariadic => 'tsrange', + prorettype => 'tsmultirange', proargtypes => '_tsrange', + proallargtypes => '{_tsrange}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4289', descr => 'tstzmultirange constructor', + proname => 'tstzmultirange', prorettype => 'tstzmultirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, +{ oid => '4290', descr => 'tstzmultirange constructor', + proname => 'tstzmultirange', prorettype => 'tstzmultirange', + proargtypes => 'tstzrange', prosrc => 'multirange_constructor1' }, +{ oid => '4291', descr => 'tstzmultirange constructor', + proname => 'tstzmultirange', provariadic => 'tstzrange', + prorettype => 'tstzmultirange', proargtypes => '_tstzrange', + proallargtypes => '{_tstzrange}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4292', descr => 'datemultirange constructor', + proname => 'datemultirange', prorettype => 'datemultirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, +{ oid => '4293', descr => 'datemultirange constructor', + proname => 'datemultirange', prorettype => 'datemultirange', + proargtypes => 'daterange', prosrc => 'multirange_constructor1' }, +{ oid => '4294', descr => 'datemultirange constructor', + proname => 'datemultirange', provariadic => 'daterange', + prorettype => 'datemultirange', proargtypes => '_daterange', + proallargtypes => '{_daterange}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4295', descr => 'int8multirange constructor', + proname => 'int8multirange', prorettype => 'int8multirange', + proargtypes => '', prosrc => 'multirange_constructor0' }, +{ oid => '4296', descr => 'int8multirange constructor', + proname => 'int8multirange', prorettype => 'int8multirange', + proargtypes => 'int8range', prosrc => 'multirange_constructor1' }, +{ oid => '4297', descr => 'int8multirange constructor', + proname => 'int8multirange', provariadic => 'int8range', + prorettype => 'int8multirange', proargtypes => '_int8range', + proallargtypes => '{_int8range}', proargmodes => '{v}', + prosrc => 'multirange_constructor2' }, +{ oid => '4298', descr => 'anymultirange cast', + proname => 'multirange', prorettype => 'anymultirange', + proargtypes => 'anyrange', prosrc => 'multirange_constructor1' }, +{ oid => '4299', descr => 'aggregate transition function', + proname => 'range_agg_transfn', proisstrict => 'f', prorettype => 'internal', + proargtypes => 'internal anyrange', prosrc => 'range_agg_transfn' }, +{ oid => '4300', descr => 'aggregate final function', + proname => 'range_agg_finalfn', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'internal anyrange', + prosrc => 'range_agg_finalfn' }, +{ oid => '4301', descr => 'combine aggregate input into a multirange', + proname => 'range_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'anyrange', + prosrc => 'aggregate_dummy' }, +{ oid => '6225', descr => 'aggregate transition function', + proname => 'multirange_agg_transfn', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal anymultirange', + prosrc => 'multirange_agg_transfn' }, +{ oid => '6226', descr => 'aggregate final function', + proname => 'multirange_agg_finalfn', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'internal anymultirange', + prosrc => 'range_agg_finalfn' }, +{ oid => '6227', descr => 'combine aggregate input into a multirange', + proname => 'range_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'anymultirange', + prosrc => 'aggregate_dummy' }, +{ oid => '4388', descr => 'range aggregate by intersecting', + proname => 'multirange_intersect_agg_transfn', prorettype => 'anymultirange', + proargtypes => 'anymultirange anymultirange', + prosrc => 'multirange_intersect_agg_transfn' }, +{ oid => '4389', descr => 'range aggregate by intersecting', + proname => 'range_intersect_agg', prokind => 'a', proisstrict => 'f', + prorettype => 'anymultirange', proargtypes => 'anymultirange', + prosrc => 'aggregate_dummy' }, +{ oid => '1293', descr => 'expand multirange to set of ranges', + proname => 'unnest', prorows => '100', proretset => 't', + prorettype => 'anyrange', proargtypes => 'anymultirange', + prosrc => 'multirange_unnest' }, + +# date, time, timestamp constructors +{ oid => '3846', descr => 'construct date', + proname => 'make_date', prorettype => 'date', proargtypes => 'int4 int4 int4', + proargnames => '{year,month,day}', prosrc => 'make_date' }, +{ oid => '3847', descr => 'construct time', + proname => 'make_time', prorettype => 'time', + proargtypes => 'int4 int4 float8', proargnames => '{hour,min,sec}', + prosrc => 'make_time' }, +{ oid => '3461', descr => 'construct timestamp', + proname => 'make_timestamp', prorettype => 'timestamp', + proargtypes => 'int4 int4 int4 int4 int4 float8', + proargnames => '{year,month,mday,hour,min,sec}', prosrc => 'make_timestamp' }, +{ oid => '3462', descr => 'construct timestamp with time zone', + proname => 'make_timestamptz', provolatile => 's', + prorettype => 'timestamptz', proargtypes => 'int4 int4 int4 int4 int4 float8', + proargnames => '{year,month,mday,hour,min,sec}', + prosrc => 'make_timestamptz' }, +{ oid => '3463', descr => 'construct timestamp with time zone', + proname => 'make_timestamptz', provolatile => 's', + prorettype => 'timestamptz', + proargtypes => 'int4 int4 int4 int4 int4 float8 text', + proargnames => '{year,month,mday,hour,min,sec,timezone}', + prosrc => 'make_timestamptz_at_timezone' }, +{ oid => '3464', descr => 'construct interval', + proname => 'make_interval', prorettype => 'interval', + proargtypes => 'int4 int4 int4 int4 int4 int4 float8', + proargnames => '{years,months,weeks,days,hours,mins,secs}', + prosrc => 'make_interval' }, + +# spgist opclasses +{ oid => '4018', descr => 'SP-GiST support for quad tree over point', + proname => 'spg_quad_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_quad_config' }, +{ oid => '4019', descr => 'SP-GiST support for quad tree over point', + proname => 'spg_quad_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_quad_choose' }, +{ oid => '4020', descr => 'SP-GiST support for quad tree over point', + proname => 'spg_quad_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_quad_picksplit' }, +{ oid => '4021', descr => 'SP-GiST support for quad tree over point', + proname => 'spg_quad_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_quad_inner_consistent' }, +{ oid => '4022', + descr => 'SP-GiST support for quad tree and k-d tree over point', + proname => 'spg_quad_leaf_consistent', prorettype => 'bool', + proargtypes => 'internal internal', prosrc => 'spg_quad_leaf_consistent' }, + +{ oid => '4023', descr => 'SP-GiST support for k-d tree over point', + proname => 'spg_kd_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_kd_config' }, +{ oid => '4024', descr => 'SP-GiST support for k-d tree over point', + proname => 'spg_kd_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_kd_choose' }, +{ oid => '4025', descr => 'SP-GiST support for k-d tree over point', + proname => 'spg_kd_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_kd_picksplit' }, +{ oid => '4026', descr => 'SP-GiST support for k-d tree over point', + proname => 'spg_kd_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_kd_inner_consistent' }, + +{ oid => '4027', descr => 'SP-GiST support for radix tree over text', + proname => 'spg_text_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_text_config' }, +{ oid => '4028', descr => 'SP-GiST support for radix tree over text', + proname => 'spg_text_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_text_choose' }, +{ oid => '4029', descr => 'SP-GiST support for radix tree over text', + proname => 'spg_text_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_text_picksplit' }, +{ oid => '4030', descr => 'SP-GiST support for radix tree over text', + proname => 'spg_text_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_text_inner_consistent' }, +{ oid => '4031', descr => 'SP-GiST support for radix tree over text', + proname => 'spg_text_leaf_consistent', prorettype => 'bool', + proargtypes => 'internal internal', prosrc => 'spg_text_leaf_consistent' }, + +{ oid => '3469', descr => 'SP-GiST support for quad tree over range', + proname => 'spg_range_quad_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_range_quad_config' }, +{ oid => '3470', descr => 'SP-GiST support for quad tree over range', + proname => 'spg_range_quad_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_range_quad_choose' }, +{ oid => '3471', descr => 'SP-GiST support for quad tree over range', + proname => 'spg_range_quad_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_range_quad_picksplit' }, +{ oid => '3472', descr => 'SP-GiST support for quad tree over range', + proname => 'spg_range_quad_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', + prosrc => 'spg_range_quad_inner_consistent' }, +{ oid => '3473', descr => 'SP-GiST support for quad tree over range', + proname => 'spg_range_quad_leaf_consistent', prorettype => 'bool', + proargtypes => 'internal internal', + prosrc => 'spg_range_quad_leaf_consistent' }, + +{ oid => '5012', descr => 'SP-GiST support for quad tree over box', + proname => 'spg_box_quad_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_box_quad_config' }, +{ oid => '5013', descr => 'SP-GiST support for quad tree over box', + proname => 'spg_box_quad_choose', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_box_quad_choose' }, +{ oid => '5014', descr => 'SP-GiST support for quad tree over box', + proname => 'spg_box_quad_picksplit', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_box_quad_picksplit' }, +{ oid => '5015', descr => 'SP-GiST support for quad tree over box', + proname => 'spg_box_quad_inner_consistent', prorettype => 'void', + proargtypes => 'internal internal', + prosrc => 'spg_box_quad_inner_consistent' }, +{ oid => '5016', descr => 'SP-GiST support for quad tree over box', + proname => 'spg_box_quad_leaf_consistent', prorettype => 'bool', + proargtypes => 'internal internal', + prosrc => 'spg_box_quad_leaf_consistent' }, + +{ oid => '5010', + descr => 'SP-GiST support for quad tree over 2-D types represented by their bounding boxes', + proname => 'spg_bbox_quad_config', prorettype => 'void', + proargtypes => 'internal internal', prosrc => 'spg_bbox_quad_config' }, +{ oid => '5011', descr => 'SP-GiST support for quad tree over polygons', + proname => 'spg_poly_quad_compress', prorettype => 'box', + proargtypes => 'polygon', prosrc => 'spg_poly_quad_compress' }, + +# replication slots +{ oid => '3779', descr => 'create a physical replication slot', + proname => 'pg_create_physical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name bool bool', + proallargtypes => '{name,bool,bool,name,pg_lsn}', + proargmodes => '{i,i,i,o,o}', + proargnames => '{slot_name,immediately_reserve,temporary,slot_name,lsn}', + prosrc => 'pg_create_physical_replication_slot' }, +{ oid => '4220', + descr => 'copy a physical replication slot, changing temporality', + proname => 'pg_copy_physical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name name bool', + proallargtypes => '{name,name,bool,name,pg_lsn}', + proargmodes => '{i,i,i,o,o}', + proargnames => '{src_slot_name,dst_slot_name,temporary,slot_name,lsn}', + prosrc => 'pg_copy_physical_replication_slot_a' }, +{ oid => '4221', descr => 'copy a physical replication slot', + proname => 'pg_copy_physical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name name', + proallargtypes => '{name,name,name,pg_lsn}', proargmodes => '{i,i,o,o}', + proargnames => '{src_slot_name,dst_slot_name,slot_name,lsn}', + prosrc => 'pg_copy_physical_replication_slot_b' }, +{ oid => '3780', descr => 'drop a replication slot', + proname => 'pg_drop_replication_slot', provolatile => 'v', proparallel => 'u', + prorettype => 'void', proargtypes => 'name', + prosrc => 'pg_drop_replication_slot' }, +{ oid => '3781', + descr => 'information about replication slots currently in use', + proname => 'pg_get_replication_slots', prorows => '10', proisstrict => 'f', + proretset => 't', provolatile => 's', prorettype => 'record', + proargtypes => '', + proallargtypes => '{name,name,text,oid,bool,bool,int4,xid,xid,pg_lsn,pg_lsn,text,int8,bool}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn,wal_status,safe_wal_size,two_phase}', + prosrc => 'pg_get_replication_slots' }, +{ oid => '3786', descr => 'set up a logical replication slot', + proname => 'pg_create_logical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', + proargtypes => 'name name bool bool', + proallargtypes => '{name,name,bool,bool,name,pg_lsn}', + proargmodes => '{i,i,i,i,o,o}', + proargnames => '{slot_name,plugin,temporary,twophase,slot_name,lsn}', + prosrc => 'pg_create_logical_replication_slot' }, +{ oid => '4222', + descr => 'copy a logical replication slot, changing temporality and plugin', + proname => 'pg_copy_logical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', + proargtypes => 'name name bool name', + proallargtypes => '{name,name,bool,name,name,pg_lsn}', + proargmodes => '{i,i,i,i,o,o}', + proargnames => '{src_slot_name,dst_slot_name,temporary,plugin,slot_name,lsn}', + prosrc => 'pg_copy_logical_replication_slot_a' }, +{ oid => '4223', + descr => 'copy a logical replication slot, changing temporality', + proname => 'pg_copy_logical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name name bool', + proallargtypes => '{name,name,bool,name,pg_lsn}', + proargmodes => '{i,i,i,o,o}', + proargnames => '{src_slot_name,dst_slot_name,temporary,slot_name,lsn}', + prosrc => 'pg_copy_logical_replication_slot_b' }, +{ oid => '4224', descr => 'copy a logical replication slot', + proname => 'pg_copy_logical_replication_slot', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name name', + proallargtypes => '{name,name,name,pg_lsn}', proargmodes => '{i,i,o,o}', + proargnames => '{src_slot_name,dst_slot_name,slot_name,lsn}', + prosrc => 'pg_copy_logical_replication_slot_c' }, +{ oid => '3782', descr => 'get changes from replication slot', + proname => 'pg_logical_slot_get_changes', procost => '1000', + prorows => '1000', provariadic => 'text', proisstrict => 'f', + proretset => 't', provolatile => 'v', proparallel => 'u', + prorettype => 'record', proargtypes => 'name pg_lsn int4 _text', + proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,text}', + proargmodes => '{i,i,i,v,o,o,o}', + proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}', + prosrc => 'pg_logical_slot_get_changes' }, +{ oid => '3783', descr => 'get binary changes from replication slot', + proname => 'pg_logical_slot_get_binary_changes', procost => '1000', + prorows => '1000', provariadic => 'text', proisstrict => 'f', + proretset => 't', provolatile => 'v', proparallel => 'u', + prorettype => 'record', proargtypes => 'name pg_lsn int4 _text', + proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,bytea}', + proargmodes => '{i,i,i,v,o,o,o}', + proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}', + prosrc => 'pg_logical_slot_get_binary_changes' }, +{ oid => '3784', descr => 'peek at changes from replication slot', + proname => 'pg_logical_slot_peek_changes', procost => '1000', + prorows => '1000', provariadic => 'text', proisstrict => 'f', + proretset => 't', provolatile => 'v', proparallel => 'u', + prorettype => 'record', proargtypes => 'name pg_lsn int4 _text', + proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,text}', + proargmodes => '{i,i,i,v,o,o,o}', + proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}', + prosrc => 'pg_logical_slot_peek_changes' }, +{ oid => '3785', descr => 'peek at binary changes from replication slot', + proname => 'pg_logical_slot_peek_binary_changes', procost => '1000', + prorows => '1000', provariadic => 'text', proisstrict => 'f', + proretset => 't', provolatile => 'v', proparallel => 'u', + prorettype => 'record', proargtypes => 'name pg_lsn int4 _text', + proallargtypes => '{name,pg_lsn,int4,_text,pg_lsn,xid,bytea}', + proargmodes => '{i,i,i,v,o,o,o}', + proargnames => '{slot_name,upto_lsn,upto_nchanges,options,lsn,xid,data}', + prosrc => 'pg_logical_slot_peek_binary_changes' }, +{ oid => '3878', descr => 'advance logical replication slot', + proname => 'pg_replication_slot_advance', provolatile => 'v', + proparallel => 'u', prorettype => 'record', proargtypes => 'name pg_lsn', + proallargtypes => '{name,pg_lsn,name,pg_lsn}', proargmodes => '{i,i,o,o}', + proargnames => '{slot_name,upto_lsn,slot_name,end_lsn}', + prosrc => 'pg_replication_slot_advance' }, +{ oid => '3577', descr => 'emit a textual logical decoding message', + proname => 'pg_logical_emit_message', provolatile => 'v', proparallel => 'u', + prorettype => 'pg_lsn', proargtypes => 'bool text text', + prosrc => 'pg_logical_emit_message_text' }, +{ oid => '3578', descr => 'emit a binary logical decoding message', + proname => 'pg_logical_emit_message', provolatile => 'v', proparallel => 'u', + prorettype => 'pg_lsn', proargtypes => 'bool text bytea', + prosrc => 'pg_logical_emit_message_bytea' }, + +# event triggers +{ oid => '3566', descr => 'list objects dropped by the current command', + proname => 'pg_event_trigger_dropped_objects', procost => '10', + prorows => '100', proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{oid,oid,int4,bool,bool,bool,text,text,text,text,_text,_text}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{classid, objid, objsubid, original, normal, is_temporary, object_type, schema_name, object_name, object_identity, address_names, address_args}', + prosrc => 'pg_event_trigger_dropped_objects' }, +{ oid => '4566', descr => 'return Oid of the table getting rewritten', + proname => 'pg_event_trigger_table_rewrite_oid', provolatile => 's', + proparallel => 'r', prorettype => 'oid', proargtypes => '', + proallargtypes => '{oid}', proargmodes => '{o}', proargnames => '{oid}', + prosrc => 'pg_event_trigger_table_rewrite_oid' }, +{ oid => '4567', descr => 'return reason code for table getting rewritten', + proname => 'pg_event_trigger_table_rewrite_reason', provolatile => 's', + proparallel => 'r', prorettype => 'int4', proargtypes => '', + prosrc => 'pg_event_trigger_table_rewrite_reason' }, +{ oid => '4568', + descr => 'list DDL actions being executed by the current command', + proname => 'pg_event_trigger_ddl_commands', procost => '10', prorows => '100', + proretset => 't', provolatile => 's', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{oid,oid,int4,text,text,text,text,bool,pg_ddl_command}', + proargmodes => '{o,o,o,o,o,o,o,o,o}', + proargnames => '{classid, objid, objsubid, command_tag, object_type, schema_name, object_identity, in_extension, command}', + prosrc => 'pg_event_trigger_ddl_commands' }, + +# generic transition functions for ordered-set aggregates +{ oid => '3970', descr => 'aggregate transition function', + proname => 'ordered_set_transition', proisstrict => 'f', + prorettype => 'internal', proargtypes => 'internal any', + prosrc => 'ordered_set_transition' }, +{ oid => '3971', descr => 'aggregate transition function', + proname => 'ordered_set_transition_multi', provariadic => 'any', + proisstrict => 'f', prorettype => 'internal', proargtypes => 'internal any', + proallargtypes => '{internal,any}', proargmodes => '{i,v}', + prosrc => 'ordered_set_transition_multi' }, + +# inverse distribution aggregates (and their support functions) +{ oid => '3972', descr => 'discrete percentile', + proname => 'percentile_disc', prokind => 'a', proisstrict => 'f', + prorettype => 'anyelement', proargtypes => 'float8 anyelement', + prosrc => 'aggregate_dummy' }, +{ oid => '3973', descr => 'aggregate final function', + proname => 'percentile_disc_final', proisstrict => 'f', + prorettype => 'anyelement', proargtypes => 'internal float8 anyelement', + prosrc => 'percentile_disc_final' }, +{ oid => '3974', descr => 'continuous distribution percentile', + proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '3975', descr => 'aggregate final function', + proname => 'percentile_cont_float8_final', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'internal float8', + prosrc => 'percentile_cont_float8_final' }, +{ oid => '3976', descr => 'continuous distribution percentile', + proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'float8 interval', + prosrc => 'aggregate_dummy' }, +{ oid => '3977', descr => 'aggregate final function', + proname => 'percentile_cont_interval_final', proisstrict => 'f', + prorettype => 'interval', proargtypes => 'internal float8', + prosrc => 'percentile_cont_interval_final' }, +{ oid => '3978', descr => 'multiple discrete percentiles', + proname => 'percentile_disc', prokind => 'a', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => '_float8 anyelement', + prosrc => 'aggregate_dummy' }, +{ oid => '3979', descr => 'aggregate final function', + proname => 'percentile_disc_multi_final', proisstrict => 'f', + prorettype => 'anyarray', proargtypes => 'internal _float8 anyelement', + prosrc => 'percentile_disc_multi_final' }, +{ oid => '3980', descr => 'multiple continuous percentiles', + proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + prorettype => '_float8', proargtypes => '_float8 float8', + prosrc => 'aggregate_dummy' }, +{ oid => '3981', descr => 'aggregate final function', + proname => 'percentile_cont_float8_multi_final', proisstrict => 'f', + prorettype => '_float8', proargtypes => 'internal _float8', + prosrc => 'percentile_cont_float8_multi_final' }, +{ oid => '3982', descr => 'multiple continuous percentiles', + proname => 'percentile_cont', prokind => 'a', proisstrict => 'f', + prorettype => '_interval', proargtypes => '_float8 interval', + prosrc => 'aggregate_dummy' }, +{ oid => '3983', descr => 'aggregate final function', + proname => 'percentile_cont_interval_multi_final', proisstrict => 'f', + prorettype => '_interval', proargtypes => 'internal _float8', + prosrc => 'percentile_cont_interval_multi_final' }, +{ oid => '3984', descr => 'most common value', + proname => 'mode', prokind => 'a', proisstrict => 'f', + prorettype => 'anyelement', proargtypes => 'anyelement', + prosrc => 'aggregate_dummy' }, +{ oid => '3985', descr => 'aggregate final function', + proname => 'mode_final', proisstrict => 'f', prorettype => 'anyelement', + proargtypes => 'internal anyelement', prosrc => 'mode_final' }, + +# hypothetical-set aggregates (and their support functions) +{ oid => '3986', descr => 'rank of hypothetical row', + proname => 'rank', provariadic => 'any', prokind => 'a', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'any', proallargtypes => '{any}', + proargmodes => '{v}', prosrc => 'aggregate_dummy' }, +{ oid => '3987', descr => 'aggregate final function', + proname => 'rank_final', provariadic => 'any', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'internal any', + proallargtypes => '{internal,any}', proargmodes => '{i,v}', + prosrc => 'hypothetical_rank_final' }, +{ oid => '3988', descr => 'fractional rank of hypothetical row', + proname => 'percent_rank', provariadic => 'any', prokind => 'a', + proisstrict => 'f', prorettype => 'float8', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'aggregate_dummy' }, +{ oid => '3989', descr => 'aggregate final function', + proname => 'percent_rank_final', provariadic => 'any', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'internal any', + proallargtypes => '{internal,any}', proargmodes => '{i,v}', + prosrc => 'hypothetical_percent_rank_final' }, +{ oid => '3990', descr => 'cumulative distribution of hypothetical row', + proname => 'cume_dist', provariadic => 'any', prokind => 'a', + proisstrict => 'f', prorettype => 'float8', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'aggregate_dummy' }, +{ oid => '3991', descr => 'aggregate final function', + proname => 'cume_dist_final', provariadic => 'any', proisstrict => 'f', + prorettype => 'float8', proargtypes => 'internal any', + proallargtypes => '{internal,any}', proargmodes => '{i,v}', + prosrc => 'hypothetical_cume_dist_final' }, +{ oid => '3992', descr => 'rank of hypothetical row without gaps', + proname => 'dense_rank', provariadic => 'any', prokind => 'a', + proisstrict => 'f', prorettype => 'int8', proargtypes => 'any', + proallargtypes => '{any}', proargmodes => '{v}', + prosrc => 'aggregate_dummy' }, +{ oid => '3993', descr => 'aggregate final function', + proname => 'dense_rank_final', provariadic => 'any', proisstrict => 'f', + prorettype => 'int8', proargtypes => 'internal any', + proallargtypes => '{internal,any}', proargmodes => '{i,v}', + prosrc => 'hypothetical_dense_rank_final' }, + +# pg_upgrade support +{ oid => '3582', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_pg_type_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_pg_type_oid' }, +{ oid => '3584', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_array_pg_type_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_array_pg_type_oid' }, +{ oid => '4390', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_multirange_pg_type_oid', + provolatile => 'v', proparallel => 'r', prorettype => 'void', + proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_multirange_pg_type_oid' }, +{ oid => '4391', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_multirange_array_pg_type_oid', + provolatile => 'v', proparallel => 'r', prorettype => 'void', + proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_multirange_array_pg_type_oid' }, +{ oid => '3586', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_heap_pg_class_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_heap_pg_class_oid' }, +{ oid => '3587', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_index_pg_class_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_index_pg_class_oid' }, +{ oid => '3588', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_toast_pg_class_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_toast_pg_class_oid' }, +{ oid => '3589', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_pg_enum_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_pg_enum_oid' }, +{ oid => '3590', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_pg_authid_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_pg_authid_oid' }, +{ oid => '3591', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_create_empty_extension', proisstrict => 'f', + provolatile => 'v', proparallel => 'u', prorettype => 'void', + proargtypes => 'text text bool text _oid _text _text', + prosrc => 'binary_upgrade_create_empty_extension' }, +{ oid => '4083', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_record_init_privs', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'bool', + prosrc => 'binary_upgrade_set_record_init_privs' }, +{ oid => '4101', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_missing_value', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'oid text text', + prosrc => 'binary_upgrade_set_missing_value' }, +{ oid => '4545', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_heap_relfilenode', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_heap_relfilenode' }, +{ oid => '4546', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_index_relfilenode', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_index_relfilenode' }, +{ oid => '4547', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_toast_relfilenode', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_toast_relfilenode' }, +{ oid => '4548', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_pg_tablespace_oid', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_pg_tablespace_oid' }, + +# conversion functions +{ oid => '4302', + descr => 'internal conversion function for KOI8R to MULE_INTERNAL', + proname => 'koi8r_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8r_to_mic', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4303', + descr => 'internal conversion function for MULE_INTERNAL to KOI8R', + proname => 'mic_to_koi8r', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_koi8r', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4304', + descr => 'internal conversion function for ISO-8859-5 to MULE_INTERNAL', + proname => 'iso_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', prosrc => 'iso_to_mic', + probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4305', + descr => 'internal conversion function for MULE_INTERNAL to ISO-8859-5', + proname => 'mic_to_iso', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', prosrc => 'mic_to_iso', + probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4306', + descr => 'internal conversion function for WIN1251 to MULE_INTERNAL', + proname => 'win1251_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1251_to_mic', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4307', + descr => 'internal conversion function for MULE_INTERNAL to WIN1251', + proname => 'mic_to_win1251', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_win1251', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4308', + descr => 'internal conversion function for WIN866 to MULE_INTERNAL', + proname => 'win866_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win866_to_mic', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4309', + descr => 'internal conversion function for MULE_INTERNAL to WIN866', + proname => 'mic_to_win866', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_win866', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4310', descr => 'internal conversion function for KOI8R to WIN1251', + proname => 'koi8r_to_win1251', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8r_to_win1251', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4311', descr => 'internal conversion function for WIN1251 to KOI8R', + proname => 'win1251_to_koi8r', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1251_to_koi8r', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4312', descr => 'internal conversion function for KOI8R to WIN866', + proname => 'koi8r_to_win866', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8r_to_win866', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4313', descr => 'internal conversion function for WIN866 to KOI8R', + proname => 'win866_to_koi8r', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win866_to_koi8r', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4314', + descr => 'internal conversion function for WIN866 to WIN1251', + proname => 'win866_to_win1251', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win866_to_win1251', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4315', + descr => 'internal conversion function for WIN1251 to WIN866', + proname => 'win1251_to_win866', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1251_to_win866', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4316', + descr => 'internal conversion function for ISO-8859-5 to KOI8R', + proname => 'iso_to_koi8r', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'iso_to_koi8r', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4317', + descr => 'internal conversion function for KOI8R to ISO-8859-5', + proname => 'koi8r_to_iso', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8r_to_iso', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4318', + descr => 'internal conversion function for ISO-8859-5 to WIN1251', + proname => 'iso_to_win1251', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'iso_to_win1251', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4319', + descr => 'internal conversion function for WIN1251 to ISO-8859-5', + proname => 'win1251_to_iso', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1251_to_iso', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4320', + descr => 'internal conversion function for ISO-8859-5 to WIN866', + proname => 'iso_to_win866', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'iso_to_win866', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4321', + descr => 'internal conversion function for WIN866 to ISO-8859-5', + proname => 'win866_to_iso', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win866_to_iso', probin => '$libdir/cyrillic_and_mic' }, +{ oid => '4322', + descr => 'internal conversion function for EUC_CN to MULE_INTERNAL', + proname => 'euc_cn_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_cn_to_mic', probin => '$libdir/euc_cn_and_mic' }, +{ oid => '4323', + descr => 'internal conversion function for MULE_INTERNAL to EUC_CN', + proname => 'mic_to_euc_cn', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_euc_cn', probin => '$libdir/euc_cn_and_mic' }, +{ oid => '4324', descr => 'internal conversion function for EUC_JP to SJIS', + proname => 'euc_jp_to_sjis', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_jp_to_sjis', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4325', descr => 'internal conversion function for SJIS to EUC_JP', + proname => 'sjis_to_euc_jp', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'sjis_to_euc_jp', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4326', + descr => 'internal conversion function for EUC_JP to MULE_INTERNAL', + proname => 'euc_jp_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_jp_to_mic', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4327', + descr => 'internal conversion function for SJIS to MULE_INTERNAL', + proname => 'sjis_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'sjis_to_mic', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4328', + descr => 'internal conversion function for MULE_INTERNAL to EUC_JP', + proname => 'mic_to_euc_jp', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_euc_jp', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4329', + descr => 'internal conversion function for MULE_INTERNAL to SJIS', + proname => 'mic_to_sjis', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_sjis', probin => '$libdir/euc_jp_and_sjis' }, +{ oid => '4330', + descr => 'internal conversion function for EUC_KR to MULE_INTERNAL', + proname => 'euc_kr_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_kr_to_mic', probin => '$libdir/euc_kr_and_mic' }, +{ oid => '4331', + descr => 'internal conversion function for MULE_INTERNAL to EUC_KR', + proname => 'mic_to_euc_kr', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_euc_kr', probin => '$libdir/euc_kr_and_mic' }, +{ oid => '4332', descr => 'internal conversion function for EUC_TW to BIG5', + proname => 'euc_tw_to_big5', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_tw_to_big5', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4333', descr => 'internal conversion function for BIG5 to EUC_TW', + proname => 'big5_to_euc_tw', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'big5_to_euc_tw', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4334', + descr => 'internal conversion function for EUC_TW to MULE_INTERNAL', + proname => 'euc_tw_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_tw_to_mic', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4335', + descr => 'internal conversion function for BIG5 to MULE_INTERNAL', + proname => 'big5_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'big5_to_mic', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4336', + descr => 'internal conversion function for MULE_INTERNAL to EUC_TW', + proname => 'mic_to_euc_tw', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_euc_tw', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4337', + descr => 'internal conversion function for MULE_INTERNAL to BIG5', + proname => 'mic_to_big5', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_big5', probin => '$libdir/euc_tw_and_big5' }, +{ oid => '4338', + descr => 'internal conversion function for LATIN2 to MULE_INTERNAL', + proname => 'latin2_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'latin2_to_mic', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4339', + descr => 'internal conversion function for MULE_INTERNAL to LATIN2', + proname => 'mic_to_latin2', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_latin2', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4340', + descr => 'internal conversion function for WIN1250 to MULE_INTERNAL', + proname => 'win1250_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1250_to_mic', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4341', + descr => 'internal conversion function for MULE_INTERNAL to WIN1250', + proname => 'mic_to_win1250', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_win1250', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4342', + descr => 'internal conversion function for LATIN2 to WIN1250', + proname => 'latin2_to_win1250', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'latin2_to_win1250', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4343', + descr => 'internal conversion function for WIN1250 to LATIN2', + proname => 'win1250_to_latin2', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win1250_to_latin2', probin => '$libdir/latin2_and_win1250' }, +{ oid => '4344', + descr => 'internal conversion function for LATIN1 to MULE_INTERNAL', + proname => 'latin1_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'latin1_to_mic', probin => '$libdir/latin_and_mic' }, +{ oid => '4345', + descr => 'internal conversion function for MULE_INTERNAL to LATIN1', + proname => 'mic_to_latin1', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_latin1', probin => '$libdir/latin_and_mic' }, +{ oid => '4346', + descr => 'internal conversion function for LATIN3 to MULE_INTERNAL', + proname => 'latin3_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'latin3_to_mic', probin => '$libdir/latin_and_mic' }, +{ oid => '4347', + descr => 'internal conversion function for MULE_INTERNAL to LATIN3', + proname => 'mic_to_latin3', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_latin3', probin => '$libdir/latin_and_mic' }, +{ oid => '4348', + descr => 'internal conversion function for LATIN4 to MULE_INTERNAL', + proname => 'latin4_to_mic', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'latin4_to_mic', probin => '$libdir/latin_and_mic' }, +{ oid => '4349', + descr => 'internal conversion function for MULE_INTERNAL to LATIN4', + proname => 'mic_to_latin4', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'mic_to_latin4', probin => '$libdir/latin_and_mic' }, +{ oid => '4352', descr => 'internal conversion function for BIG5 to UTF8', + proname => 'big5_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'big5_to_utf8', probin => '$libdir/utf8_and_big5' }, +{ oid => '4353', descr => 'internal conversion function for UTF8 to BIG5', + proname => 'utf8_to_big5', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_big5', probin => '$libdir/utf8_and_big5' }, +{ oid => '4354', descr => 'internal conversion function for UTF8 to KOI8R', + proname => 'utf8_to_koi8r', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_koi8r', probin => '$libdir/utf8_and_cyrillic' }, +{ oid => '4355', descr => 'internal conversion function for KOI8R to UTF8', + proname => 'koi8r_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8r_to_utf8', probin => '$libdir/utf8_and_cyrillic' }, +{ oid => '4356', descr => 'internal conversion function for UTF8 to KOI8U', + proname => 'utf8_to_koi8u', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_koi8u', probin => '$libdir/utf8_and_cyrillic' }, +{ oid => '4357', descr => 'internal conversion function for KOI8U to UTF8', + proname => 'koi8u_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'koi8u_to_utf8', probin => '$libdir/utf8_and_cyrillic' }, +{ oid => '4358', descr => 'internal conversion function for UTF8 to WIN', + proname => 'utf8_to_win', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_win', probin => '$libdir/utf8_and_win' }, +{ oid => '4359', descr => 'internal conversion function for WIN to UTF8', + proname => 'win_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'win_to_utf8', probin => '$libdir/utf8_and_win' }, +{ oid => '4360', descr => 'internal conversion function for EUC_CN to UTF8', + proname => 'euc_cn_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_cn_to_utf8', probin => '$libdir/utf8_and_euc_cn' }, +{ oid => '4361', descr => 'internal conversion function for UTF8 to EUC_CN', + proname => 'utf8_to_euc_cn', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_euc_cn', probin => '$libdir/utf8_and_euc_cn' }, +{ oid => '4362', descr => 'internal conversion function for EUC_JP to UTF8', + proname => 'euc_jp_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_jp_to_utf8', probin => '$libdir/utf8_and_euc_jp' }, +{ oid => '4363', descr => 'internal conversion function for UTF8 to EUC_JP', + proname => 'utf8_to_euc_jp', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_euc_jp', probin => '$libdir/utf8_and_euc_jp' }, +{ oid => '4364', descr => 'internal conversion function for EUC_KR to UTF8', + proname => 'euc_kr_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_kr_to_utf8', probin => '$libdir/utf8_and_euc_kr' }, +{ oid => '4365', descr => 'internal conversion function for UTF8 to EUC_KR', + proname => 'utf8_to_euc_kr', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_euc_kr', probin => '$libdir/utf8_and_euc_kr' }, +{ oid => '4366', descr => 'internal conversion function for EUC_TW to UTF8', + proname => 'euc_tw_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_tw_to_utf8', probin => '$libdir/utf8_and_euc_tw' }, +{ oid => '4367', descr => 'internal conversion function for UTF8 to EUC_TW', + proname => 'utf8_to_euc_tw', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_euc_tw', probin => '$libdir/utf8_and_euc_tw' }, +{ oid => '4368', descr => 'internal conversion function for GB18030 to UTF8', + proname => 'gb18030_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'gb18030_to_utf8', probin => '$libdir/utf8_and_gb18030' }, +{ oid => '4369', descr => 'internal conversion function for UTF8 to GB18030', + proname => 'utf8_to_gb18030', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_gb18030', probin => '$libdir/utf8_and_gb18030' }, +{ oid => '4370', descr => 'internal conversion function for GBK to UTF8', + proname => 'gbk_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'gbk_to_utf8', probin => '$libdir/utf8_and_gbk' }, +{ oid => '4371', descr => 'internal conversion function for UTF8 to GBK', + proname => 'utf8_to_gbk', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_gbk', probin => '$libdir/utf8_and_gbk' }, +{ oid => '4372', + descr => 'internal conversion function for UTF8 to ISO-8859 2-16', + proname => 'utf8_to_iso8859', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_iso8859', probin => '$libdir/utf8_and_iso8859' }, +{ oid => '4373', + descr => 'internal conversion function for ISO-8859 2-16 to UTF8', + proname => 'iso8859_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'iso8859_to_utf8', probin => '$libdir/utf8_and_iso8859' }, +{ oid => '4374', descr => 'internal conversion function for LATIN1 to UTF8', + proname => 'iso8859_1_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'iso8859_1_to_utf8', probin => '$libdir/utf8_and_iso8859_1' }, +{ oid => '4375', descr => 'internal conversion function for UTF8 to LATIN1', + proname => 'utf8_to_iso8859_1', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_iso8859_1', probin => '$libdir/utf8_and_iso8859_1' }, +{ oid => '4376', descr => 'internal conversion function for JOHAB to UTF8', + proname => 'johab_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'johab_to_utf8', probin => '$libdir/utf8_and_johab' }, +{ oid => '4377', descr => 'internal conversion function for UTF8 to JOHAB', + proname => 'utf8_to_johab', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_johab', probin => '$libdir/utf8_and_johab' }, +{ oid => '4378', descr => 'internal conversion function for SJIS to UTF8', + proname => 'sjis_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'sjis_to_utf8', probin => '$libdir/utf8_and_sjis' }, +{ oid => '4379', descr => 'internal conversion function for UTF8 to SJIS', + proname => 'utf8_to_sjis', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_sjis', probin => '$libdir/utf8_and_sjis' }, +{ oid => '4380', descr => 'internal conversion function for UHC to UTF8', + proname => 'uhc_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'uhc_to_utf8', probin => '$libdir/utf8_and_uhc' }, +{ oid => '4381', descr => 'internal conversion function for UTF8 to UHC', + proname => 'utf8_to_uhc', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_uhc', probin => '$libdir/utf8_and_uhc' }, +{ oid => '4382', + descr => 'internal conversion function for EUC_JIS_2004 to UTF8', + proname => 'euc_jis_2004_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_jis_2004_to_utf8', probin => '$libdir/utf8_and_euc2004' }, +{ oid => '4383', + descr => 'internal conversion function for UTF8 to EUC_JIS_2004', + proname => 'utf8_to_euc_jis_2004', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_euc_jis_2004', probin => '$libdir/utf8_and_euc2004' }, +{ oid => '4384', + descr => 'internal conversion function for SHIFT_JIS_2004 to UTF8', + proname => 'shift_jis_2004_to_utf8', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'shift_jis_2004_to_utf8', probin => '$libdir/utf8_and_sjis2004' }, +{ oid => '4385', + descr => 'internal conversion function for UTF8 to SHIFT_JIS_2004', + proname => 'utf8_to_shift_jis_2004', prolang => 'c', prorettype => 'int4', + proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'utf8_to_shift_jis_2004', probin => '$libdir/utf8_and_sjis2004' }, +{ oid => '4386', + descr => 'internal conversion function for EUC_JIS_2004 to SHIFT_JIS_2004', + proname => 'euc_jis_2004_to_shift_jis_2004', prolang => 'c', + prorettype => 'int4', proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'euc_jis_2004_to_shift_jis_2004', + probin => '$libdir/euc2004_sjis2004' }, +{ oid => '4387', + descr => 'internal conversion function for SHIFT_JIS_2004 to EUC_JIS_2004', + proname => 'shift_jis_2004_to_euc_jis_2004', prolang => 'c', + prorettype => 'int4', proargtypes => 'int4 int4 cstring internal int4 bool', + prosrc => 'shift_jis_2004_to_euc_jis_2004', + probin => '$libdir/euc2004_sjis2004' }, + +{ oid => '5040', + descr => 'restriction selectivity for generic matching operators', + proname => 'matchingsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int4', prosrc => 'matchingsel' }, +{ oid => '5041', descr => 'join selectivity for generic matching operators', + proname => 'matchingjoinsel', provolatile => 's', prorettype => 'float8', + proargtypes => 'internal oid internal int2 internal', + prosrc => 'matchingjoinsel' }, + +# replication/origin.h +{ oid => '6003', descr => 'create a replication origin', + proname => 'pg_replication_origin_create', provolatile => 'v', + proparallel => 'u', prorettype => 'oid', proargtypes => 'text', + prosrc => 'pg_replication_origin_create' }, + +{ oid => '6004', descr => 'drop replication origin identified by its name', + proname => 'pg_replication_origin_drop', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'text', + prosrc => 'pg_replication_origin_drop' }, + +{ oid => '6005', + descr => 'translate the replication origin\'s name to its id', + proname => 'pg_replication_origin_oid', provolatile => 's', + prorettype => 'oid', proargtypes => 'text', + prosrc => 'pg_replication_origin_oid' }, + +{ oid => '6006', + descr => 'configure session to maintain replication progress tracking for the passed in origin', + proname => 'pg_replication_origin_session_setup', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'text', + prosrc => 'pg_replication_origin_session_setup' }, + +{ oid => '6007', descr => 'teardown configured replication progress tracking', + proname => 'pg_replication_origin_session_reset', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => '', + prosrc => 'pg_replication_origin_session_reset' }, + +{ oid => '6008', + descr => 'is a replication origin configured in this session', + proname => 'pg_replication_origin_session_is_setup', provolatile => 'v', + proparallel => 'r', prorettype => 'bool', proargtypes => '', + prosrc => 'pg_replication_origin_session_is_setup' }, + +{ oid => '6009', + descr => 'get the replication progress of the current session', + proname => 'pg_replication_origin_session_progress', provolatile => 'v', + proparallel => 'u', prorettype => 'pg_lsn', proargtypes => 'bool', + prosrc => 'pg_replication_origin_session_progress' }, + +{ oid => '6010', descr => 'setup the transaction\'s origin lsn and timestamp', + proname => 'pg_replication_origin_xact_setup', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'pg_lsn timestamptz', + prosrc => 'pg_replication_origin_xact_setup' }, + +{ oid => '6011', descr => 'reset the transaction\'s origin lsn and timestamp', + proname => 'pg_replication_origin_xact_reset', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => '', + prosrc => 'pg_replication_origin_xact_reset' }, + +{ oid => '6012', descr => 'advance replication origin to specific location', + proname => 'pg_replication_origin_advance', provolatile => 'v', + proparallel => 'u', prorettype => 'void', proargtypes => 'text pg_lsn', + prosrc => 'pg_replication_origin_advance' }, + +{ oid => '6013', + descr => 'get an individual replication origin\'s replication progress', + proname => 'pg_replication_origin_progress', provolatile => 'v', + proparallel => 'u', prorettype => 'pg_lsn', proargtypes => 'text bool', + prosrc => 'pg_replication_origin_progress' }, + +{ oid => '6014', descr => 'get progress for all replication origins', + proname => 'pg_show_replication_origin_status', prorows => '100', + proisstrict => 'f', proretset => 't', provolatile => 'v', proparallel => 'r', + prorettype => 'record', proargtypes => '', + proallargtypes => '{oid,text,pg_lsn,pg_lsn}', proargmodes => '{o,o,o,o}', + proargnames => '{local_id, external_id, remote_lsn, local_lsn}', + prosrc => 'pg_show_replication_origin_status' }, + +# publications +{ oid => '6119', descr => 'get information of tables in a publication', + proname => 'pg_get_publication_tables', prorows => '1000', proretset => 't', + provolatile => 's', prorettype => 'record', proargtypes => 'text', + proallargtypes => '{text,oid,int2vector,pg_node_tree}', + proargmodes => '{i,o,o,o}', proargnames => '{pubname,relid,attrs,qual}', + prosrc => 'pg_get_publication_tables' }, +{ oid => '6121', + descr => 'returns whether a relation can be part of a publication', + proname => 'pg_relation_is_publishable', provolatile => 's', + prorettype => 'bool', proargtypes => 'regclass', + prosrc => 'pg_relation_is_publishable' }, + +# rls +{ oid => '3298', + descr => 'row security for current context active on table by table oid', + proname => 'row_security_active', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid', prosrc => 'row_security_active' }, +{ oid => '3299', + descr => 'row security for current context active on table by table name', + proname => 'row_security_active', provolatile => 's', prorettype => 'bool', + proargtypes => 'text', prosrc => 'row_security_active_name' }, + +# pg_config +{ oid => '3400', descr => 'pg_config binary as a function', + proname => 'pg_config', prorows => '23', proretset => 't', provolatile => 's', + proparallel => 'r', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,text}', proargmodes => '{o,o}', + proargnames => '{name,setting}', prosrc => 'pg_config' }, + +# pg_controldata related functions +{ oid => '3441', + descr => 'pg_controldata general state information as a function', + proname => 'pg_control_system', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{int4,int4,int8,timestamptz}', + proargmodes => '{o,o,o,o}', + proargnames => '{pg_control_version,catalog_version_no,system_identifier,pg_control_last_modified}', + prosrc => 'pg_control_system' }, + +{ oid => '3442', + descr => 'pg_controldata checkpoint state information as a function', + proname => 'pg_control_checkpoint', provolatile => 'v', + prorettype => 'record', proargtypes => '', + proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}', + prosrc => 'pg_control_checkpoint' }, + +{ oid => '3443', + descr => 'pg_controldata recovery state information as a function', + proname => 'pg_control_recovery', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{pg_lsn,int4,pg_lsn,pg_lsn,bool}', + proargmodes => '{o,o,o,o,o}', + proargnames => '{min_recovery_end_lsn,min_recovery_end_timeline,backup_start_lsn,backup_end_lsn,end_of_backup_record_required}', + prosrc => 'pg_control_recovery' }, + +{ oid => '3444', + descr => 'pg_controldata init state information as a function', + proname => 'pg_control_init', provolatile => 'v', prorettype => 'record', + proargtypes => '', + proallargtypes => '{int4,int4,int4,int4,int4,int4,int4,int4,int4,bool,int4}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version}', + prosrc => 'pg_control_init' }, + +# subscripting support for built-in types +{ oid => '6179', descr => 'standard array subscripting support', + proname => 'array_subscript_handler', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'array_subscript_handler' }, +{ oid => '6180', descr => 'raw array subscripting support', + proname => 'raw_array_subscript_handler', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'raw_array_subscript_handler' }, +# type subscripting support +{ oid => '6098', descr => 'jsonb subscripting logic', + proname => 'jsonb_subscript_handler', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'jsonb_subscript_handler' }, + +# collation management functions +{ oid => '3445', descr => 'import collations from operating system', + proname => 'pg_import_system_collations', procost => '100', + provolatile => 'v', proparallel => 'u', prorettype => 'int4', + proargtypes => 'regnamespace', prosrc => 'pg_import_system_collations' }, + +{ oid => '3448', + descr => 'get actual version of collation from operating system', + proname => 'pg_collation_actual_version', procost => '100', + provolatile => 'v', prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_collation_actual_version' }, +{ oid => '6249', + descr => 'get actual version of database collation from operating system', + proname => 'pg_database_collation_actual_version', procost => '100', + provolatile => 'v', prorettype => 'text', proargtypes => 'oid', + prosrc => 'pg_database_collation_actual_version' }, + +# system management/monitoring related functions +{ oid => '3353', descr => 'list files in the log directory', + proname => 'pg_ls_logdir', procost => '10', prorows => '20', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8,timestamptz}', proargmodes => '{o,o,o}', + proargnames => '{name,size,modification}', prosrc => 'pg_ls_logdir' }, +{ oid => '3354', descr => 'list of files in the WAL directory', + proname => 'pg_ls_waldir', procost => '10', prorows => '20', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8,timestamptz}', proargmodes => '{o,o,o}', + proargnames => '{name,size,modification}', prosrc => 'pg_ls_waldir' }, +{ oid => '5031', descr => 'list of files in the archive_status directory', + proname => 'pg_ls_archive_statusdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,int8,timestamptz}', + proargmodes => '{o,o,o}', proargnames => '{name,size,modification}', + prosrc => 'pg_ls_archive_statusdir' }, +{ oid => '5029', descr => 'list files in the pgsql_tmp directory', + proname => 'pg_ls_tmpdir', procost => '10', prorows => '20', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => '', + proallargtypes => '{text,int8,timestamptz}', proargmodes => '{o,o,o}', + proargnames => '{name,size,modification}', prosrc => 'pg_ls_tmpdir_noargs' }, +{ oid => '5030', descr => 'list files in the pgsql_tmp directory', + proname => 'pg_ls_tmpdir', procost => '10', prorows => '20', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => 'oid', + proallargtypes => '{oid,text,int8,timestamptz}', proargmodes => '{i,o,o,o}', + proargnames => '{tablespace,name,size,modification}', + prosrc => 'pg_ls_tmpdir_1arg' }, +{ oid => '6270', + descr => 'list of files in the pg_logical/snapshots directory', + proname => 'pg_ls_logicalsnapdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,int8,timestamptz}', + proargmodes => '{o,o,o}', proargnames => '{name,size,modification}', + prosrc => 'pg_ls_logicalsnapdir' }, +{ oid => '6271', + descr => 'list of files in the pg_logical/mappings directory', + proname => 'pg_ls_logicalmapdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,int8,timestamptz}', + proargmodes => '{o,o,o}', proargnames => '{name,size,modification}', + prosrc => 'pg_ls_logicalmapdir' }, +{ oid => '6272', + descr => 'list of files in the pg_replslot/slot_name directory', + proname => 'pg_ls_replslotdir', procost => '10', prorows => '20', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => 'text', proallargtypes => '{text,text,int8,timestamptz}', + proargmodes => '{i,o,o,o}', + proargnames => '{slot_name,name,size,modification}', + prosrc => 'pg_ls_replslotdir' }, + +# hash partitioning constraint function +{ oid => '5028', descr => 'hash partition CHECK constraint', + proname => 'satisfies_hash_partition', provariadic => 'any', + proisstrict => 'f', prorettype => 'bool', proargtypes => 'oid int4 int4 any', + proargmodes => '{i,i,i,v}', prosrc => 'satisfies_hash_partition' }, + +# information about a partition tree +{ oid => '3423', descr => 'view partition tree tables', + proname => 'pg_partition_tree', prorows => '1000', proretset => 't', + provolatile => 'v', prorettype => 'record', proargtypes => 'regclass', + proallargtypes => '{regclass,regclass,regclass,bool,int4}', + proargmodes => '{i,o,o,o,o}', + proargnames => '{rootrelid,relid,parentrelid,isleaf,level}', + prosrc => 'pg_partition_tree' }, +{ oid => '3425', descr => 'view ancestors of the partition', + proname => 'pg_partition_ancestors', prorows => '10', proretset => 't', + provolatile => 'v', prorettype => 'regclass', proargtypes => 'regclass', + proallargtypes => '{regclass,regclass}', proargmodes => '{i,o}', + proargnames => '{partitionid,relid}', prosrc => 'pg_partition_ancestors' }, + +# function to get the top-most partition root parent +{ oid => '3424', descr => 'get top-most partition root parent', + proname => 'pg_partition_root', prorettype => 'regclass', + proargtypes => 'regclass', prosrc => 'pg_partition_root' }, + +{ oid => '4350', descr => 'Unicode normalization', + proname => 'normalize', prorettype => 'text', proargtypes => 'text text', + prosrc => 'unicode_normalize_func' }, + +{ oid => '4351', descr => 'check Unicode normalization', + proname => 'is_normalized', prorettype => 'bool', proargtypes => 'text text', + prosrc => 'unicode_is_normalized' }, + +{ oid => '6198', descr => 'unescape Unicode characters', + proname => 'unistr', prorettype => 'text', proargtypes => 'text', + prosrc => 'unistr' }, + +{ oid => '4596', descr => 'I/O', + proname => 'brin_bloom_summary_in', prorettype => 'pg_brin_bloom_summary', + proargtypes => 'cstring', prosrc => 'brin_bloom_summary_in' }, +{ oid => '4597', descr => 'I/O', + proname => 'brin_bloom_summary_out', prorettype => 'cstring', + proargtypes => 'pg_brin_bloom_summary', prosrc => 'brin_bloom_summary_out' }, +{ oid => '4598', descr => 'I/O', + proname => 'brin_bloom_summary_recv', provolatile => 's', + prorettype => 'pg_brin_bloom_summary', proargtypes => 'internal', + prosrc => 'brin_bloom_summary_recv' }, +{ oid => '4599', descr => 'I/O', + proname => 'brin_bloom_summary_send', provolatile => 's', + prorettype => 'bytea', proargtypes => 'pg_brin_bloom_summary', + prosrc => 'brin_bloom_summary_send' }, + +{ oid => '4638', descr => 'I/O', + proname => 'brin_minmax_multi_summary_in', + prorettype => 'pg_brin_minmax_multi_summary', proargtypes => 'cstring', + prosrc => 'brin_minmax_multi_summary_in' }, +{ oid => '4639', descr => 'I/O', + proname => 'brin_minmax_multi_summary_out', prorettype => 'cstring', + proargtypes => 'pg_brin_minmax_multi_summary', + prosrc => 'brin_minmax_multi_summary_out' }, +{ oid => '4640', descr => 'I/O', + proname => 'brin_minmax_multi_summary_recv', provolatile => 's', + prorettype => 'pg_brin_minmax_multi_summary', proargtypes => 'internal', + prosrc => 'brin_minmax_multi_summary_recv' }, +{ oid => '4641', descr => 'I/O', + proname => 'brin_minmax_multi_summary_send', provolatile => 's', + prorettype => 'bytea', proargtypes => 'pg_brin_minmax_multi_summary', + prosrc => 'brin_minmax_multi_summary_send' }, + +] diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h new file mode 100644 index 0000000..76310d4 --- /dev/null +++ b/src/include/catalog/pg_proc.h @@ -0,0 +1,220 @@ +/*------------------------------------------------------------------------- + * + * pg_proc.h + * definition of the "procedure" system catalog (pg_proc) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_proc.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PROC_H +#define PG_PROC_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_proc_d.h" +#include "nodes/pg_list.h" + +/* ---------------- + * pg_proc definition. cpp turns this into + * typedef struct FormData_pg_proc + * ---------------- + */ +CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,ProcedureRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid; /* oid */ + + /* procedure name */ + NameData proname; + + /* OID of namespace containing this proc */ + Oid pronamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* procedure owner */ + Oid proowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* OID of pg_language entry */ + Oid prolang BKI_DEFAULT(internal) BKI_LOOKUP(pg_language); + + /* estimated execution cost */ + float4 procost BKI_DEFAULT(1); + + /* estimated # of rows out (if proretset) */ + float4 prorows BKI_DEFAULT(0); + + /* element type of variadic array, or 0 if not variadic */ + Oid provariadic BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* planner support function for this function, or 0 if none */ + regproc prosupport BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_proc); + + /* see PROKIND_ categories below */ + char prokind BKI_DEFAULT(f); + + /* security definer */ + bool prosecdef BKI_DEFAULT(f); + + /* is it a leak-proof function? */ + bool proleakproof BKI_DEFAULT(f); + + /* strict with respect to NULLs? */ + bool proisstrict BKI_DEFAULT(t); + + /* returns a set? */ + bool proretset BKI_DEFAULT(f); + + /* see PROVOLATILE_ categories below */ + char provolatile BKI_DEFAULT(i); + + /* see PROPARALLEL_ categories below */ + char proparallel BKI_DEFAULT(s); + + /* number of arguments */ + /* Note: need not be given in pg_proc.dat; genbki.pl will compute it */ + int16 pronargs; + + /* number of arguments with defaults */ + int16 pronargdefaults BKI_DEFAULT(0); + + /* OID of result type */ + Oid prorettype BKI_LOOKUP(pg_type); + + /* + * variable-length fields start here, but we allow direct access to + * proargtypes + */ + + /* parameter types (excludes OUT params) */ + oidvector proargtypes BKI_LOOKUP(pg_type) BKI_FORCE_NOT_NULL; + +#ifdef CATALOG_VARLEN + + /* all param types (NULL if IN only) */ + Oid proallargtypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type); + + /* parameter modes (NULL if IN only) */ + char proargmodes[1] BKI_DEFAULT(_null_); + + /* parameter names (NULL if no names) */ + text proargnames[1] BKI_DEFAULT(_null_); + + /* list of expression trees for argument defaults (NULL if none) */ + pg_node_tree proargdefaults BKI_DEFAULT(_null_); + + /* types for which to apply transforms */ + Oid protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type); + + /* procedure source text */ + text prosrc BKI_FORCE_NOT_NULL; + + /* secondary procedure info (can be NULL) */ + text probin BKI_DEFAULT(_null_); + + /* pre-parsed SQL function body */ + pg_node_tree prosqlbody BKI_DEFAULT(_null_); + + /* procedure-local GUC settings */ + text proconfig[1] BKI_DEFAULT(_null_); + + /* access permissions */ + aclitem proacl[1] BKI_DEFAULT(_null_); +#endif +} FormData_pg_proc; + +/* ---------------- + * Form_pg_proc corresponds to a pointer to a tuple with + * the format of pg_proc relation. + * ---------------- + */ +typedef FormData_pg_proc *Form_pg_proc; + +DECLARE_TOAST(pg_proc, 2836, 2837); + +DECLARE_UNIQUE_INDEX_PKEY(pg_proc_oid_index, 2690, ProcedureOidIndexId, on pg_proc using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index, 2691, ProcedureNameArgsNspIndexId, on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Symbolic values for prokind column + */ +#define PROKIND_FUNCTION 'f' +#define PROKIND_AGGREGATE 'a' +#define PROKIND_WINDOW 'w' +#define PROKIND_PROCEDURE 'p' + +/* + * Symbolic values for provolatile column: these indicate whether the result + * of a function is dependent *only* on the values of its explicit arguments, + * or can change due to outside factors (such as parameter variables or + * table contents). NOTE: functions having side-effects, such as setval(), + * must be labeled volatile to ensure they will not get optimized away, + * even if the actual return value is not changeable. + */ +#define PROVOLATILE_IMMUTABLE 'i' /* never changes for given input */ +#define PROVOLATILE_STABLE 's' /* does not change within a scan */ +#define PROVOLATILE_VOLATILE 'v' /* can change even within a scan */ + +/* + * Symbolic values for proparallel column: these indicate whether a function + * can be safely be run in a parallel backend, during parallelism but + * necessarily in the leader, or only in non-parallel mode. + */ +#define PROPARALLEL_SAFE 's' /* can run in worker or leader */ +#define PROPARALLEL_RESTRICTED 'r' /* can run in parallel leader only */ +#define PROPARALLEL_UNSAFE 'u' /* banned while in parallel mode */ + +/* + * Symbolic values for proargmodes column. Note that these must agree with + * the FunctionParameterMode enum in parsenodes.h; we declare them here to + * be accessible from either header. + */ +#define PROARGMODE_IN 'i' +#define PROARGMODE_OUT 'o' +#define PROARGMODE_INOUT 'b' +#define PROARGMODE_VARIADIC 'v' +#define PROARGMODE_TABLE 't' + +#endif /* EXPOSE_TO_CLIENT_CODE */ + + +extern ObjectAddress ProcedureCreate(const char *procedureName, + Oid procNamespace, + bool replace, + bool returnsSet, + Oid returnType, + Oid proowner, + Oid languageObjectId, + Oid languageValidator, + const char *prosrc, + const char *probin, + Node *prosqlbody, + char prokind, + bool security_definer, + bool isLeakProof, + bool isStrict, + char volatility, + char parallel, + oidvector *parameterTypes, + Datum allParameterTypes, + Datum parameterModes, + Datum parameterNames, + List *parameterDefaults, + Datum trftypes, + Datum proconfig, + Oid prosupport, + float4 procost, + float4 prorows); + +extern bool function_parse_error_transpose(const char *prosrc); + +extern List *oid_array_to_list(Datum datum); + +#endif /* PG_PROC_H */ diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h new file mode 100644 index 0000000..48205ba --- /dev/null +++ b/src/include/catalog/pg_publication.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------- + * + * pg_publication.h + * definition of the "publication" system catalog (pg_publication) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_publication.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_H +#define PG_PUBLICATION_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_publication_d.h" + +/* ---------------- + * pg_publication definition. cpp turns this into + * typedef struct FormData_pg_publication + * ---------------- + */ +CATALOG(pg_publication,6104,PublicationRelationId) +{ + Oid oid; /* oid */ + + NameData pubname; /* name of the publication */ + + Oid pubowner BKI_LOOKUP(pg_authid); /* publication owner */ + + /* + * indicates that this is special publication which should encompass all + * tables in the database (except for the unlogged and temp ones) + */ + bool puballtables; + + /* true if inserts are published */ + bool pubinsert; + + /* true if updates are published */ + bool pubupdate; + + /* true if deletes are published */ + bool pubdelete; + + /* true if truncates are published */ + bool pubtruncate; + + /* true if partition changes are published using root schema */ + bool pubviaroot; +} FormData_pg_publication; + +/* ---------------- + * Form_pg_publication corresponds to a pointer to a tuple with + * the format of pg_publication relation. + * ---------------- + */ +typedef FormData_pg_publication *Form_pg_publication; + +DECLARE_UNIQUE_INDEX_PKEY(pg_publication_oid_index, 6110, PublicationObjectIndexId, on pg_publication using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_publication_pubname_index, 6111, PublicationNameIndexId, on pg_publication using btree(pubname name_ops)); + +typedef struct PublicationActions +{ + bool pubinsert; + bool pubupdate; + bool pubdelete; + bool pubtruncate; +} PublicationActions; + +typedef struct PublicationDesc +{ + PublicationActions pubactions; + + /* + * true if the columns referenced in row filters which are used for UPDATE + * or DELETE are part of the replica identity or the publication actions + * do not include UPDATE or DELETE. + */ + bool rf_valid_for_update; + bool rf_valid_for_delete; + + /* + * true if the columns are part of the replica identity or the publication + * actions do not include UPDATE or DELETE. + */ + bool cols_valid_for_update; + bool cols_valid_for_delete; +} PublicationDesc; + +typedef struct Publication +{ + Oid oid; + char *name; + bool alltables; + bool pubviaroot; + PublicationActions pubactions; +} Publication; + +typedef struct PublicationRelInfo +{ + Relation relation; + Node *whereClause; + List *columns; +} PublicationRelInfo; + +extern Publication *GetPublication(Oid pubid); +extern Publication *GetPublicationByName(const char *pubname, bool missing_ok); +extern List *GetRelationPublications(Oid relid); + +/*--------- + * Expected values for pub_partopt parameter of GetRelationPublications(), + * which allows callers to specify which partitions of partitioned tables + * mentioned in the publication they expect to see. + * + * ROOT: only the table explicitly mentioned in the publication + * LEAF: only leaf partitions in given tree + * ALL: all partitions in given tree + */ +typedef enum PublicationPartOpt +{ + PUBLICATION_PART_ROOT, + PUBLICATION_PART_LEAF, + PUBLICATION_PART_ALL, +} PublicationPartOpt; + +extern List *GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt); +extern List *GetAllTablesPublications(void); +extern List *GetAllTablesPublicationRelations(bool pubviaroot); +extern List *GetPublicationSchemas(Oid pubid); +extern List *GetSchemaPublications(Oid schemaid); +extern List *GetSchemaPublicationRelations(Oid schemaid, + PublicationPartOpt pub_partopt); +extern List *GetAllSchemaPublicationRelations(Oid puboid, + PublicationPartOpt pub_partopt); +extern List *GetPubPartitionOptionRelations(List *result, + PublicationPartOpt pub_partopt, + Oid relid); +extern Oid GetTopMostAncestorInPublication(Oid puboid, List *ancestors, + int *ancestor_level); + +extern bool is_publishable_relation(Relation rel); +extern bool is_schema_publication(Oid pubid); +extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *pri, + bool if_not_exists); +extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, + bool if_not_exists); + +extern Bitmapset *pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, + MemoryContext mcxt); + +extern Oid get_publication_oid(const char *pubname, bool missing_ok); +extern char *get_publication_name(Oid pubid, bool missing_ok); + +#endif /* PG_PUBLICATION_H */ diff --git a/src/include/catalog/pg_publication_namespace.h b/src/include/catalog/pg_publication_namespace.h new file mode 100644 index 0000000..d166600 --- /dev/null +++ b/src/include/catalog/pg_publication_namespace.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * pg_publication_namespace.h + * definition of the system catalog for mappings between schemas and + * publications (pg_publication_namespace) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_publication_namespace.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_NAMESPACE_H +#define PG_PUBLICATION_NAMESPACE_H + +#include "catalog/genbki.h" +#include "catalog/pg_publication_namespace_d.h" + + +/* ---------------- + * pg_publication_namespace definition. cpp turns this into + * typedef struct FormData_pg_publication_namespace + * ---------------- + */ +CATALOG(pg_publication_namespace,6237,PublicationNamespaceRelationId) +{ + Oid oid; /* oid */ + Oid pnpubid BKI_LOOKUP(pg_publication); /* Oid of the publication */ + Oid pnnspid BKI_LOOKUP(pg_namespace); /* Oid of the schema */ +} FormData_pg_publication_namespace; + +/* ---------------- + * Form_pg_publication_namespace corresponds to a pointer to a tuple with + * the format of pg_publication_namespace relation. + * ---------------- + */ +typedef FormData_pg_publication_namespace *Form_pg_publication_namespace; + +DECLARE_UNIQUE_INDEX_PKEY(pg_publication_namespace_oid_index, 6238, PublicationNamespaceObjectIndexId, on pg_publication_namespace using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_publication_namespace_pnnspid_pnpubid_index, 6239, PublicationNamespacePnnspidPnpubidIndexId, on pg_publication_namespace using btree(pnnspid oid_ops, pnpubid oid_ops)); + +#endif /* PG_PUBLICATION_NAMESPACE_H */ diff --git a/src/include/catalog/pg_publication_rel.h b/src/include/catalog/pg_publication_rel.h new file mode 100644 index 0000000..ecd3739 --- /dev/null +++ b/src/include/catalog/pg_publication_rel.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * pg_publication_rel.h + * definition of the system catalog for mappings between relations and + * publications (pg_publication_rel) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_publication_rel.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PUBLICATION_REL_H +#define PG_PUBLICATION_REL_H + +#include "catalog/genbki.h" +#include "catalog/pg_publication_rel_d.h" + +/* ---------------- + * pg_publication_rel definition. cpp turns this into + * typedef struct FormData_pg_publication_rel + * ---------------- + */ +CATALOG(pg_publication_rel,6106,PublicationRelRelationId) +{ + Oid oid; /* oid */ + Oid prpubid BKI_LOOKUP(pg_publication); /* Oid of the publication */ + Oid prrelid BKI_LOOKUP(pg_class); /* Oid of the relation */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + pg_node_tree prqual; /* qualifications */ + int2vector prattrs; /* columns to replicate */ +#endif +} FormData_pg_publication_rel; + +/* ---------------- + * Form_pg_publication_rel corresponds to a pointer to a tuple with + * the format of pg_publication_rel relation. + * ---------------- + */ +typedef FormData_pg_publication_rel *Form_pg_publication_rel; + +DECLARE_TOAST(pg_publication_rel, 6228, 6229); + +DECLARE_UNIQUE_INDEX_PKEY(pg_publication_rel_oid_index, 6112, PublicationRelObjectIndexId, on pg_publication_rel using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_publication_rel_prrelid_prpubid_index, 6113, PublicationRelPrrelidPrpubidIndexId, on pg_publication_rel using btree(prrelid oid_ops, prpubid oid_ops)); +DECLARE_INDEX(pg_publication_rel_prpubid_index, 6116, PublicationRelPrpubidIndexId, on pg_publication_rel using btree(prpubid oid_ops)); + +#endif /* PG_PUBLICATION_REL_H */ diff --git a/src/include/catalog/pg_range.dat b/src/include/catalog/pg_range.dat new file mode 100644 index 0000000..74d6de0 --- /dev/null +++ b/src/include/catalog/pg_range.dat @@ -0,0 +1,34 @@ +#---------------------------------------------------------------------- +# +# pg_range.dat +# Initial contents of the pg_range system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_range.dat +# +#---------------------------------------------------------------------- + +[ + +{ rngtypid => 'int4range', rngsubtype => 'int4', + rngmultitypid => 'int4multirange', rngsubopc => 'btree/int4_ops', + rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' }, +{ rngtypid => 'numrange', rngsubtype => 'numeric', + rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops', + rngcanonical => '-', rngsubdiff => 'numrange_subdiff' }, +{ rngtypid => 'tsrange', rngsubtype => 'timestamp', + rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops', + rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' }, +{ rngtypid => 'tstzrange', rngsubtype => 'timestamptz', + rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops', + rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' }, +{ rngtypid => 'daterange', rngsubtype => 'date', + rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops', + rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' }, +{ rngtypid => 'int8range', rngsubtype => 'int8', + rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops', + rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff' }, + +] diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h new file mode 100644 index 0000000..faa57e8 --- /dev/null +++ b/src/include/catalog/pg_range.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * pg_range.h + * definition of the "range type" system catalog (pg_range) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_range.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_RANGE_H +#define PG_RANGE_H + +#include "catalog/genbki.h" +#include "catalog/pg_range_d.h" + +/* ---------------- + * pg_range definition. cpp turns this into + * typedef struct FormData_pg_range + * ---------------- + */ +CATALOG(pg_range,3541,RangeRelationId) +{ + /* OID of owning range type */ + Oid rngtypid BKI_LOOKUP(pg_type); + + /* OID of range's element type (subtype) */ + Oid rngsubtype BKI_LOOKUP(pg_type); + + /* OID of the range's multirange type */ + Oid rngmultitypid BKI_LOOKUP(pg_type); + + /* collation for this range type, or 0 */ + Oid rngcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation); + + /* subtype's btree opclass */ + Oid rngsubopc BKI_LOOKUP(pg_opclass); + + /* canonicalize range, or 0 */ + regproc rngcanonical BKI_LOOKUP_OPT(pg_proc); + + /* subtype difference as a float8, or 0 */ + regproc rngsubdiff BKI_LOOKUP_OPT(pg_proc); +} FormData_pg_range; + +/* ---------------- + * Form_pg_range corresponds to a pointer to a tuple with + * the format of pg_range relation. + * ---------------- + */ +typedef FormData_pg_range *Form_pg_range; + +DECLARE_UNIQUE_INDEX_PKEY(pg_range_rngtypid_index, 3542, RangeTypidIndexId, on pg_range using btree(rngtypid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_range_rngmultitypid_index, 2228, RangeMultirangeTypidIndexId, on pg_range using btree(rngmultitypid oid_ops)); + +/* + * prototypes for functions in pg_range.c + */ + +extern void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, + Oid rangeSubOpclass, RegProcedure rangeCanonical, + RegProcedure rangeSubDiff, Oid multirangeTypeOid); +extern void RangeDelete(Oid rangeTypeOid); + +#endif /* PG_RANGE_H */ diff --git a/src/include/catalog/pg_replication_origin.h b/src/include/catalog/pg_replication_origin.h new file mode 100644 index 0000000..3b11cd2 --- /dev/null +++ b/src/include/catalog/pg_replication_origin.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * pg_replication_origin.h + * definition of the "replication origin" system catalog + * (pg_replication_origin) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_replication_origin.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_REPLICATION_ORIGIN_H +#define PG_REPLICATION_ORIGIN_H + +#include "access/xlogdefs.h" +#include "catalog/genbki.h" +#include "catalog/pg_replication_origin_d.h" + +/* ---------------- + * pg_replication_origin. cpp turns this into + * typedef struct FormData_pg_replication_origin + * ---------------- + */ +CATALOG(pg_replication_origin,6000,ReplicationOriginRelationId) BKI_SHARED_RELATION +{ + /* + * Locally known id that get included into WAL. + * + * This should never leave the system. + * + * Needs to fit into an uint16, so we don't waste too much space in WAL + * records. For this reason we don't use a normal Oid column here, since + * we need to handle allocation of new values manually. + */ + Oid roident; + + /* + * Variable-length fields start here, but we allow direct access to + * roname. + */ + + /* external, free-format, name */ + text roname BKI_FORCE_NOT_NULL; + +#ifdef CATALOG_VARLEN /* further variable-length fields */ +#endif +} FormData_pg_replication_origin; + +typedef FormData_pg_replication_origin *Form_pg_replication_origin; + +DECLARE_TOAST_WITH_MACRO(pg_replication_origin, 4181, 4182, PgReplicationOriginToastTable, PgReplicationOriginToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_replication_origin_roiident_index, 6001, ReplicationOriginIdentIndex, on pg_replication_origin using btree(roident oid_ops)); +DECLARE_UNIQUE_INDEX(pg_replication_origin_roname_index, 6002, ReplicationOriginNameIndex, on pg_replication_origin using btree(roname text_ops)); + +#endif /* PG_REPLICATION_ORIGIN_H */ diff --git a/src/include/catalog/pg_rewrite.h b/src/include/catalog/pg_rewrite.h new file mode 100644 index 0000000..c647f26 --- /dev/null +++ b/src/include/catalog/pg_rewrite.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * pg_rewrite.h + * definition of the "rewrite rule" system catalog (pg_rewrite) + * + * As of Postgres 7.3, the primary key for this table is <ev_class, rulename> + * --- ie, rule names are only unique among the rules of a given table. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_rewrite.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_REWRITE_H +#define PG_REWRITE_H + +#include "catalog/genbki.h" +#include "catalog/pg_rewrite_d.h" + +/* ---------------- + * pg_rewrite definition. cpp turns this into + * typedef struct FormData_pg_rewrite + * ---------------- + */ +CATALOG(pg_rewrite,2618,RewriteRelationId) +{ + Oid oid; /* oid */ + NameData rulename; + Oid ev_class BKI_LOOKUP(pg_class); + char ev_type; + char ev_enabled; + bool is_instead; + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + pg_node_tree ev_qual BKI_FORCE_NOT_NULL; + pg_node_tree ev_action BKI_FORCE_NOT_NULL; +#endif +} FormData_pg_rewrite; + +/* ---------------- + * Form_pg_rewrite corresponds to a pointer to a tuple with + * the format of pg_rewrite relation. + * ---------------- + */ +typedef FormData_pg_rewrite *Form_pg_rewrite; + +DECLARE_TOAST(pg_rewrite, 2838, 2839); + +DECLARE_UNIQUE_INDEX_PKEY(pg_rewrite_oid_index, 2692, RewriteOidIndexId, on pg_rewrite using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index, 2693, RewriteRelRulenameIndexId, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops)); + +#endif /* PG_REWRITE_H */ diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h new file mode 100644 index 0000000..e1ddb64 --- /dev/null +++ b/src/include/catalog/pg_seclabel.h @@ -0,0 +1,45 @@ +/* ------------------------------------------------------------------------- + * + * pg_seclabel.h + * definition of the "security label" system catalog (pg_seclabel) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_seclabel.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SECLABEL_H +#define PG_SECLABEL_H + +#include "catalog/genbki.h" +#include "catalog/pg_seclabel_d.h" + +/* ---------------- + * pg_seclabel definition. cpp turns this into + * typedef struct FormData_pg_seclabel + * ---------------- + */ +CATALOG(pg_seclabel,3596,SecLabelRelationId) +{ + Oid objoid; /* OID of the object itself */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing the + * object */ + int32 objsubid; /* column number, or 0 if not used */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text provider BKI_FORCE_NOT_NULL; /* name of label provider */ + text label BKI_FORCE_NOT_NULL; /* security label of the object */ +#endif +} FormData_pg_seclabel; + +DECLARE_TOAST(pg_seclabel, 3598, 3599); + +DECLARE_UNIQUE_INDEX_PKEY(pg_seclabel_object_index, 3597, SecLabelObjectIndexId, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops)); + +#endif /* PG_SECLABEL_H */ diff --git a/src/include/catalog/pg_sequence.h b/src/include/catalog/pg_sequence.h new file mode 100644 index 0000000..82b35aa --- /dev/null +++ b/src/include/catalog/pg_sequence.h @@ -0,0 +1,44 @@ +/* ------------------------------------------------------------------------- + * + * pg_sequence.h + * definition of the "sequence" system catalog (pg_sequence) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_sequence.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SEQUENCE_H +#define PG_SEQUENCE_H + +#include "catalog/genbki.h" +#include "catalog/pg_sequence_d.h" + +CATALOG(pg_sequence,2224,SequenceRelationId) +{ + Oid seqrelid BKI_LOOKUP(pg_class); + Oid seqtypid BKI_LOOKUP(pg_type); + int64 seqstart; + int64 seqincrement; + int64 seqmax; + int64 seqmin; + int64 seqcache; + bool seqcycle; +} FormData_pg_sequence; + +/* ---------------- + * Form_pg_sequence corresponds to a pointer to a tuple with + * the format of pg_sequence relation. + * ---------------- + */ +typedef FormData_pg_sequence *Form_pg_sequence; + +DECLARE_UNIQUE_INDEX_PKEY(pg_sequence_seqrelid_index, 5002, SequenceRelidIndexId, on pg_sequence using btree(seqrelid oid_ops)); + +#endif /* PG_SEQUENCE_H */ diff --git a/src/include/catalog/pg_shdepend.h b/src/include/catalog/pg_shdepend.h new file mode 100644 index 0000000..8119b28 --- /dev/null +++ b/src/include/catalog/pg_shdepend.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + * + * pg_shdepend.h + * definition of the "shared dependency" system catalog (pg_shdepend) + * + * pg_shdepend has no preloaded contents, so there is no pg_shdepend.dat + * file; dependencies for system-defined objects are loaded into it + * on-the-fly during initdb. Most built-in objects are pinned anyway, + * and hence need no explicit entries in pg_shdepend. + * + * NOTE: we do not represent all possible dependency pairs in pg_shdepend; + * for example, there's not much value in creating an explicit dependency + * from a relation to its database. Currently, only dependencies on roles + * are explicitly stored in pg_shdepend. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_shdepend.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHDEPEND_H +#define PG_SHDEPEND_H + +#include "catalog/genbki.h" +#include "catalog/pg_shdepend_d.h" + +/* ---------------- + * pg_shdepend definition. cpp turns this into + * typedef struct FormData_pg_shdepend + * ---------------- + */ +CATALOG(pg_shdepend,1214,SharedDependRelationId) BKI_SHARED_RELATION +{ + /* + * Identification of the dependent (referencing) object. + * + * Note that dbid can be zero to denote a shared object. + */ + Oid dbid BKI_LOOKUP_OPT(pg_database); /* OID of database + * containing object */ + Oid classid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ + Oid objid; /* OID of object itself */ + int32 objsubid; /* column number, or 0 if not used */ + + /* + * Identification of the independent (referenced) object. This is always + * a shared object, so we need no database ID field. We don't bother with + * a sub-object ID either. + */ + Oid refclassid BKI_LOOKUP(pg_class); /* OID of table containing + * object */ + Oid refobjid; /* OID of object itself */ + + /* + * Precise semantics of the relationship are specified by the deptype + * field. See SharedDependencyType in catalog/dependency.h. + */ + char deptype; /* see codes in dependency.h */ +} FormData_pg_shdepend; + +/* ---------------- + * Form_pg_shdepend corresponds to a pointer to a row with + * the format of pg_shdepend relation. + * ---------------- + */ +typedef FormData_pg_shdepend *Form_pg_shdepend; + +DECLARE_INDEX(pg_shdepend_depender_index, 1232, SharedDependDependerIndexId, on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops, objsubid int4_ops)); +DECLARE_INDEX(pg_shdepend_reference_index, 1233, SharedDependReferenceIndexId, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops)); + +#endif /* PG_SHDEPEND_H */ diff --git a/src/include/catalog/pg_shdescription.h b/src/include/catalog/pg_shdescription.h new file mode 100644 index 0000000..da2b9f6 --- /dev/null +++ b/src/include/catalog/pg_shdescription.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + * + * pg_shdescription.h + * definition of the "shared description" system catalog + * (pg_shdescription) + * + * Because the contents of this table are taken from the *.dat files + * of other catalogs, there is no pg_shdescription.dat file. The initial + * contents are assembled by genbki.pl and loaded during initdb. + * + * NOTE: an object is identified by the OID of the row that primarily + * defines the object, plus the OID of the table that that row appears in. + * For example, a database is identified by the OID of its pg_database row + * plus the pg_class OID of table pg_database. This allows unique + * identification of objects without assuming that OIDs are unique + * across tables. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_shdescription.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHDESCRIPTION_H +#define PG_SHDESCRIPTION_H + +#include "catalog/genbki.h" +#include "catalog/pg_shdescription_d.h" + +/* ---------------- + * pg_shdescription definition. cpp turns this into + * typedef struct FormData_pg_shdescription + * ---------------- + */ +CATALOG(pg_shdescription,2396,SharedDescriptionRelationId) BKI_SHARED_RELATION +{ + Oid objoid; /* OID of object itself */ + Oid classoid; /* OID of table containing object */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text description BKI_FORCE_NOT_NULL; /* description of object */ +#endif +} FormData_pg_shdescription; + +/* ---------------- + * Form_pg_shdescription corresponds to a pointer to a tuple with + * the format of pg_shdescription relation. + * ---------------- + */ +typedef FormData_pg_shdescription * Form_pg_shdescription; + +DECLARE_TOAST_WITH_MACRO(pg_shdescription, 2846, 2847, PgShdescriptionToastTable, PgShdescriptionToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_shdescription_o_c_index, 2397, SharedDescriptionObjIndexId, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops)); + +/* We do not use BKI_LOOKUP here because it causes problems for genbki.pl */ +DECLARE_FOREIGN_KEY((classoid), pg_class, (oid)); + +#endif /* PG_SHDESCRIPTION_H */ diff --git a/src/include/catalog/pg_shseclabel.h b/src/include/catalog/pg_shseclabel.h new file mode 100644 index 0000000..fc1b97f --- /dev/null +++ b/src/include/catalog/pg_shseclabel.h @@ -0,0 +1,46 @@ +/* ------------------------------------------------------------------------- + * + * pg_shseclabel.h + * definition of the "shared security label" system catalog (pg_shseclabel) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_shseclabel.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SHSECLABEL_H +#define PG_SHSECLABEL_H + +#include "catalog/genbki.h" +#include "catalog/pg_shseclabel_d.h" + +/* ---------------- + * pg_shseclabel definition. cpp turns this into + * typedef struct FormData_pg_shseclabel + * ---------------- + */ +CATALOG(pg_shseclabel,3592,SharedSecLabelRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(4066,SharedSecLabelRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid objoid; /* OID of the shared object itself */ + Oid classoid BKI_LOOKUP(pg_class); /* OID of table containing the + * shared object */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text provider BKI_FORCE_NOT_NULL; /* name of label provider */ + text label BKI_FORCE_NOT_NULL; /* security label of the object */ +#endif +} FormData_pg_shseclabel; + +typedef FormData_pg_shseclabel * Form_pg_shseclabel; + +DECLARE_TOAST_WITH_MACRO(pg_shseclabel, 4060, 4061, PgShseclabelToastTable, PgShseclabelToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_shseclabel_object_index, 3593, SharedSecLabelObjectIndexId, on pg_shseclabel using btree(objoid oid_ops, classoid oid_ops, provider text_ops)); + +#endif /* PG_SHSECLABEL_H */ diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h new file mode 100644 index 0000000..cdf7448 --- /dev/null +++ b/src/include/catalog/pg_statistic.h @@ -0,0 +1,282 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic.h + * definition of the "statistics" system catalog (pg_statistic) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_statistic.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_H +#define PG_STATISTIC_H + +#include "catalog/genbki.h" +#include "catalog/pg_statistic_d.h" + +/* ---------------- + * pg_statistic definition. cpp turns this into + * typedef struct FormData_pg_statistic + * ---------------- + */ +CATALOG(pg_statistic,2619,StatisticRelationId) +{ + /* These fields form the unique key for the entry: */ + Oid starelid BKI_LOOKUP(pg_class); /* relation containing + * attribute */ + int16 staattnum; /* attribute (column) stats are for */ + bool stainherit; /* true if inheritance children are included */ + + /* the fraction of the column's entries that are NULL: */ + float4 stanullfrac; + + /* + * stawidth is the average width in bytes of non-null entries. For + * fixed-width datatypes this is of course the same as the typlen, but for + * var-width types it is more useful. Note that this is the average width + * of the data as actually stored, post-TOASTing (eg, for a + * moved-out-of-line value, only the size of the pointer object is + * counted). This is the appropriate definition for the primary use of + * the statistic, which is to estimate sizes of in-memory hash tables of + * tuples. + */ + int32 stawidth; + + /* ---------------- + * stadistinct indicates the (approximate) number of distinct non-null + * data values in the column. The interpretation is: + * 0 unknown or not computed + * > 0 actual number of distinct values + * < 0 negative of multiplier for number of rows + * The special negative case allows us to cope with columns that are + * unique (stadistinct = -1) or nearly so (for example, a column in which + * non-null values appear about twice on the average could be represented + * by stadistinct = -0.5 if there are no nulls, or -0.4 if 20% of the + * column is nulls). Because the number-of-rows statistic in pg_class may + * be updated more frequently than pg_statistic is, it's important to be + * able to describe such situations as a multiple of the number of rows, + * rather than a fixed number of distinct values. But in other cases a + * fixed number is correct (eg, a boolean column). + * ---------------- + */ + float4 stadistinct; + + /* ---------------- + * To allow keeping statistics on different kinds of datatypes, + * we do not hard-wire any particular meaning for the remaining + * statistical fields. Instead, we provide several "slots" in which + * statistical data can be placed. Each slot includes: + * kind integer code identifying kind of data (see below) + * op OID of associated operator, if needed + * coll OID of relevant collation, or 0 if none + * numbers float4 array (for statistical values) + * values anyarray (for representations of data values) + * The ID, operator, and collation fields are never NULL; they are zeroes + * in an unused slot. The numbers and values fields are NULL in an + * unused slot, and might also be NULL in a used slot if the slot kind + * has no need for one or the other. + * ---------------- + */ + + int16 stakind1; + int16 stakind2; + int16 stakind3; + int16 stakind4; + int16 stakind5; + + Oid staop1 BKI_LOOKUP_OPT(pg_operator); + Oid staop2 BKI_LOOKUP_OPT(pg_operator); + Oid staop3 BKI_LOOKUP_OPT(pg_operator); + Oid staop4 BKI_LOOKUP_OPT(pg_operator); + Oid staop5 BKI_LOOKUP_OPT(pg_operator); + + Oid stacoll1 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll2 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll3 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll4 BKI_LOOKUP_OPT(pg_collation); + Oid stacoll5 BKI_LOOKUP_OPT(pg_collation); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + float4 stanumbers1[1]; + float4 stanumbers2[1]; + float4 stanumbers3[1]; + float4 stanumbers4[1]; + float4 stanumbers5[1]; + + /* + * Values in these arrays are values of the column's data type, or of some + * related type such as an array element type. We presently have to cheat + * quite a bit to allow polymorphic arrays of this kind, but perhaps + * someday it'll be a less bogus facility. + */ + anyarray stavalues1; + anyarray stavalues2; + anyarray stavalues3; + anyarray stavalues4; + anyarray stavalues5; +#endif +} FormData_pg_statistic; + +#define STATISTIC_NUM_SLOTS 5 + + +/* ---------------- + * Form_pg_statistic corresponds to a pointer to a tuple with + * the format of pg_statistic relation. + * ---------------- + */ +typedef FormData_pg_statistic *Form_pg_statistic; + +DECLARE_TOAST(pg_statistic, 2840, 2841); + +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_relid_att_inh_index, 2696, StatisticRelidAttnumInhIndexId, on pg_statistic using btree(starelid oid_ops, staattnum int2_ops, stainherit bool_ops)); + +DECLARE_FOREIGN_KEY((starelid, staattnum), pg_attribute, (attrelid, attnum)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * Several statistical slot "kinds" are defined by core PostgreSQL, as + * documented below. Also, custom data types can define their own "kind" + * codes by mutual agreement between a custom typanalyze routine and the + * selectivity estimation functions of the type's operators. + * + * Code reading the pg_statistic relation should not assume that a particular + * data "kind" will appear in any particular slot. Instead, search the + * stakind fields to see if the desired data is available. (The standard + * function get_attstatsslot() may be used for this.) + */ + +/* + * The present allocation of "kind" codes is: + * + * 1-99: reserved for assignment by the core PostgreSQL project + * (values in this range will be documented in this file) + * 100-199: reserved for assignment by the PostGIS project + * (values to be documented in PostGIS documentation) + * 200-299: reserved for assignment by the ESRI ST_Geometry project + * (values to be documented in ESRI ST_Geometry documentation) + * 300-9999: reserved for future public assignments + * + * For private use you may choose a "kind" code at random in the range + * 10000-30000. However, for code that is to be widely disseminated it is + * better to obtain a publicly defined "kind" code by request from the + * PostgreSQL Global Development Group. + */ + +/* + * In a "most common values" slot, staop is the OID of the "=" operator + * used to decide whether values are the same or not, and stacoll is the + * collation used (same as column's collation). stavalues contains + * the K most common non-null values appearing in the column, and stanumbers + * contains their frequencies (fractions of total row count). The values + * shall be ordered in decreasing frequency. Note that since the arrays are + * variable-size, K may be chosen by the statistics collector. Values should + * not appear in MCV unless they have been observed to occur more than once; + * a unique column will have no MCV slot. + */ +#define STATISTIC_KIND_MCV 1 + +/* + * A "histogram" slot describes the distribution of scalar data. staop is + * the OID of the "<" operator that describes the sort ordering, and stacoll + * is the relevant collation. (In theory more than one histogram could appear, + * if a datatype has more than one useful sort operator or we care about more + * than one collation. Currently the collation will always be that of the + * underlying column.) stavalues contains M (>=2) non-null values that + * divide the non-null column data values into M-1 bins of approximately equal + * population. The first stavalues item is the MIN and the last is the MAX. + * stanumbers is not used and should be NULL. IMPORTANT POINT: if an MCV + * slot is also provided, then the histogram describes the data distribution + * *after removing the values listed in MCV* (thus, it's a "compressed + * histogram" in the technical parlance). This allows a more accurate + * representation of the distribution of a column with some very-common + * values. In a column with only a few distinct values, it's possible that + * the MCV list describes the entire data population; in this case the + * histogram reduces to empty and should be omitted. + */ +#define STATISTIC_KIND_HISTOGRAM 2 + +/* + * A "correlation" slot describes the correlation between the physical order + * of table tuples and the ordering of data values of this column, as seen + * by the "<" operator identified by staop with the collation identified by + * stacoll. (As with the histogram, more than one entry could theoretically + * appear.) stavalues is not used and should be NULL. stanumbers contains + * a single entry, the correlation coefficient between the sequence of data + * values and the sequence of their actual tuple positions. The coefficient + * ranges from +1 to -1. + */ +#define STATISTIC_KIND_CORRELATION 3 + +/* + * A "most common elements" slot is similar to a "most common values" slot, + * except that it stores the most common non-null *elements* of the column + * values. This is useful when the column datatype is an array or some other + * type with identifiable elements (for instance, tsvector). staop contains + * the equality operator appropriate to the element type, and stacoll + * contains the collation to use with it. stavalues contains + * the most common element values, and stanumbers their frequencies. Unlike + * MCV slots, frequencies are measured as the fraction of non-null rows the + * element value appears in, not the frequency of all rows. Also unlike + * MCV slots, the values are sorted into the element type's default order + * (to support binary search for a particular value). Since this puts the + * minimum and maximum frequencies at unpredictable spots in stanumbers, + * there are two extra members of stanumbers, holding copies of the minimum + * and maximum frequencies. Optionally, there can be a third extra member, + * which holds the frequency of null elements (expressed in the same terms: + * the fraction of non-null rows that contain at least one null element). If + * this member is omitted, the column is presumed to contain no null elements. + * + * Note: in current usage for tsvector columns, the stavalues elements are of + * type text, even though their representation within tsvector is not + * exactly text. + */ +#define STATISTIC_KIND_MCELEM 4 + +/* + * A "distinct elements count histogram" slot describes the distribution of + * the number of distinct element values present in each row of an array-type + * column. Only non-null rows are considered, and only non-null elements. + * staop contains the equality operator appropriate to the element type, + * and stacoll contains the collation to use with it. + * stavalues is not used and should be NULL. The last member of stanumbers is + * the average count of distinct element values over all non-null rows. The + * preceding M (>=2) members form a histogram that divides the population of + * distinct-elements counts into M-1 bins of approximately equal population. + * The first of these is the minimum observed count, and the last the maximum. + */ +#define STATISTIC_KIND_DECHIST 5 + +/* + * A "length histogram" slot describes the distribution of range lengths in + * rows of a range-type column. stanumbers contains a single entry, the + * fraction of empty ranges. stavalues is a histogram of non-empty lengths, in + * a format similar to STATISTIC_KIND_HISTOGRAM: it contains M (>=2) range + * values that divide the column data values into M-1 bins of approximately + * equal population. The lengths are stored as float8s, as measured by the + * range type's subdiff function. Only non-null rows are considered. + */ +#define STATISTIC_KIND_RANGE_LENGTH_HISTOGRAM 6 + +/* + * A "bounds histogram" slot is similar to STATISTIC_KIND_HISTOGRAM, but for + * a range-type column. stavalues contains M (>=2) range values that divide + * the column data values into M-1 bins of approximately equal population. + * Unlike a regular scalar histogram, this is actually two histograms combined + * into a single array, with the lower bounds of each value forming a + * histogram of lower bounds, and the upper bounds a histogram of upper + * bounds. Only non-NULL, non-empty ranges are included. + */ +#define STATISTIC_KIND_BOUNDS_HISTOGRAM 7 + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_STATISTIC_H */ diff --git a/src/include/catalog/pg_statistic_ext.h b/src/include/catalog/pg_statistic_ext.h new file mode 100644 index 0000000..b8520ba --- /dev/null +++ b/src/include/catalog/pg_statistic_ext.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic_ext.h + * definition of the "extended statistics" system catalog + * (pg_statistic_ext) + * + * Note that pg_statistic_ext contains the definitions of extended statistics + * objects, created by CREATE STATISTICS, but not the actual statistical data, + * created by running ANALYZE. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_statistic_ext.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_EXT_H +#define PG_STATISTIC_EXT_H + +#include "catalog/genbki.h" +#include "catalog/pg_statistic_ext_d.h" + +/* ---------------- + * pg_statistic_ext definition. cpp turns this into + * typedef struct FormData_pg_statistic_ext + * ---------------- + */ +CATALOG(pg_statistic_ext,3381,StatisticExtRelationId) +{ + Oid oid; /* oid */ + + Oid stxrelid BKI_LOOKUP(pg_class); /* relation containing + * attributes */ + + /* These two fields form the unique key for the entry: */ + NameData stxname; /* statistics object name */ + Oid stxnamespace BKI_LOOKUP(pg_namespace); /* OID of statistics + * object's namespace */ + + Oid stxowner BKI_LOOKUP(pg_authid); /* statistics object's owner */ + int32 stxstattarget BKI_DEFAULT(-1); /* statistics target */ + + /* + * variable-length fields start here, but we allow direct access to + * stxkeys + */ + int2vector stxkeys BKI_FORCE_NOT_NULL; /* array of column keys */ + +#ifdef CATALOG_VARLEN + char stxkind[1] BKI_FORCE_NOT_NULL; /* statistics kinds requested + * to build */ + pg_node_tree stxexprs; /* A list of expression trees for stats + * attributes that are not simple column + * references. */ +#endif + +} FormData_pg_statistic_ext; + +/* ---------------- + * Form_pg_statistic_ext corresponds to a pointer to a tuple with + * the format of pg_statistic_ext relation. + * ---------------- + */ +typedef FormData_pg_statistic_ext *Form_pg_statistic_ext; + +DECLARE_TOAST(pg_statistic_ext, 3439, 3440); + +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_ext_oid_index, 3380, StatisticExtOidIndexId, on pg_statistic_ext using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_statistic_ext_name_index, 3997, StatisticExtNameIndexId, on pg_statistic_ext using btree(stxname name_ops, stxnamespace oid_ops)); +DECLARE_INDEX(pg_statistic_ext_relid_index, 3379, StatisticExtRelidIndexId, on pg_statistic_ext using btree(stxrelid oid_ops)); + +DECLARE_ARRAY_FOREIGN_KEY((stxrelid, stxkeys), pg_attribute, (attrelid, attnum)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +#define STATS_EXT_NDISTINCT 'd' +#define STATS_EXT_DEPENDENCIES 'f' +#define STATS_EXT_MCV 'm' +#define STATS_EXT_EXPRESSIONS 'e' + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_STATISTIC_EXT_H */ diff --git a/src/include/catalog/pg_statistic_ext_data.h b/src/include/catalog/pg_statistic_ext_data.h new file mode 100644 index 0000000..0ea3c41 --- /dev/null +++ b/src/include/catalog/pg_statistic_ext_data.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * pg_statistic_ext_data.h + * definition of the "extended statistics data" system catalog + * (pg_statistic_ext_data) + * + * This catalog stores the statistical data for extended statistics objects. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_statistic_ext_data.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_STATISTIC_EXT_DATA_H +#define PG_STATISTIC_EXT_DATA_H + +#include "catalog/genbki.h" +#include "catalog/pg_statistic_ext_data_d.h" + +/* ---------------- + * pg_statistic_ext_data definition. cpp turns this into + * typedef struct FormData_pg_statistic_ext_data + * ---------------- + */ +CATALOG(pg_statistic_ext_data,3429,StatisticExtDataRelationId) +{ + Oid stxoid BKI_LOOKUP(pg_statistic_ext); /* statistics object + * this data is for */ + bool stxdinherit; /* true if inheritance children are included */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + pg_ndistinct stxdndistinct; /* ndistinct coefficients (serialized) */ + pg_dependencies stxddependencies; /* dependencies (serialized) */ + pg_mcv_list stxdmcv; /* MCV (serialized) */ + pg_statistic stxdexpr[1]; /* stats for expressions */ + +#endif + +} FormData_pg_statistic_ext_data; + +/* ---------------- + * Form_pg_statistic_ext_data corresponds to a pointer to a tuple with + * the format of pg_statistic_ext_data relation. + * ---------------- + */ +typedef FormData_pg_statistic_ext_data *Form_pg_statistic_ext_data; + +DECLARE_TOAST(pg_statistic_ext_data, 3430, 3431); + +DECLARE_UNIQUE_INDEX_PKEY(pg_statistic_ext_data_stxoid_inh_index, 3433, StatisticExtDataStxoidInhIndexId, on pg_statistic_ext_data using btree(stxoid oid_ops, stxdinherit bool_ops)); + + +#endif /* PG_STATISTIC_EXT_DATA_H */ diff --git a/src/include/catalog/pg_subscription.h b/src/include/catalog/pg_subscription.h new file mode 100644 index 0000000..d1260f5 --- /dev/null +++ b/src/include/catalog/pg_subscription.h @@ -0,0 +1,131 @@ +/* ------------------------------------------------------------------------- + * + * pg_subscription.h + * definition of the "subscription" system catalog (pg_subscription) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_subscription.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SUBSCRIPTION_H +#define PG_SUBSCRIPTION_H + +#include "access/xlogdefs.h" +#include "catalog/genbki.h" +#include "catalog/pg_subscription_d.h" + +#include "nodes/pg_list.h" + +/* + * two_phase tri-state values. See comments atop worker.c to know more about + * these states. + */ +#define LOGICALREP_TWOPHASE_STATE_DISABLED 'd' +#define LOGICALREP_TWOPHASE_STATE_PENDING 'p' +#define LOGICALREP_TWOPHASE_STATE_ENABLED 'e' + +/* ---------------- + * pg_subscription definition. cpp turns this into + * typedef struct FormData_pg_subscription + * ---------------- + */ + +/* + * Technically, the subscriptions live inside the database, so a shared catalog + * seems weird, but the replication launcher process needs to access all of + * them to be able to start the workers, so we have to put them in a shared, + * nailed catalog. + * + * CAUTION: There is a GRANT in system_views.sql to grant public select + * access on all columns except subconninfo. When you add a new column + * here, be sure to update that (or, if the new column is not to be publicly + * readable, update associated comments and catalogs.sgml instead). + */ +CATALOG(pg_subscription,6100,SubscriptionRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6101,SubscriptionRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid; /* oid */ + + Oid subdbid BKI_LOOKUP(pg_database); /* Database the + * subscription is in. */ + + XLogRecPtr subskiplsn; /* All changes finished at this LSN are + * skipped */ + + NameData subname; /* Name of the subscription */ + + Oid subowner BKI_LOOKUP(pg_authid); /* Owner of the subscription */ + + bool subenabled; /* True if the subscription is enabled (the + * worker should be running) */ + + bool subbinary; /* True if the subscription wants the + * publisher to send data in binary */ + + bool substream; /* Stream in-progress transactions. */ + + char subtwophasestate; /* Stream two-phase transactions */ + + bool subdisableonerr; /* True if a worker error should cause the + * subscription to be disabled */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* Connection string to the publisher */ + text subconninfo BKI_FORCE_NOT_NULL; + + /* Slot name on publisher */ + NameData subslotname BKI_FORCE_NULL; + + /* Synchronous commit setting for worker */ + text subsynccommit BKI_FORCE_NOT_NULL; + + /* List of publications subscribed to */ + text subpublications[1] BKI_FORCE_NOT_NULL; +#endif +} FormData_pg_subscription; + +typedef FormData_pg_subscription *Form_pg_subscription; + +DECLARE_TOAST_WITH_MACRO(pg_subscription, 4183, 4184, PgSubscriptionToastTable, PgSubscriptionToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_subscription_oid_index, 6114, SubscriptionObjectIndexId, on pg_subscription using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_subscription_subname_index, 6115, SubscriptionNameIndexId, on pg_subscription using btree(subdbid oid_ops, subname name_ops)); + +typedef struct Subscription +{ + Oid oid; /* Oid of the subscription */ + Oid dbid; /* Oid of the database which subscription is + * in */ + XLogRecPtr skiplsn; /* All changes finished at this LSN are + * skipped */ + char *name; /* Name of the subscription */ + Oid owner; /* Oid of the subscription owner */ + bool enabled; /* Indicates if the subscription is enabled */ + bool binary; /* Indicates if the subscription wants data in + * binary format */ + bool stream; /* Allow streaming in-progress transactions. */ + char twophasestate; /* Allow streaming two-phase transactions */ + bool disableonerr; /* Indicates if the subscription should be + * automatically disabled if a worker error + * occurs */ + char *conninfo; /* Connection string to the publisher */ + char *slotname; /* Name of the replication slot */ + char *synccommit; /* Synchronous commit setting for worker */ + List *publications; /* List of publication names to subscribe to */ +} Subscription; + +extern Subscription *GetSubscription(Oid subid, bool missing_ok); +extern void FreeSubscription(Subscription *sub); +extern void DisableSubscription(Oid subid); +extern Oid get_subscription_oid(const char *subname, bool missing_ok); +extern char *get_subscription_name(Oid subid, bool missing_ok); + +extern int CountDBSubscriptions(Oid dbid); + +#endif /* PG_SUBSCRIPTION_H */ diff --git a/src/include/catalog/pg_subscription_rel.h b/src/include/catalog/pg_subscription_rel.h new file mode 100644 index 0000000..9df99c3 --- /dev/null +++ b/src/include/catalog/pg_subscription_rel.h @@ -0,0 +1,94 @@ +/* ------------------------------------------------------------------------- + * + * pg_subscription_rel.h + * definition of the system catalog containing the state for each + * replicated table in each subscription (pg_subscription_rel) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_subscription_rel.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + * ------------------------------------------------------------------------- + */ +#ifndef PG_SUBSCRIPTION_REL_H +#define PG_SUBSCRIPTION_REL_H + +#include "access/xlogdefs.h" +#include "catalog/genbki.h" +#include "catalog/pg_subscription_rel_d.h" +#include "nodes/pg_list.h" + +/* ---------------- + * pg_subscription_rel definition. cpp turns this into + * typedef struct FormData_pg_subscription_rel + * ---------------- + */ +CATALOG(pg_subscription_rel,6102,SubscriptionRelRelationId) +{ + Oid srsubid BKI_LOOKUP(pg_subscription); /* Oid of subscription */ + Oid srrelid BKI_LOOKUP(pg_class); /* Oid of relation */ + char srsubstate; /* state of the relation in subscription */ + + /* + * Although srsublsn is a fixed-width type, it is allowed to be NULL, so + * we prevent direct C code access to it just as for a varlena field. + */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + XLogRecPtr srsublsn BKI_FORCE_NULL; /* remote LSN of the state change + * used for synchronization + * coordination, or NULL if not + * valid */ +#endif +} FormData_pg_subscription_rel; + +typedef FormData_pg_subscription_rel *Form_pg_subscription_rel; + +DECLARE_UNIQUE_INDEX_PKEY(pg_subscription_rel_srrelid_srsubid_index, 6117, SubscriptionRelSrrelidSrsubidIndexId, on pg_subscription_rel using btree(srrelid oid_ops, srsubid oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* ---------------- + * substate constants + * ---------------- + */ +#define SUBREL_STATE_INIT 'i' /* initializing (sublsn NULL) */ +#define SUBREL_STATE_DATASYNC 'd' /* data is being synchronized (sublsn + * NULL) */ +#define SUBREL_STATE_FINISHEDCOPY 'f' /* tablesync copy phase is completed + * (sublsn NULL) */ +#define SUBREL_STATE_SYNCDONE 's' /* synchronization finished in front of + * apply (sublsn set) */ +#define SUBREL_STATE_READY 'r' /* ready (sublsn set) */ + +/* These are never stored in the catalog, we only use them for IPC. */ +#define SUBREL_STATE_UNKNOWN '\0' /* unknown state */ +#define SUBREL_STATE_SYNCWAIT 'w' /* waiting for sync */ +#define SUBREL_STATE_CATCHUP 'c' /* catching up with apply */ + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +typedef struct SubscriptionRelState +{ + Oid relid; + XLogRecPtr lsn; + char state; +} SubscriptionRelState; + +extern void AddSubscriptionRelState(Oid subid, Oid relid, char state, + XLogRecPtr sublsn); +extern void UpdateSubscriptionRelState(Oid subid, Oid relid, char state, + XLogRecPtr sublsn); +extern char GetSubscriptionRelState(Oid subid, Oid relid, XLogRecPtr *sublsn); +extern void RemoveSubscriptionRel(Oid subid, Oid relid); + +extern bool HasSubscriptionRelations(Oid subid); +extern List *GetSubscriptionRelations(Oid subid); +extern List *GetSubscriptionNotReadyRelations(Oid subid); + +#endif /* PG_SUBSCRIPTION_REL_H */ diff --git a/src/include/catalog/pg_tablespace.dat b/src/include/catalog/pg_tablespace.dat new file mode 100644 index 0000000..59234ae --- /dev/null +++ b/src/include/catalog/pg_tablespace.dat @@ -0,0 +1,20 @@ +#---------------------------------------------------------------------- +# +# pg_tablespace.dat +# Initial contents of the pg_tablespace system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_tablespace.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '1663', oid_symbol => 'DEFAULTTABLESPACE_OID', + spcname => 'pg_default', spcacl => '_null_', spcoptions => '_null_' }, +{ oid => '1664', oid_symbol => 'GLOBALTABLESPACE_OID', + spcname => 'pg_global', spcacl => '_null_', spcoptions => '_null_' }, + +] diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h new file mode 100644 index 0000000..572eeeb --- /dev/null +++ b/src/include/catalog/pg_tablespace.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * pg_tablespace.h + * definition of the "tablespace" system catalog (pg_tablespace) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_tablespace.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TABLESPACE_H +#define PG_TABLESPACE_H + +#include "catalog/genbki.h" +#include "catalog/pg_tablespace_d.h" + +/* ---------------- + * pg_tablespace definition. cpp turns this into + * typedef struct FormData_pg_tablespace + * ---------------- + */ +CATALOG(pg_tablespace,1213,TableSpaceRelationId) BKI_SHARED_RELATION +{ + Oid oid; /* oid */ + NameData spcname; /* tablespace name */ + + /* owner of tablespace */ + Oid spcowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem spcacl[1]; /* access permissions */ + text spcoptions[1]; /* per-tablespace options */ +#endif +} FormData_pg_tablespace; + +/* ---------------- + * Form_pg_tablespace corresponds to a pointer to a tuple with + * the format of pg_tablespace relation. + * ---------------- + */ +typedef FormData_pg_tablespace *Form_pg_tablespace; + +DECLARE_TOAST_WITH_MACRO(pg_tablespace, 4185, 4186, PgTablespaceToastTable, PgTablespaceToastIndex); + +DECLARE_UNIQUE_INDEX_PKEY(pg_tablespace_oid_index, 2697, TablespaceOidIndexId, on pg_tablespace using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_tablespace_spcname_index, 2698, TablespaceNameIndexId, on pg_tablespace using btree(spcname name_ops)); + +#endif /* PG_TABLESPACE_H */ diff --git a/src/include/catalog/pg_transform.h b/src/include/catalog/pg_transform.h new file mode 100644 index 0000000..2a02691 --- /dev/null +++ b/src/include/catalog/pg_transform.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * pg_transform.h + * definition of the "transform" system catalog (pg_transform) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_transform.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TRANSFORM_H +#define PG_TRANSFORM_H + +#include "catalog/genbki.h" +#include "catalog/pg_transform_d.h" + +/* ---------------- + * pg_transform definition. cpp turns this into + * typedef struct FormData_pg_transform + * ---------------- + */ +CATALOG(pg_transform,3576,TransformRelationId) +{ + Oid oid; /* oid */ + Oid trftype BKI_LOOKUP(pg_type); + Oid trflang BKI_LOOKUP(pg_language); + regproc trffromsql BKI_LOOKUP_OPT(pg_proc); + regproc trftosql BKI_LOOKUP_OPT(pg_proc); +} FormData_pg_transform; + +/* ---------------- + * Form_pg_transform corresponds to a pointer to a tuple with + * the format of pg_transform relation. + * ---------------- + */ +typedef FormData_pg_transform *Form_pg_transform; + +DECLARE_UNIQUE_INDEX_PKEY(pg_transform_oid_index, 3574, TransformOidIndexId, on pg_transform using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_transform_type_lang_index, 3575, TransformTypeLangIndexId, on pg_transform using btree(trftype oid_ops, trflang oid_ops)); + +#endif /* PG_TRANSFORM_H */ diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h new file mode 100644 index 0000000..194277b --- /dev/null +++ b/src/include/catalog/pg_trigger.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- + * + * pg_trigger.h + * definition of the "trigger" system catalog (pg_trigger) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_trigger.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TRIGGER_H +#define PG_TRIGGER_H + +#include "catalog/genbki.h" +#include "catalog/pg_trigger_d.h" + +/* ---------------- + * pg_trigger definition. cpp turns this into + * typedef struct FormData_pg_trigger + * + * Note: when tgconstraint is nonzero, tgconstrrelid, tgconstrindid, + * tgdeferrable, and tginitdeferred are largely redundant with the referenced + * pg_constraint entry. However, it is possible for a non-deferrable trigger + * to be associated with a deferrable constraint. + * ---------------- + */ +CATALOG(pg_trigger,2620,TriggerRelationId) +{ + Oid oid; /* oid */ + Oid tgrelid BKI_LOOKUP(pg_class); /* relation trigger is + * attached to */ + Oid tgparentid BKI_LOOKUP_OPT(pg_trigger); /* OID of parent + * trigger, if any */ + NameData tgname; /* trigger's name */ + Oid tgfoid BKI_LOOKUP(pg_proc); /* OID of function to be called */ + int16 tgtype; /* BEFORE/AFTER/INSTEAD, UPDATE/DELETE/INSERT, + * ROW/STATEMENT; see below */ + char tgenabled; /* trigger's firing configuration WRT + * session_replication_role */ + bool tgisinternal; /* trigger is system-generated */ + Oid tgconstrrelid BKI_LOOKUP_OPT(pg_class); /* constraint's FROM + * table, if any */ + Oid tgconstrindid BKI_LOOKUP_OPT(pg_class); /* constraint's + * supporting index, if + * any */ + Oid tgconstraint BKI_LOOKUP_OPT(pg_constraint); /* associated + * pg_constraint entry, + * if any */ + bool tgdeferrable; /* constraint trigger is deferrable */ + bool tginitdeferred; /* constraint trigger is deferred initially */ + int16 tgnargs; /* # of extra arguments in tgargs */ + + /* + * Variable-length fields start here, but we allow direct access to + * tgattr. Note: tgattr and tgargs must not be null. + */ + int2vector tgattr BKI_FORCE_NOT_NULL; /* column numbers, if trigger is + * on columns */ + +#ifdef CATALOG_VARLEN + bytea tgargs BKI_FORCE_NOT_NULL; /* first\000second\000tgnargs\000 */ + pg_node_tree tgqual; /* WHEN expression, or NULL if none */ + NameData tgoldtable; /* old transition table, or NULL if none */ + NameData tgnewtable; /* new transition table, or NULL if none */ +#endif +} FormData_pg_trigger; + +/* ---------------- + * Form_pg_trigger corresponds to a pointer to a tuple with + * the format of pg_trigger relation. + * ---------------- + */ +typedef FormData_pg_trigger *Form_pg_trigger; + +DECLARE_TOAST(pg_trigger, 2336, 2337); + +DECLARE_INDEX(pg_trigger_tgconstraint_index, 2699, TriggerConstraintIndexId, on pg_trigger using btree(tgconstraint oid_ops)); +DECLARE_UNIQUE_INDEX(pg_trigger_tgrelid_tgname_index, 2701, TriggerRelidNameIndexId, on pg_trigger using btree(tgrelid oid_ops, tgname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_trigger_oid_index, 2702, TriggerOidIndexId, on pg_trigger using btree(oid oid_ops)); + +DECLARE_ARRAY_FOREIGN_KEY((tgrelid, tgattr), pg_attribute, (attrelid, attnum)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* Bits within tgtype */ +#define TRIGGER_TYPE_ROW (1 << 0) +#define TRIGGER_TYPE_BEFORE (1 << 1) +#define TRIGGER_TYPE_INSERT (1 << 2) +#define TRIGGER_TYPE_DELETE (1 << 3) +#define TRIGGER_TYPE_UPDATE (1 << 4) +#define TRIGGER_TYPE_TRUNCATE (1 << 5) +#define TRIGGER_TYPE_INSTEAD (1 << 6) + +#define TRIGGER_TYPE_LEVEL_MASK (TRIGGER_TYPE_ROW) +#define TRIGGER_TYPE_STATEMENT 0 + +/* Note bits within TRIGGER_TYPE_TIMING_MASK aren't adjacent */ +#define TRIGGER_TYPE_TIMING_MASK \ + (TRIGGER_TYPE_BEFORE | TRIGGER_TYPE_INSTEAD) +#define TRIGGER_TYPE_AFTER 0 + +#define TRIGGER_TYPE_EVENT_MASK \ + (TRIGGER_TYPE_INSERT | TRIGGER_TYPE_DELETE | TRIGGER_TYPE_UPDATE | TRIGGER_TYPE_TRUNCATE) + +/* Macros for manipulating tgtype */ +#define TRIGGER_CLEAR_TYPE(type) ((type) = 0) + +#define TRIGGER_SETT_ROW(type) ((type) |= TRIGGER_TYPE_ROW) +#define TRIGGER_SETT_STATEMENT(type) ((type) |= TRIGGER_TYPE_STATEMENT) +#define TRIGGER_SETT_BEFORE(type) ((type) |= TRIGGER_TYPE_BEFORE) +#define TRIGGER_SETT_AFTER(type) ((type) |= TRIGGER_TYPE_AFTER) +#define TRIGGER_SETT_INSTEAD(type) ((type) |= TRIGGER_TYPE_INSTEAD) +#define TRIGGER_SETT_INSERT(type) ((type) |= TRIGGER_TYPE_INSERT) +#define TRIGGER_SETT_DELETE(type) ((type) |= TRIGGER_TYPE_DELETE) +#define TRIGGER_SETT_UPDATE(type) ((type) |= TRIGGER_TYPE_UPDATE) +#define TRIGGER_SETT_TRUNCATE(type) ((type) |= TRIGGER_TYPE_TRUNCATE) + +#define TRIGGER_FOR_ROW(type) ((type) & TRIGGER_TYPE_ROW) +#define TRIGGER_FOR_BEFORE(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_BEFORE) +#define TRIGGER_FOR_AFTER(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_AFTER) +#define TRIGGER_FOR_INSTEAD(type) (((type) & TRIGGER_TYPE_TIMING_MASK) == TRIGGER_TYPE_INSTEAD) +#define TRIGGER_FOR_INSERT(type) ((type) & TRIGGER_TYPE_INSERT) +#define TRIGGER_FOR_DELETE(type) ((type) & TRIGGER_TYPE_DELETE) +#define TRIGGER_FOR_UPDATE(type) ((type) & TRIGGER_TYPE_UPDATE) +#define TRIGGER_FOR_TRUNCATE(type) ((type) & TRIGGER_TYPE_TRUNCATE) + +/* + * Efficient macro for checking if tgtype matches a particular level + * (TRIGGER_TYPE_ROW or TRIGGER_TYPE_STATEMENT), timing (TRIGGER_TYPE_BEFORE, + * TRIGGER_TYPE_AFTER or TRIGGER_TYPE_INSTEAD), and event (TRIGGER_TYPE_INSERT, + * TRIGGER_TYPE_DELETE, TRIGGER_TYPE_UPDATE, or TRIGGER_TYPE_TRUNCATE). Note + * that a tgtype can match more than one event, but only one level or timing. + */ +#define TRIGGER_TYPE_MATCHES(type, level, timing, event) \ + (((type) & (TRIGGER_TYPE_LEVEL_MASK | TRIGGER_TYPE_TIMING_MASK | (event))) == ((level) | (timing) | (event))) + +/* + * Macro to determine whether tgnewtable or tgoldtable has been specified for + * a trigger. + */ +#define TRIGGER_USES_TRANSITION_TABLE(namepointer) \ + ((namepointer) != (char *) NULL) + +#endif /* EXPOSE_TO_CLIENT_CODE */ + +#endif /* PG_TRIGGER_H */ diff --git a/src/include/catalog/pg_ts_config.dat b/src/include/catalog/pg_ts_config.dat new file mode 100644 index 0000000..1bbcfe3 --- /dev/null +++ b/src/include/catalog/pg_ts_config.dat @@ -0,0 +1,18 @@ +#---------------------------------------------------------------------- +# +# pg_ts_config.dat +# Initial contents of the pg_ts_config system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_ts_config.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '3748', descr => 'simple configuration', + cfgname => 'simple', cfgparser => 'default' }, + +] diff --git a/src/include/catalog/pg_ts_config.h b/src/include/catalog/pg_ts_config.h new file mode 100644 index 0000000..e5a3084 --- /dev/null +++ b/src/include/catalog/pg_ts_config.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_config.h + * definition of the "text search configuration" system catalog + * (pg_ts_config) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_ts_config.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_CONFIG_H +#define PG_TS_CONFIG_H + +#include "catalog/genbki.h" +#include "catalog/pg_ts_config_d.h" + +/* ---------------- + * pg_ts_config definition. cpp turns this into + * typedef struct FormData_pg_ts_config + * ---------------- + */ +CATALOG(pg_ts_config,3602,TSConfigRelationId) +{ + /* oid */ + Oid oid; + + /* name of configuration */ + NameData cfgname; + + /* name space */ + Oid cfgnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner */ + Oid cfgowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* OID of parser */ + Oid cfgparser BKI_LOOKUP(pg_ts_parser); +} FormData_pg_ts_config; + +typedef FormData_pg_ts_config *Form_pg_ts_config; + +DECLARE_UNIQUE_INDEX(pg_ts_config_cfgname_index, 3608, TSConfigNameNspIndexId, on pg_ts_config using btree(cfgname name_ops, cfgnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_config_oid_index, 3712, TSConfigOidIndexId, on pg_ts_config using btree(oid oid_ops)); + +#endif /* PG_TS_CONFIG_H */ diff --git a/src/include/catalog/pg_ts_config_map.dat b/src/include/catalog/pg_ts_config_map.dat new file mode 100644 index 0000000..ede0166 --- /dev/null +++ b/src/include/catalog/pg_ts_config_map.dat @@ -0,0 +1,54 @@ +#---------------------------------------------------------------------- +# +# pg_ts_config_map.dat +# Initial contents of the pg_ts_config_map system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_ts_config_map.dat +# +#---------------------------------------------------------------------- + +[ + +{ mapcfg => 'simple', maptokentype => '1', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '2', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '3', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '4', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '5', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '6', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '7', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '8', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '9', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '10', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '11', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '15', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '16', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '17', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '18', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '19', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '20', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '21', mapseqno => '1', + mapdict => 'simple' }, +{ mapcfg => 'simple', maptokentype => '22', mapseqno => '1', + mapdict => 'simple' }, + +] diff --git a/src/include/catalog/pg_ts_config_map.h b/src/include/catalog/pg_ts_config_map.h new file mode 100644 index 0000000..c10e0c5 --- /dev/null +++ b/src/include/catalog/pg_ts_config_map.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_config_map.h + * definition of the system catalog for text search token mappings + * (pg_ts_config_map) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_ts_config_map.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_CONFIG_MAP_H +#define PG_TS_CONFIG_MAP_H + +#include "catalog/genbki.h" +#include "catalog/pg_ts_config_map_d.h" + +/* ---------------- + * pg_ts_config_map definition. cpp turns this into + * typedef struct FormData_pg_ts_config_map + * ---------------- + */ +CATALOG(pg_ts_config_map,3603,TSConfigMapRelationId) +{ + /* OID of configuration owning this entry */ + Oid mapcfg BKI_LOOKUP(pg_ts_config); + + /* token type from parser */ + int32 maptokentype; + + /* order in which to consult dictionaries */ + int32 mapseqno; + + /* dictionary to consult */ + Oid mapdict BKI_LOOKUP(pg_ts_dict); +} FormData_pg_ts_config_map; + +typedef FormData_pg_ts_config_map *Form_pg_ts_config_map; + +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_config_map_index, 3609, TSConfigMapIndexId, on pg_ts_config_map using btree(mapcfg oid_ops, maptokentype int4_ops, mapseqno int4_ops)); + +#endif /* PG_TS_CONFIG_MAP_H */ diff --git a/src/include/catalog/pg_ts_dict.dat b/src/include/catalog/pg_ts_dict.dat new file mode 100644 index 0000000..c9b0e66 --- /dev/null +++ b/src/include/catalog/pg_ts_dict.dat @@ -0,0 +1,19 @@ +#---------------------------------------------------------------------- +# +# pg_ts_dict.dat +# Initial contents of the pg_ts_dict system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_ts_dict.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '3765', + descr => 'simple dictionary: just lower case and check for stopword', + dictname => 'simple', dicttemplate => 'simple', dictinitoption => '_null_' }, + +] diff --git a/src/include/catalog/pg_ts_dict.h b/src/include/catalog/pg_ts_dict.h new file mode 100644 index 0000000..4b6188f --- /dev/null +++ b/src/include/catalog/pg_ts_dict.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_dict.h + * definition of the "text search dictionary" system catalog (pg_ts_dict) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_ts_dict.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_DICT_H +#define PG_TS_DICT_H + +#include "catalog/genbki.h" +#include "catalog/pg_ts_dict_d.h" + +/* ---------------- + * pg_ts_dict definition. cpp turns this into + * typedef struct FormData_pg_ts_dict + * ---------------- + */ +CATALOG(pg_ts_dict,3600,TSDictionaryRelationId) +{ + /* oid */ + Oid oid; + + /* dictionary name */ + NameData dictname; + + /* name space */ + Oid dictnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner */ + Oid dictowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* dictionary's template */ + Oid dicttemplate BKI_LOOKUP(pg_ts_template); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + /* options passed to dict_init() */ + text dictinitoption; +#endif +} FormData_pg_ts_dict; + +typedef FormData_pg_ts_dict *Form_pg_ts_dict; + +DECLARE_TOAST(pg_ts_dict, 4169, 4170); + +DECLARE_UNIQUE_INDEX(pg_ts_dict_dictname_index, 3604, TSDictionaryNameNspIndexId, on pg_ts_dict using btree(dictname name_ops, dictnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_dict_oid_index, 3605, TSDictionaryOidIndexId, on pg_ts_dict using btree(oid oid_ops)); + +#endif /* PG_TS_DICT_H */ diff --git a/src/include/catalog/pg_ts_parser.dat b/src/include/catalog/pg_ts_parser.dat new file mode 100644 index 0000000..d1fdc02 --- /dev/null +++ b/src/include/catalog/pg_ts_parser.dat @@ -0,0 +1,20 @@ +#---------------------------------------------------------------------- +# +# pg_ts_parser.dat +# Initial contents of the pg_ts_parser system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_ts_parser.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '3722', descr => 'default word parser', + prsname => 'default', prsstart => 'prsd_start', prstoken => 'prsd_nexttoken', + prsend => 'prsd_end', prsheadline => 'prsd_headline', + prslextype => 'prsd_lextype' }, + +] diff --git a/src/include/catalog/pg_ts_parser.h b/src/include/catalog/pg_ts_parser.h new file mode 100644 index 0000000..c2d474d --- /dev/null +++ b/src/include/catalog/pg_ts_parser.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_parser.h + * definition of the "text search parser" system catalog (pg_ts_parser) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_ts_parser.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_PARSER_H +#define PG_TS_PARSER_H + +#include "catalog/genbki.h" +#include "catalog/pg_ts_parser_d.h" + +/* ---------------- + * pg_ts_parser definition. cpp turns this into + * typedef struct FormData_pg_ts_parser + * ---------------- + */ +CATALOG(pg_ts_parser,3601,TSParserRelationId) +{ + Oid oid; /* oid */ + + /* parser's name */ + NameData prsname; + + /* name space */ + Oid prsnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* init parsing session */ + regproc prsstart BKI_LOOKUP(pg_proc); + + /* return next token */ + regproc prstoken BKI_LOOKUP(pg_proc); + + /* finalize parsing session */ + regproc prsend BKI_LOOKUP(pg_proc); + + /* return data for headline creation */ + regproc prsheadline BKI_LOOKUP_OPT(pg_proc); + + /* return descriptions of lexeme's types */ + regproc prslextype BKI_LOOKUP(pg_proc); +} FormData_pg_ts_parser; + +typedef FormData_pg_ts_parser *Form_pg_ts_parser; + +DECLARE_UNIQUE_INDEX(pg_ts_parser_prsname_index, 3606, TSParserNameNspIndexId, on pg_ts_parser using btree(prsname name_ops, prsnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_parser_oid_index, 3607, TSParserOidIndexId, on pg_ts_parser using btree(oid oid_ops)); + +#endif /* PG_TS_PARSER_H */ diff --git a/src/include/catalog/pg_ts_template.dat b/src/include/catalog/pg_ts_template.dat new file mode 100644 index 0000000..edc01c0 --- /dev/null +++ b/src/include/catalog/pg_ts_template.dat @@ -0,0 +1,30 @@ +#---------------------------------------------------------------------- +# +# pg_ts_template.dat +# Initial contents of the pg_ts_template system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_ts_template.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '3727', + descr => 'simple dictionary: just lower case and check for stopword', + tmplname => 'simple', tmplinit => 'dsimple_init', + tmpllexize => 'dsimple_lexize' }, +{ oid => '3730', descr => 'synonym dictionary: replace word by its synonym', + tmplname => 'synonym', tmplinit => 'dsynonym_init', + tmpllexize => 'dsynonym_lexize' }, +{ oid => '3733', descr => 'ispell dictionary', + tmplname => 'ispell', tmplinit => 'dispell_init', + tmpllexize => 'dispell_lexize' }, +{ oid => '3742', + descr => 'thesaurus dictionary: phrase by phrase substitution', + tmplname => 'thesaurus', tmplinit => 'thesaurus_init', + tmpllexize => 'thesaurus_lexize' }, + +] diff --git a/src/include/catalog/pg_ts_template.h b/src/include/catalog/pg_ts_template.h new file mode 100644 index 0000000..2a553fe --- /dev/null +++ b/src/include/catalog/pg_ts_template.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * pg_ts_template.h + * definition of the "text search template" system catalog (pg_ts_template) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_ts_template.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TS_TEMPLATE_H +#define PG_TS_TEMPLATE_H + +#include "catalog/genbki.h" +#include "catalog/pg_ts_template_d.h" + +/* ---------------- + * pg_ts_template definition. cpp turns this into + * typedef struct FormData_pg_ts_template + * ---------------- + */ +CATALOG(pg_ts_template,3764,TSTemplateRelationId) +{ + Oid oid; /* oid */ + + /* template name */ + NameData tmplname; + + /* name space */ + Oid tmplnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* initialization method of dict (may be 0) */ + regproc tmplinit BKI_LOOKUP_OPT(pg_proc); + + /* base method of dictionary */ + regproc tmpllexize BKI_LOOKUP(pg_proc); +} FormData_pg_ts_template; + +typedef FormData_pg_ts_template *Form_pg_ts_template; + +DECLARE_UNIQUE_INDEX(pg_ts_template_tmplname_index, 3766, TSTemplateNameNspIndexId, on pg_ts_template using btree(tmplname name_ops, tmplnamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_ts_template_oid_index, 3767, TSTemplateOidIndexId, on pg_ts_template using btree(oid oid_ops)); + +#endif /* PG_TS_TEMPLATE_H */ diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat new file mode 100644 index 0000000..df45879 --- /dev/null +++ b/src/include/catalog/pg_type.dat @@ -0,0 +1,695 @@ +#---------------------------------------------------------------------- +# +# pg_type.dat +# Initial contents of the pg_type system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_type.dat +# +#---------------------------------------------------------------------- + +[ + +# For types used in the system catalogs, make sure the values here match +# TypInfo[] in bootstrap.c. + +# OID symbol macro names for pg_type OIDs are not specified here because +# they are generated by genbki.pl according to the following rule: +# foo_bar -> FOO_BAROID +# _foo_bar -> FOO_BARARRAYOID + +# To autogenerate an array type, add 'array_type_oid => 'nnnn' to the element +# type, which will instruct genbki.pl to generate a BKI entry for it. +# In a few cases, the array type's properties don't match the normal pattern +# so it can't be autogenerated; in such cases do not write array_type_oid. + +# Once upon a time these entries were ordered by OID. Lately it's often +# been the custom to insert new entries adjacent to related older entries. +# Try to do one or the other though, don't just insert entries at random. + +# OIDS 1 - 99 + +{ oid => '16', array_type_oid => '1000', + descr => 'boolean, \'true\'/\'false\'', + typname => 'bool', typlen => '1', typbyval => 't', typcategory => 'B', + typispreferred => 't', typinput => 'boolin', typoutput => 'boolout', + typreceive => 'boolrecv', typsend => 'boolsend', typalign => 'c' }, +{ oid => '17', array_type_oid => '1001', + descr => 'variable-length string, binary values escaped', + typname => 'bytea', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'byteain', typoutput => 'byteaout', typreceive => 'bytearecv', + typsend => 'byteasend', typalign => 'i', typstorage => 'x' }, +{ oid => '18', array_type_oid => '1002', descr => 'single character', + typname => 'char', typlen => '1', typbyval => 't', typcategory => 'Z', + typinput => 'charin', typoutput => 'charout', typreceive => 'charrecv', + typsend => 'charsend', typalign => 'c' }, +{ oid => '19', array_type_oid => '1003', + descr => '63-byte type for storing system identifiers', + typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f', + typcategory => 'S', typsubscript => 'raw_array_subscript_handler', + typelem => 'char', typinput => 'namein', typoutput => 'nameout', + typreceive => 'namerecv', typsend => 'namesend', typalign => 'c', + typcollation => 'C' }, +{ oid => '20', array_type_oid => '1016', + descr => '~18 digit integer, 8-byte storage', + typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'N', typinput => 'int8in', typoutput => 'int8out', + typreceive => 'int8recv', typsend => 'int8send', typalign => 'd' }, +{ oid => '21', array_type_oid => '1005', + descr => '-32 thousand to 32 thousand, 2-byte storage', + typname => 'int2', typlen => '2', typbyval => 't', typcategory => 'N', + typinput => 'int2in', typoutput => 'int2out', typreceive => 'int2recv', + typsend => 'int2send', typalign => 's' }, +{ oid => '22', array_type_oid => '1006', + descr => 'array of int2, used in system tables', + typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A', + typsubscript => 'array_subscript_handler', typelem => 'int2', + typinput => 'int2vectorin', typoutput => 'int2vectorout', + typreceive => 'int2vectorrecv', typsend => 'int2vectorsend', + typalign => 'i' }, +{ oid => '23', array_type_oid => '1007', + descr => '-2 billion to 2 billion integer, 4-byte storage', + typname => 'int4', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'int4in', typoutput => 'int4out', typreceive => 'int4recv', + typsend => 'int4send', typalign => 'i' }, +{ oid => '24', array_type_oid => '1008', descr => 'registered procedure', + typname => 'regproc', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regprocin', typoutput => 'regprocout', + typreceive => 'regprocrecv', typsend => 'regprocsend', typalign => 'i' }, +{ oid => '25', array_type_oid => '1009', + descr => 'variable-length string, no limit specified', + typname => 'text', typlen => '-1', typbyval => 'f', typcategory => 'S', + typispreferred => 't', typinput => 'textin', typoutput => 'textout', + typreceive => 'textrecv', typsend => 'textsend', typalign => 'i', + typstorage => 'x', typcollation => 'default' }, +{ oid => '26', array_type_oid => '1028', + descr => 'object identifier(oid), maximum 4 billion', + typname => 'oid', typlen => '4', typbyval => 't', typcategory => 'N', + typispreferred => 't', typinput => 'oidin', typoutput => 'oidout', + typreceive => 'oidrecv', typsend => 'oidsend', typalign => 'i' }, +{ oid => '27', array_type_oid => '1010', + descr => '(block, offset), physical location of tuple', + typname => 'tid', typlen => '6', typbyval => 'f', typcategory => 'U', + typinput => 'tidin', typoutput => 'tidout', typreceive => 'tidrecv', + typsend => 'tidsend', typalign => 's' }, +{ oid => '28', array_type_oid => '1011', descr => 'transaction id', + typname => 'xid', typlen => '4', typbyval => 't', typcategory => 'U', + typinput => 'xidin', typoutput => 'xidout', typreceive => 'xidrecv', + typsend => 'xidsend', typalign => 'i' }, +{ oid => '29', array_type_oid => '1012', + descr => 'command identifier type, sequence in transaction id', + typname => 'cid', typlen => '4', typbyval => 't', typcategory => 'U', + typinput => 'cidin', typoutput => 'cidout', typreceive => 'cidrecv', + typsend => 'cidsend', typalign => 'i' }, +{ oid => '30', array_type_oid => '1013', + descr => 'array of oids, used in system tables', + typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A', + typsubscript => 'array_subscript_handler', typelem => 'oid', + typinput => 'oidvectorin', typoutput => 'oidvectorout', + typreceive => 'oidvectorrecv', typsend => 'oidvectorsend', typalign => 'i' }, + +# hand-built rowtype entries for bootstrapped catalogs +# NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations +{ oid => '71', array_type_oid => '210', + typname => 'pg_type', typlen => '-1', typbyval => 'f', typtype => 'c', + typcategory => 'C', typrelid => 'pg_type', typinput => 'record_in', + typoutput => 'record_out', typreceive => 'record_recv', + typsend => 'record_send', typalign => 'd', typstorage => 'x' }, +{ oid => '75', array_type_oid => '270', + typname => 'pg_attribute', typlen => '-1', typbyval => 'f', typtype => 'c', + typcategory => 'C', typrelid => 'pg_attribute', typinput => 'record_in', + typoutput => 'record_out', typreceive => 'record_recv', + typsend => 'record_send', typalign => 'd', typstorage => 'x' }, +{ oid => '81', array_type_oid => '272', + typname => 'pg_proc', typlen => '-1', typbyval => 'f', typtype => 'c', + typcategory => 'C', typrelid => 'pg_proc', typinput => 'record_in', + typoutput => 'record_out', typreceive => 'record_recv', + typsend => 'record_send', typalign => 'd', typstorage => 'x' }, +{ oid => '83', array_type_oid => '273', + typname => 'pg_class', typlen => '-1', typbyval => 'f', typtype => 'c', + typcategory => 'C', typrelid => 'pg_class', typinput => 'record_in', + typoutput => 'record_out', typreceive => 'record_recv', + typsend => 'record_send', typalign => 'd', typstorage => 'x' }, + +# OIDS 100 - 199 + +{ oid => '114', array_type_oid => '199', descr => 'JSON stored as text', + typname => 'json', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'json_in', typoutput => 'json_out', typreceive => 'json_recv', + typsend => 'json_send', typalign => 'i', typstorage => 'x' }, +{ oid => '142', array_type_oid => '143', descr => 'XML content', + typname => 'xml', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'xml_in', typoutput => 'xml_out', typreceive => 'xml_recv', + typsend => 'xml_send', typalign => 'i', typstorage => 'x' }, +{ oid => '194', descr => 'string representing an internal node tree', + typname => 'pg_node_tree', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'pg_node_tree_in', + typoutput => 'pg_node_tree_out', typreceive => 'pg_node_tree_recv', + typsend => 'pg_node_tree_send', typalign => 'i', typstorage => 'x', + typcollation => 'default' }, +{ oid => '3361', descr => 'multivariate ndistinct coefficients', + typname => 'pg_ndistinct', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'pg_ndistinct_in', + typoutput => 'pg_ndistinct_out', typreceive => 'pg_ndistinct_recv', + typsend => 'pg_ndistinct_send', typalign => 'i', typstorage => 'x', + typcollation => 'default' }, +{ oid => '3402', descr => 'multivariate dependencies', + typname => 'pg_dependencies', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'pg_dependencies_in', + typoutput => 'pg_dependencies_out', typreceive => 'pg_dependencies_recv', + typsend => 'pg_dependencies_send', typalign => 'i', typstorage => 'x', + typcollation => 'default' }, +{ oid => '5017', descr => 'multivariate MCV list', + typname => 'pg_mcv_list', typlen => '-1', typbyval => 'f', typcategory => 'Z', + typinput => 'pg_mcv_list_in', typoutput => 'pg_mcv_list_out', + typreceive => 'pg_mcv_list_recv', typsend => 'pg_mcv_list_send', + typalign => 'i', typstorage => 'x', typcollation => 'default' }, +{ oid => '32', descr => 'internal type for passing CollectedCommand', + typname => 'pg_ddl_command', typlen => 'SIZEOF_POINTER', typbyval => 't', + typtype => 'p', typcategory => 'P', typinput => 'pg_ddl_command_in', + typoutput => 'pg_ddl_command_out', typreceive => 'pg_ddl_command_recv', + typsend => 'pg_ddl_command_send', typalign => 'ALIGNOF_POINTER' }, +{ oid => '5069', array_type_oid => '271', descr => 'full transaction id', + typname => 'xid8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'U', typinput => 'xid8in', typoutput => 'xid8out', + typreceive => 'xid8recv', typsend => 'xid8send', typalign => 'd' }, + +# OIDS 600 - 699 + +{ oid => '600', array_type_oid => '1017', + descr => 'geometric point \'(x, y)\'', + typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G', + typsubscript => 'raw_array_subscript_handler', typelem => 'float8', + typinput => 'point_in', typoutput => 'point_out', typreceive => 'point_recv', + typsend => 'point_send', typalign => 'd' }, +{ oid => '601', array_type_oid => '1018', + descr => 'geometric line segment \'(pt1,pt2)\'', + typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G', + typsubscript => 'raw_array_subscript_handler', typelem => 'point', + typinput => 'lseg_in', typoutput => 'lseg_out', typreceive => 'lseg_recv', + typsend => 'lseg_send', typalign => 'd' }, +{ oid => '602', array_type_oid => '1019', + descr => 'geometric path \'(pt1,...)\'', + typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G', + typinput => 'path_in', typoutput => 'path_out', typreceive => 'path_recv', + typsend => 'path_send', typalign => 'd', typstorage => 'x' }, +{ oid => '603', array_type_oid => '1020', + descr => 'geometric box \'(lower left,upper right)\'', + typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G', + typdelim => ';', typsubscript => 'raw_array_subscript_handler', + typelem => 'point', typinput => 'box_in', typoutput => 'box_out', + typreceive => 'box_recv', typsend => 'box_send', typalign => 'd' }, +{ oid => '604', array_type_oid => '1027', + descr => 'geometric polygon \'(pt1,...)\'', + typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G', + typinput => 'poly_in', typoutput => 'poly_out', typreceive => 'poly_recv', + typsend => 'poly_send', typalign => 'd', typstorage => 'x' }, +{ oid => '628', array_type_oid => '629', descr => 'geometric line', + typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G', + typsubscript => 'raw_array_subscript_handler', typelem => 'float8', + typinput => 'line_in', typoutput => 'line_out', typreceive => 'line_recv', + typsend => 'line_send', typalign => 'd' }, + +# OIDS 700 - 799 + +{ oid => '700', array_type_oid => '1021', + descr => 'single-precision floating point number, 4-byte storage', + typname => 'float4', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'float4in', typoutput => 'float4out', typreceive => 'float4recv', + typsend => 'float4send', typalign => 'i' }, +{ oid => '701', array_type_oid => '1022', + descr => 'double-precision floating point number, 8-byte storage', + typname => 'float8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'N', typispreferred => 't', typinput => 'float8in', + typoutput => 'float8out', typreceive => 'float8recv', typsend => 'float8send', + typalign => 'd' }, +{ oid => '705', descr => 'pseudo-type representing an undetermined type', + typname => 'unknown', typlen => '-2', typbyval => 'f', typtype => 'p', + typcategory => 'X', typinput => 'unknownin', typoutput => 'unknownout', + typreceive => 'unknownrecv', typsend => 'unknownsend', typalign => 'c' }, +{ oid => '718', array_type_oid => '719', + descr => 'geometric circle \'(center,radius)\'', + typname => 'circle', typlen => '24', typbyval => 'f', typcategory => 'G', + typinput => 'circle_in', typoutput => 'circle_out', + typreceive => 'circle_recv', typsend => 'circle_send', typalign => 'd' }, +{ oid => '790', array_type_oid => '791', + descr => 'monetary amounts, $d,ddd.cc', + typname => 'money', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'N', typinput => 'cash_in', typoutput => 'cash_out', + typreceive => 'cash_recv', typsend => 'cash_send', typalign => 'd' }, + +# OIDS 800 - 899 + +{ oid => '829', array_type_oid => '1040', + descr => 'XX:XX:XX:XX:XX:XX, MAC address', + typname => 'macaddr', typlen => '6', typbyval => 'f', typcategory => 'U', + typinput => 'macaddr_in', typoutput => 'macaddr_out', + typreceive => 'macaddr_recv', typsend => 'macaddr_send', typalign => 'i' }, +{ oid => '869', array_type_oid => '1041', + descr => 'IP address/netmask, host address, netmask optional', + typname => 'inet', typlen => '-1', typbyval => 'f', typcategory => 'I', + typispreferred => 't', typinput => 'inet_in', typoutput => 'inet_out', + typreceive => 'inet_recv', typsend => 'inet_send', typalign => 'i', + typstorage => 'm' }, +{ oid => '650', array_type_oid => '651', + descr => 'network IP address/netmask, network address', + typname => 'cidr', typlen => '-1', typbyval => 'f', typcategory => 'I', + typinput => 'cidr_in', typoutput => 'cidr_out', typreceive => 'cidr_recv', + typsend => 'cidr_send', typalign => 'i', typstorage => 'm' }, +{ oid => '774', array_type_oid => '775', + descr => 'XX:XX:XX:XX:XX:XX:XX:XX, MAC address', + typname => 'macaddr8', typlen => '8', typbyval => 'f', typcategory => 'U', + typinput => 'macaddr8_in', typoutput => 'macaddr8_out', + typreceive => 'macaddr8_recv', typsend => 'macaddr8_send', typalign => 'i' }, + +# OIDS 1000 - 1099 + +{ oid => '1033', array_type_oid => '1034', descr => 'access control list', + typname => 'aclitem', typlen => '12', typbyval => 'f', typcategory => 'U', + typinput => 'aclitemin', typoutput => 'aclitemout', typreceive => '-', + typsend => '-', typalign => 'i' }, +{ oid => '1042', array_type_oid => '1014', + descr => 'char(length), blank-padded string, fixed storage length', + typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S', + typinput => 'bpcharin', typoutput => 'bpcharout', typreceive => 'bpcharrecv', + typsend => 'bpcharsend', typmodin => 'bpchartypmodin', + typmodout => 'bpchartypmodout', typalign => 'i', typstorage => 'x', + typcollation => 'default' }, +{ oid => '1043', array_type_oid => '1015', + descr => 'varchar(length), non-blank-padded string, variable storage length', + typname => 'varchar', typlen => '-1', typbyval => 'f', typcategory => 'S', + typinput => 'varcharin', typoutput => 'varcharout', + typreceive => 'varcharrecv', typsend => 'varcharsend', + typmodin => 'varchartypmodin', typmodout => 'varchartypmodout', + typalign => 'i', typstorage => 'x', typcollation => 'default' }, +{ oid => '1082', array_type_oid => '1182', descr => 'date', + typname => 'date', typlen => '4', typbyval => 't', typcategory => 'D', + typinput => 'date_in', typoutput => 'date_out', typreceive => 'date_recv', + typsend => 'date_send', typalign => 'i' }, +{ oid => '1083', array_type_oid => '1183', descr => 'time of day', + typname => 'time', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'D', typinput => 'time_in', typoutput => 'time_out', + typreceive => 'time_recv', typsend => 'time_send', typmodin => 'timetypmodin', + typmodout => 'timetypmodout', typalign => 'd' }, + +# OIDS 1100 - 1199 + +{ oid => '1114', array_type_oid => '1115', descr => 'date and time', + typname => 'timestamp', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'D', typinput => 'timestamp_in', typoutput => 'timestamp_out', + typreceive => 'timestamp_recv', typsend => 'timestamp_send', + typmodin => 'timestamptypmodin', typmodout => 'timestamptypmodout', + typalign => 'd' }, +{ oid => '1184', array_type_oid => '1185', + descr => 'date and time with time zone', + typname => 'timestamptz', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'D', typispreferred => 't', typinput => 'timestamptz_in', + typoutput => 'timestamptz_out', typreceive => 'timestamptz_recv', + typsend => 'timestamptz_send', typmodin => 'timestamptztypmodin', + typmodout => 'timestamptztypmodout', typalign => 'd' }, +{ oid => '1186', array_type_oid => '1187', + descr => '@ <number> <units>, time interval', + typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T', + typispreferred => 't', typinput => 'interval_in', typoutput => 'interval_out', + typreceive => 'interval_recv', typsend => 'interval_send', + typmodin => 'intervaltypmodin', typmodout => 'intervaltypmodout', + typalign => 'd' }, + +# OIDS 1200 - 1299 + +{ oid => '1266', array_type_oid => '1270', + descr => 'time of day with time zone', + typname => 'timetz', typlen => '12', typbyval => 'f', typcategory => 'D', + typinput => 'timetz_in', typoutput => 'timetz_out', + typreceive => 'timetz_recv', typsend => 'timetz_send', + typmodin => 'timetztypmodin', typmodout => 'timetztypmodout', + typalign => 'd' }, + +# OIDS 1500 - 1599 + +{ oid => '1560', array_type_oid => '1561', descr => 'fixed-length bit string', + typname => 'bit', typlen => '-1', typbyval => 'f', typcategory => 'V', + typinput => 'bit_in', typoutput => 'bit_out', typreceive => 'bit_recv', + typsend => 'bit_send', typmodin => 'bittypmodin', typmodout => 'bittypmodout', + typalign => 'i', typstorage => 'x' }, +{ oid => '1562', array_type_oid => '1563', + descr => 'variable-length bit string', + typname => 'varbit', typlen => '-1', typbyval => 'f', typcategory => 'V', + typispreferred => 't', typinput => 'varbit_in', typoutput => 'varbit_out', + typreceive => 'varbit_recv', typsend => 'varbit_send', + typmodin => 'varbittypmodin', typmodout => 'varbittypmodout', typalign => 'i', + typstorage => 'x' }, + +# OIDS 1700 - 1799 + +{ oid => '1700', array_type_oid => '1231', + descr => 'numeric(precision, decimal), arbitrary precision number', + typname => 'numeric', typlen => '-1', typbyval => 'f', typcategory => 'N', + typinput => 'numeric_in', typoutput => 'numeric_out', + typreceive => 'numeric_recv', typsend => 'numeric_send', + typmodin => 'numerictypmodin', typmodout => 'numerictypmodout', + typalign => 'i', typstorage => 'm' }, + +{ oid => '1790', array_type_oid => '2201', + descr => 'reference to cursor (portal name)', + typname => 'refcursor', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'textin', typoutput => 'textout', typreceive => 'textrecv', + typsend => 'textsend', typalign => 'i', typstorage => 'x' }, + +# OIDS 2200 - 2299 + +{ oid => '2202', array_type_oid => '2207', + descr => 'registered procedure (with args)', + typname => 'regprocedure', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regprocedurein', typoutput => 'regprocedureout', + typreceive => 'regprocedurerecv', typsend => 'regproceduresend', + typalign => 'i' }, +{ oid => '2203', array_type_oid => '2208', descr => 'registered operator', + typname => 'regoper', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regoperin', typoutput => 'regoperout', + typreceive => 'regoperrecv', typsend => 'regopersend', typalign => 'i' }, +{ oid => '2204', array_type_oid => '2209', + descr => 'registered operator (with args)', + typname => 'regoperator', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regoperatorin', typoutput => 'regoperatorout', + typreceive => 'regoperatorrecv', typsend => 'regoperatorsend', + typalign => 'i' }, +{ oid => '2205', array_type_oid => '2210', descr => 'registered class', + typname => 'regclass', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regclassin', typoutput => 'regclassout', + typreceive => 'regclassrecv', typsend => 'regclasssend', typalign => 'i' }, +{ oid => '4191', array_type_oid => '4192', descr => 'registered collation', + typname => 'regcollation', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regcollationin', typoutput => 'regcollationout', + typreceive => 'regcollationrecv', typsend => 'regcollationsend', + typalign => 'i' }, +{ oid => '2206', array_type_oid => '2211', descr => 'registered type', + typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regtypein', typoutput => 'regtypeout', + typreceive => 'regtyperecv', typsend => 'regtypesend', typalign => 'i' }, +{ oid => '4096', array_type_oid => '4097', descr => 'registered role', + typname => 'regrole', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regrolein', typoutput => 'regroleout', + typreceive => 'regrolerecv', typsend => 'regrolesend', typalign => 'i' }, +{ oid => '4089', array_type_oid => '4090', descr => 'registered namespace', + typname => 'regnamespace', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regnamespacein', typoutput => 'regnamespaceout', + typreceive => 'regnamespacerecv', typsend => 'regnamespacesend', + typalign => 'i' }, + +# uuid +{ oid => '2950', array_type_oid => '2951', descr => 'UUID datatype', + typname => 'uuid', typlen => '16', typbyval => 'f', typcategory => 'U', + typinput => 'uuid_in', typoutput => 'uuid_out', typreceive => 'uuid_recv', + typsend => 'uuid_send', typalign => 'c' }, + +# pg_lsn +{ oid => '3220', array_type_oid => '3221', descr => 'PostgreSQL LSN datatype', + typname => 'pg_lsn', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'U', typinput => 'pg_lsn_in', typoutput => 'pg_lsn_out', + typreceive => 'pg_lsn_recv', typsend => 'pg_lsn_send', typalign => 'd' }, + +# text search +{ oid => '3614', array_type_oid => '3643', + descr => 'text representation for text search', + typname => 'tsvector', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'tsvectorin', typoutput => 'tsvectorout', + typreceive => 'tsvectorrecv', typsend => 'tsvectorsend', + typanalyze => 'ts_typanalyze', typalign => 'i', typstorage => 'x' }, +{ oid => '3642', array_type_oid => '3644', + descr => 'GiST index internal text representation for text search', + typname => 'gtsvector', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'gtsvectorin', typoutput => 'gtsvectorout', typreceive => '-', + typsend => '-', typalign => 'i' }, +{ oid => '3615', array_type_oid => '3645', + descr => 'query representation for text search', + typname => 'tsquery', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'tsqueryin', typoutput => 'tsqueryout', + typreceive => 'tsqueryrecv', typsend => 'tsquerysend', typalign => 'i' }, +{ oid => '3734', array_type_oid => '3735', + descr => 'registered text search configuration', + typname => 'regconfig', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regconfigin', typoutput => 'regconfigout', + typreceive => 'regconfigrecv', typsend => 'regconfigsend', typalign => 'i' }, +{ oid => '3769', array_type_oid => '3770', + descr => 'registered text search dictionary', + typname => 'regdictionary', typlen => '4', typbyval => 't', + typcategory => 'N', typinput => 'regdictionaryin', + typoutput => 'regdictionaryout', typreceive => 'regdictionaryrecv', + typsend => 'regdictionarysend', typalign => 'i' }, + +# jsonb +{ oid => '3802', array_type_oid => '3807', descr => 'Binary JSON', + typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U', + typsubscript => 'jsonb_subscript_handler', typinput => 'jsonb_in', + typoutput => 'jsonb_out', typreceive => 'jsonb_recv', typsend => 'jsonb_send', + typalign => 'i', typstorage => 'x' }, +{ oid => '4072', array_type_oid => '4073', descr => 'JSON path', + typname => 'jsonpath', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'jsonpath_in', typoutput => 'jsonpath_out', + typreceive => 'jsonpath_recv', typsend => 'jsonpath_send', typalign => 'i', + typstorage => 'x' }, + +{ oid => '2970', array_type_oid => '2949', descr => 'txid snapshot', + typname => 'txid_snapshot', typlen => '-1', typbyval => 'f', + typcategory => 'U', typinput => 'txid_snapshot_in', + typoutput => 'txid_snapshot_out', typreceive => 'txid_snapshot_recv', + typsend => 'txid_snapshot_send', typalign => 'd', typstorage => 'x' }, +{ oid => '5038', array_type_oid => '5039', descr => 'snapshot', + typname => 'pg_snapshot', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'pg_snapshot_in', typoutput => 'pg_snapshot_out', + typreceive => 'pg_snapshot_recv', typsend => 'pg_snapshot_send', + typalign => 'd', typstorage => 'x' }, + +# range types +{ oid => '3904', array_type_oid => '3905', descr => 'range of integers', + typname => 'int4range', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, +{ oid => '3906', array_type_oid => '3907', descr => 'range of numerics', + typname => 'numrange', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, +{ oid => '3908', array_type_oid => '3909', + descr => 'range of timestamps without time zone', + typname => 'tsrange', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, +{ oid => '3910', array_type_oid => '3911', + descr => 'range of timestamps with time zone', + typname => 'tstzrange', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, +{ oid => '3912', array_type_oid => '3913', descr => 'range of dates', + typname => 'daterange', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'i', typstorage => 'x' }, +{ oid => '3926', array_type_oid => '3927', descr => 'range of bigints', + typname => 'int8range', typlen => '-1', typbyval => 'f', typtype => 'r', + typcategory => 'R', typinput => 'range_in', typoutput => 'range_out', + typreceive => 'range_recv', typsend => 'range_send', + typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, + +# multirange types +{ oid => '4451', array_type_oid => '6150', descr => 'multirange of integers', + typname => 'int4multirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4532', array_type_oid => '6151', descr => 'multirange of numerics', + typname => 'nummultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4533', array_type_oid => '6152', + descr => 'multirange of timestamps without time zone', + typname => 'tsmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, +{ oid => '4534', array_type_oid => '6153', + descr => 'multirange of timestamps with time zone', + typname => 'tstzmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, +{ oid => '4535', array_type_oid => '6155', descr => 'multirange of dates', + typname => 'datemultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4536', array_type_oid => '6157', descr => 'multirange of bigints', + typname => 'int8multirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, + +# pseudo-types +# types with typtype='p' represent various special cases in the type system. +# These cannot be used to define table columns, but are valid as function +# argument and result types (if supported by the function's implementation +# language). +# Note: cstring is a borderline case; it is still considered a pseudo-type, +# but there is now support for it in records and arrays. Perhaps we should +# just treat it as a regular base type? + +{ oid => '2249', descr => 'pseudo-type representing any composite type', + typname => 'record', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typarray => '_record', typinput => 'record_in', + typoutput => 'record_out', typreceive => 'record_recv', + typsend => 'record_send', typalign => 'd', typstorage => 'x' }, +# Arrays of records have typcategory P, so they can't be autogenerated. +{ oid => '2287', + typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typsubscript => 'array_subscript_handler', + typelem => 'record', typinput => 'array_in', typoutput => 'array_out', + typreceive => 'array_recv', typsend => 'array_send', + typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, +{ oid => '2275', array_type_oid => '1263', descr => 'C-style string', + typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p', + typcategory => 'P', typinput => 'cstring_in', typoutput => 'cstring_out', + typreceive => 'cstring_recv', typsend => 'cstring_send', typalign => 'c' }, +{ oid => '2276', descr => 'pseudo-type representing any type', + typname => 'any', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'any_in', typoutput => 'any_out', + typreceive => '-', typsend => '-', typalign => 'i' }, +{ oid => '2277', descr => 'pseudo-type representing a polymorphic array type', + typname => 'anyarray', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typinput => 'anyarray_in', typoutput => 'anyarray_out', + typreceive => 'anyarray_recv', typsend => 'anyarray_send', typalign => 'd', + typstorage => 'x' }, +{ oid => '2278', + descr => 'pseudo-type for the result of a function with no real result', + typname => 'void', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'void_in', typoutput => 'void_out', + typreceive => 'void_recv', typsend => 'void_send', typalign => 'i' }, +{ oid => '2279', descr => 'pseudo-type for the result of a trigger function', + typname => 'trigger', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'trigger_in', typoutput => 'trigger_out', + typreceive => '-', typsend => '-', typalign => 'i' }, +{ oid => '3838', + descr => 'pseudo-type for the result of an event trigger function', + typname => 'event_trigger', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'event_trigger_in', + typoutput => 'event_trigger_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '2280', + descr => 'pseudo-type for the result of a language handler function', + typname => 'language_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'language_handler_in', + typoutput => 'language_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '2281', + descr => 'pseudo-type representing an internal data structure', + typname => 'internal', typlen => 'SIZEOF_POINTER', typbyval => 't', + typtype => 'p', typcategory => 'P', typinput => 'internal_in', + typoutput => 'internal_out', typreceive => '-', typsend => '-', + typalign => 'ALIGNOF_POINTER' }, +{ oid => '2283', descr => 'pseudo-type representing a polymorphic base type', + typname => 'anyelement', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'anyelement_in', + typoutput => 'anyelement_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '2776', + descr => 'pseudo-type representing a polymorphic base type that is not an array', + typname => 'anynonarray', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'anynonarray_in', + typoutput => 'anynonarray_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '3500', + descr => 'pseudo-type representing a polymorphic base type that is an enum', + typname => 'anyenum', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'anyenum_in', typoutput => 'anyenum_out', + typreceive => '-', typsend => '-', typalign => 'i' }, +{ oid => '3115', + descr => 'pseudo-type for the result of an FDW handler function', + typname => 'fdw_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'fdw_handler_in', + typoutput => 'fdw_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '325', + descr => 'pseudo-type for the result of an index AM handler function', + typname => 'index_am_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'index_am_handler_in', + typoutput => 'index_am_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '3310', + descr => 'pseudo-type for the result of a tablesample method function', + typname => 'tsm_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'tsm_handler_in', + typoutput => 'tsm_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '269', + typname => 'table_am_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'table_am_handler_in', + typoutput => 'table_am_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '3831', + descr => 'pseudo-type representing a range over a polymorphic base type', + typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typinput => 'anyrange_in', typoutput => 'anyrange_out', + typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' }, +{ oid => '5077', + descr => 'pseudo-type representing a polymorphic common type', + typname => 'anycompatible', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'anycompatible_in', + typoutput => 'anycompatible_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '5078', + descr => 'pseudo-type representing an array of polymorphic common type elements', + typname => 'anycompatiblearray', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblearray_in', + typoutput => 'anycompatiblearray_out', + typreceive => 'anycompatiblearray_recv', typsend => 'anycompatiblearray_send', + typalign => 'd', typstorage => 'x' }, +{ oid => '5079', + descr => 'pseudo-type representing a polymorphic common type that is not an array', + typname => 'anycompatiblenonarray', typlen => '4', typbyval => 't', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblenonarray_in', + typoutput => 'anycompatiblenonarray_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '5080', + descr => 'pseudo-type representing a range over a polymorphic common type', + typname => 'anycompatiblerange', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in', + typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, +{ oid => '4537', + descr => 'pseudo-type representing a polymorphic base type that is a multirange', + typname => 'anymultirange', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typinput => 'anymultirange_in', + typoutput => 'anymultirange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, +{ oid => '4538', + descr => 'pseudo-type representing a multirange over a polymorphic common type', + typname => 'anycompatiblemultirange', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblemultirange_in', + typoutput => 'anycompatiblemultirange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, +{ oid => '4600', descr => 'BRIN bloom summary', + typname => 'pg_brin_bloom_summary', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'brin_bloom_summary_in', + typoutput => 'brin_bloom_summary_out', + typreceive => 'brin_bloom_summary_recv', typsend => 'brin_bloom_summary_send', + typalign => 'i', typstorage => 'x', typcollation => 'default' }, +{ oid => '4601', descr => 'BRIN minmax-multi summary', + typname => 'pg_brin_minmax_multi_summary', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'brin_minmax_multi_summary_in', + typoutput => 'brin_minmax_multi_summary_out', + typreceive => 'brin_minmax_multi_summary_recv', + typsend => 'brin_minmax_multi_summary_send', typalign => 'i', + typstorage => 'x', typcollation => 'default' }, +] diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h new file mode 100644 index 0000000..48a2559 --- /dev/null +++ b/src/include/catalog/pg_type.h @@ -0,0 +1,404 @@ +/*------------------------------------------------------------------------- + * + * pg_type.h + * definition of the "type" system catalog (pg_type) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_type.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TYPE_H +#define PG_TYPE_H + +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_type_d.h" +#include "nodes/nodes.h" + +/* ---------------- + * pg_type definition. cpp turns this into + * typedef struct FormData_pg_type + * + * Some of the values in a pg_type instance are copied into + * pg_attribute instances. Some parts of Postgres use the pg_type copy, + * while others use the pg_attribute copy, so they must match. + * See struct FormData_pg_attribute for details. + * ---------------- + */ +CATALOG(pg_type,1247,TypeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71,TypeRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid; /* oid */ + + /* type name */ + NameData typname; + + /* OID of namespace containing this type */ + Oid typnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* type owner */ + Oid typowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); + + /* + * For a fixed-size type, typlen is the number of bytes we use to + * represent a value of this type, e.g. 4 for an int4. But for a + * variable-length type, typlen is negative. We use -1 to indicate a + * "varlena" type (one that has a length word), -2 to indicate a + * null-terminated C string. + */ + int16 typlen BKI_ARRAY_DEFAULT(-1); + + /* + * typbyval determines whether internal Postgres routines pass a value of + * this type by value or by reference. typbyval had better be false if + * the length is not 1, 2, or 4 (or 8 on 8-byte-Datum machines). + * Variable-length types are always passed by reference. Note that + * typbyval can be false even if the length would allow pass-by-value; for + * example, type macaddr8 is pass-by-ref even when Datum is 8 bytes. + */ + bool typbyval BKI_ARRAY_DEFAULT(f); + + /* + * typtype is 'b' for a base type, 'c' for a composite type (e.g., a + * table's rowtype), 'd' for a domain, 'e' for an enum type, 'p' for a + * pseudo-type, or 'r' for a range type. (Use the TYPTYPE macros below.) + * + * If typtype is 'c', typrelid is the OID of the class' entry in pg_class. + */ + char typtype BKI_DEFAULT(b) BKI_ARRAY_DEFAULT(b); + + /* + * typcategory and typispreferred help the parser distinguish preferred + * and non-preferred coercions. The category can be any single ASCII + * character (but not \0). The categories used for built-in types are + * identified by the TYPCATEGORY macros below. + */ + + /* arbitrary type classification */ + char typcategory BKI_ARRAY_DEFAULT(A); + + /* is type "preferred" within its category? */ + bool typispreferred BKI_DEFAULT(f) BKI_ARRAY_DEFAULT(f); + + /* + * If typisdefined is false, the entry is only a placeholder (forward + * reference). We know the type's name and owner, but not yet anything + * else about it. + */ + bool typisdefined BKI_DEFAULT(t); + + /* delimiter for arrays of this type */ + char typdelim BKI_DEFAULT(','); + + /* associated pg_class OID if a composite type, else 0 */ + Oid typrelid BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_class); + + /* + * Type-specific subscripting handler. If typsubscript is 0, it means + * that this type doesn't support subscripting. Note that various parts + * of the system deem types to be "true" array types only if their + * typsubscript is array_subscript_handler. + */ + regproc typsubscript BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_subscript_handler) BKI_LOOKUP_OPT(pg_proc); + + /* + * If typelem is not 0 then it identifies another row in pg_type, defining + * the type yielded by subscripting. This should be 0 if typsubscript is + * 0. However, it can be 0 when typsubscript isn't 0, if the handler + * doesn't need typelem to determine the subscripting result type. Note + * that a typelem dependency is considered to imply physical containment + * of the element type in this type; so DDL changes on the element type + * might be restricted by the presence of this type. + */ + Oid typelem BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* + * If there is a "true" array type having this type as element type, + * typarray links to it. Zero if no associated "true" array type. + */ + Oid typarray BKI_DEFAULT(0) BKI_ARRAY_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* + * I/O conversion procedures for the datatype. + */ + + /* text format (required) */ + regproc typinput BKI_ARRAY_DEFAULT(array_in) BKI_LOOKUP(pg_proc); + regproc typoutput BKI_ARRAY_DEFAULT(array_out) BKI_LOOKUP(pg_proc); + + /* binary format (optional) */ + regproc typreceive BKI_ARRAY_DEFAULT(array_recv) BKI_LOOKUP_OPT(pg_proc); + regproc typsend BKI_ARRAY_DEFAULT(array_send) BKI_LOOKUP_OPT(pg_proc); + + /* + * I/O functions for optional type modifiers. + */ + regproc typmodin BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + regproc typmodout BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc); + + /* + * Custom ANALYZE procedure for the datatype (0 selects the default). + */ + regproc typanalyze BKI_DEFAULT(-) BKI_ARRAY_DEFAULT(array_typanalyze) BKI_LOOKUP_OPT(pg_proc); + + /* ---------------- + * typalign is the alignment required when storing a value of this + * type. It applies to storage on disk as well as most + * representations of the value inside Postgres. When multiple values + * are stored consecutively, such as in the representation of a + * complete row on disk, padding is inserted before a datum of this + * type so that it begins on the specified boundary. The alignment + * reference is the beginning of the first datum in the sequence. + * + * 'c' = CHAR alignment, ie no alignment needed. + * 's' = SHORT alignment (2 bytes on most machines). + * 'i' = INT alignment (4 bytes on most machines). + * 'd' = DOUBLE alignment (8 bytes on many machines, but by no means all). + * (Use the TYPALIGN macros below for these.) + * + * See include/access/tupmacs.h for the macros that compute these + * alignment requirements. Note also that we allow the nominal alignment + * to be violated when storing "packed" varlenas; the TOAST mechanism + * takes care of hiding that from most code. + * + * NOTE: for types used in system tables, it is critical that the + * size and alignment defined in pg_type agree with the way that the + * compiler will lay out the field in a struct representing a table row. + * ---------------- + */ + char typalign; + + /* ---------------- + * typstorage tells if the type is prepared for toasting and what + * the default strategy for attributes of this type should be. + * + * 'p' PLAIN type not prepared for toasting + * 'e' EXTERNAL external storage possible, don't try to compress + * 'x' EXTENDED try to compress and store external if required + * 'm' MAIN like 'x' but try to keep in main tuple + * (Use the TYPSTORAGE macros below for these.) + * + * Note that 'm' fields can also be moved out to secondary storage, + * but only as a last resort ('e' and 'x' fields are moved first). + * ---------------- + */ + char typstorage BKI_DEFAULT(p) BKI_ARRAY_DEFAULT(x); + + /* + * This flag represents a "NOT NULL" constraint against this datatype. + * + * If true, the attnotnull column for a corresponding table column using + * this datatype will always enforce the NOT NULL constraint. + * + * Used primarily for domain types. + */ + bool typnotnull BKI_DEFAULT(f); + + /* + * Domains use typbasetype to show the base (or domain) type that the + * domain is based on. Zero if the type is not a domain. + */ + Oid typbasetype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type); + + /* + * Domains use typtypmod to record the typmod to be applied to their base + * type (-1 if base type does not use a typmod). -1 if this type is not a + * domain. + */ + int32 typtypmod BKI_DEFAULT(-1); + + /* + * typndims is the declared number of dimensions for an array domain type + * (i.e., typbasetype is an array type). Otherwise zero. + */ + int32 typndims BKI_DEFAULT(0); + + /* + * Collation: 0 if type cannot use collations, nonzero (typically + * DEFAULT_COLLATION_OID) for collatable base types, possibly some other + * OID for domains over collatable types + */ + Oid typcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation); + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + /* + * If typdefaultbin is not NULL, it is the nodeToString representation of + * a default expression for the type. Currently this is only used for + * domains. + */ + pg_node_tree typdefaultbin BKI_DEFAULT(_null_) BKI_ARRAY_DEFAULT(_null_); + + /* + * typdefault is NULL if the type has no associated default value. If + * typdefaultbin is not NULL, typdefault must contain a human-readable + * version of the default expression represented by typdefaultbin. If + * typdefaultbin is NULL and typdefault is not, then typdefault is the + * external representation of the type's default value, which may be fed + * to the type's input converter to produce a constant. + */ + text typdefault BKI_DEFAULT(_null_) BKI_ARRAY_DEFAULT(_null_); + + /* + * Access permissions + */ + aclitem typacl[1] BKI_DEFAULT(_null_); +#endif +} FormData_pg_type; + +/* ---------------- + * Form_pg_type corresponds to a pointer to a row with + * the format of pg_type relation. + * ---------------- + */ +typedef FormData_pg_type *Form_pg_type; + +DECLARE_TOAST(pg_type, 4171, 4172); + +DECLARE_UNIQUE_INDEX_PKEY(pg_type_oid_index, 2703, TypeOidIndexId, on pg_type using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, TypeNameNspIndexId, on pg_type using btree(typname name_ops, typnamespace oid_ops)); + +#ifdef EXPOSE_TO_CLIENT_CODE + +/* + * macros for values of poor-mans-enumerated-type columns + */ +#define TYPTYPE_BASE 'b' /* base type (ordinary scalar type) */ +#define TYPTYPE_COMPOSITE 'c' /* composite (e.g., table's rowtype) */ +#define TYPTYPE_DOMAIN 'd' /* domain over another type */ +#define TYPTYPE_ENUM 'e' /* enumerated type */ +#define TYPTYPE_MULTIRANGE 'm' /* multirange type */ +#define TYPTYPE_PSEUDO 'p' /* pseudo-type */ +#define TYPTYPE_RANGE 'r' /* range type */ + +#define TYPCATEGORY_INVALID '\0' /* not an allowed category */ +#define TYPCATEGORY_ARRAY 'A' +#define TYPCATEGORY_BOOLEAN 'B' +#define TYPCATEGORY_COMPOSITE 'C' +#define TYPCATEGORY_DATETIME 'D' +#define TYPCATEGORY_ENUM 'E' +#define TYPCATEGORY_GEOMETRIC 'G' +#define TYPCATEGORY_NETWORK 'I' /* think INET */ +#define TYPCATEGORY_NUMERIC 'N' +#define TYPCATEGORY_PSEUDOTYPE 'P' +#define TYPCATEGORY_RANGE 'R' +#define TYPCATEGORY_STRING 'S' +#define TYPCATEGORY_TIMESPAN 'T' +#define TYPCATEGORY_USER 'U' +#define TYPCATEGORY_BITSTRING 'V' /* er ... "varbit"? */ +#define TYPCATEGORY_UNKNOWN 'X' +#define TYPCATEGORY_INTERNAL 'Z' + +#define TYPALIGN_CHAR 'c' /* char alignment (i.e. unaligned) */ +#define TYPALIGN_SHORT 's' /* short alignment (typically 2 bytes) */ +#define TYPALIGN_INT 'i' /* int alignment (typically 4 bytes) */ +#define TYPALIGN_DOUBLE 'd' /* double alignment (often 8 bytes) */ + +#define TYPSTORAGE_PLAIN 'p' /* type not prepared for toasting */ +#define TYPSTORAGE_EXTERNAL 'e' /* toastable, don't try to compress */ +#define TYPSTORAGE_EXTENDED 'x' /* fully toastable */ +#define TYPSTORAGE_MAIN 'm' /* like 'x' but try to store inline */ + +/* Is a type OID a polymorphic pseudotype? (Beware of multiple evaluation) */ +#define IsPolymorphicType(typid) \ + (IsPolymorphicTypeFamily1(typid) || \ + IsPolymorphicTypeFamily2(typid)) + +/* Code not part of polymorphic type resolution should not use these macros: */ +#define IsPolymorphicTypeFamily1(typid) \ + ((typid) == ANYELEMENTOID || \ + (typid) == ANYARRAYOID || \ + (typid) == ANYNONARRAYOID || \ + (typid) == ANYENUMOID || \ + (typid) == ANYRANGEOID || \ + (typid) == ANYMULTIRANGEOID) + +#define IsPolymorphicTypeFamily2(typid) \ + ((typid) == ANYCOMPATIBLEOID || \ + (typid) == ANYCOMPATIBLEARRAYOID || \ + (typid) == ANYCOMPATIBLENONARRAYOID || \ + (typid) == ANYCOMPATIBLERANGEOID || \ + (typid) == ANYCOMPATIBLEMULTIRANGEOID) + +/* Is this a "true" array type? (Requires fmgroids.h) */ +#define IsTrueArrayType(typeForm) \ + (OidIsValid((typeForm)->typelem) && \ + (typeForm)->typsubscript == F_ARRAY_SUBSCRIPT_HANDLER) + +/* + * Backwards compatibility for ancient random spellings of pg_type OID macros. + * Don't use these names in new code. + */ +#define CASHOID MONEYOID +#define LSNOID PG_LSNOID + +#endif /* EXPOSE_TO_CLIENT_CODE */ + + +extern ObjectAddress TypeShellMake(const char *typeName, + Oid typeNamespace, + Oid ownerId); + +extern ObjectAddress TypeCreate(Oid newTypeOid, + const char *typeName, + Oid typeNamespace, + Oid relationOid, + char relationKind, + Oid ownerId, + int16 internalSize, + char typeType, + char typeCategory, + bool typePreferred, + char typDelim, + Oid inputProcedure, + Oid outputProcedure, + Oid receiveProcedure, + Oid sendProcedure, + Oid typmodinProcedure, + Oid typmodoutProcedure, + Oid analyzeProcedure, + Oid subscriptProcedure, + Oid elementType, + bool isImplicitArray, + Oid arrayType, + Oid baseType, + const char *defaultTypeValue, + char *defaultTypeBin, + bool passedByValue, + char alignment, + char storage, + int32 typeMod, + int32 typNDims, + bool typeNotNull, + Oid typeCollation); + +extern void GenerateTypeDependencies(HeapTuple typeTuple, + Relation typeCatalog, + Node *defaultExpr, + void *typacl, + char relationKind, /* only for relation + * rowtypes */ + bool isImplicitArray, + bool isDependentType, + bool makeExtensionDep, + bool rebuild); + +extern void RenameTypeInternal(Oid typeOid, const char *newTypeName, + Oid typeNamespace); + +extern char *makeArrayTypeName(const char *typeName, Oid typeNamespace); + +extern bool moveArrayTypeName(Oid typeOid, const char *typeName, + Oid typeNamespace); + +extern char *makeMultirangeTypeName(const char *rangeTypeName, + Oid typeNamespace); + +#endif /* PG_TYPE_H */ diff --git a/src/include/catalog/pg_user_mapping.h b/src/include/catalog/pg_user_mapping.h new file mode 100644 index 0000000..5615061 --- /dev/null +++ b/src/include/catalog/pg_user_mapping.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * pg_user_mapping.h + * definition of the "user mapping" system catalog (pg_user_mapping) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_user_mapping.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_USER_MAPPING_H +#define PG_USER_MAPPING_H + +#include "catalog/genbki.h" +#include "catalog/pg_user_mapping_d.h" + +/* ---------------- + * pg_user_mapping definition. cpp turns this into + * typedef struct FormData_pg_user_mapping + * ---------------- + */ +CATALOG(pg_user_mapping,1418,UserMappingRelationId) +{ + Oid oid; /* oid */ + + Oid umuser BKI_LOOKUP_OPT(pg_authid); /* Id of the user, + * InvalidOid if PUBLIC is + * wanted */ + Oid umserver BKI_LOOKUP(pg_foreign_server); /* server of this + * mapping */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text umoptions[1]; /* user mapping options */ +#endif +} FormData_pg_user_mapping; + +/* ---------------- + * Form_pg_user_mapping corresponds to a pointer to a tuple with + * the format of pg_user_mapping relation. + * ---------------- + */ +typedef FormData_pg_user_mapping *Form_pg_user_mapping; + +DECLARE_TOAST(pg_user_mapping, 4173, 4174); + +DECLARE_UNIQUE_INDEX_PKEY(pg_user_mapping_oid_index, 174, UserMappingOidIndexId, on pg_user_mapping using btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, UserMappingUserServerIndexId, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops)); + +#endif /* PG_USER_MAPPING_H */ diff --git a/src/include/catalog/reformat_dat_file.pl b/src/include/catalog/reformat_dat_file.pl new file mode 100755 index 0000000..e4a105e --- /dev/null +++ b/src/include/catalog/reformat_dat_file.pl @@ -0,0 +1,312 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# reformat_dat_file.pl +# Perl script that reads in catalog data file(s) and writes out +# functionally equivalent file(s) in a standard format. +# +# In each entry of a reformatted file, metadata fields (if present) +# come first, with normal attributes starting on the following line, +# in the same order as the columns of the corresponding catalog. +# Comments and blank lines are preserved. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/reformat_dat_file.pl +# +#---------------------------------------------------------------------- + +use strict; +use warnings; + +use FindBin; +use Getopt::Long; + +# If you copy this script to somewhere other than src/include/catalog, +# you'll need to modify this "use lib" or provide a suitable -I switch. +use lib "$FindBin::RealBin/../../backend/catalog/"; +use Catalog; + +# Names of the metadata fields of a catalog entry. +# Note: oid is a normal column from a storage perspective, but it's more +# important than the rest, so it's listed first among the metadata fields. +# Note: line_number is also a metadata field, but we never write it out, +# so it's not listed here. +my @METADATA = + ('oid', 'oid_symbol', 'array_type_oid', 'descr', 'autogenerated'); + +# Process command line switches. +my $output_path = ''; +my $full_tuples = 0; + +GetOptions( + 'output=s' => \$output_path, + 'full-tuples' => \$full_tuples) || usage(); + +# Sanity check arguments. +die "No input files.\n" unless @ARGV; + +# Make sure output_path ends in a slash. +if ($output_path ne '' && substr($output_path, -1) ne '/') +{ + $output_path .= '/'; +} + +# Read all the input files into internal data structures. +# We pass data file names as arguments and then look for matching +# headers to parse the schema from. +my %catalogs; +my %catalog_data; +my @catnames; +foreach my $datfile (@ARGV) +{ + $datfile =~ /(.+)\.dat$/ + or die "Input files need to be data (.dat) files.\n"; + + my $header = "$1.h"; + die "There in no header file corresponding to $datfile" + if !-e $header; + + my $catalog = Catalog::ParseHeader($header); + my $catname = $catalog->{catname}; + my $schema = $catalog->{columns}; + + push @catnames, $catname; + $catalogs{$catname} = $catalog; + + $catalog_data{$catname} = Catalog::ParseData($datfile, $schema, 1); +} + +######################################################################## +# At this point, we have read all the data. If you are modifying this +# script for bulk editing, this is a good place to build lookup tables, +# if you need to. In the following example, the "next if !ref $row" +# check below is a hack to filter out non-hash objects. This is because +# we build the lookup tables from data that we read using the +# "preserve_formatting" parameter. +# +##Index access method lookup. +#my %amnames; +#foreach my $row (@{ $catalog_data{pg_am} }) +#{ +# next if !ref $row; +# $amnames{$row->{oid}} = $row->{amname}; +#} +######################################################################## + +# Write the data. +foreach my $catname (@catnames) +{ + my $catalog = $catalogs{$catname}; + my @attnames; + my $schema = $catalog->{columns}; + + foreach my $column (@$schema) + { + my $attname = $column->{name}; + + # We may have ordinary columns at the storage level that we still + # want to format as a special value. Exclude these from the column + # list so they are not written twice. + push @attnames, $attname + if !(grep { $_ eq $attname } @METADATA); + } + + # Write output files to specified directory. + my $datfile = "$output_path$catname.dat"; + open my $dat, '>', $datfile + or die "can't open $datfile: $!"; + + foreach my $data (@{ $catalog_data{$catname} }) + { + + # Hash ref representing a data entry. + if (ref $data eq 'HASH') + { + my %values = %$data; + + ############################################################ + # At this point we have the full tuple in memory as a hash + # and can do any operations we want. As written, it only + # removes default values, but this script can be adapted to + # do one-off bulk-editing. + ############################################################ + + if (!$full_tuples) + { + # If it's an autogenerated entry, drop it completely. + next if $values{autogenerated}; + # Else, just drop any default/computed fields. + strip_default_values(\%values, $schema, $catname); + } + + print $dat "{"; + + # Separate out metadata fields for readability. + my $metadata_str = format_hash(\%values, @METADATA); + if ($metadata_str) + { + print $dat $metadata_str; + + # User attributes start on next line. + print $dat ",\n "; + } + + my $data_str = format_hash(\%values, @attnames); + print $dat $data_str; + print $dat " },\n"; + } + + # Preserve blank lines. + elsif ($data =~ /^\s*$/) + { + print $dat "\n"; + } + + # Preserve comments or brackets that are on their own line. + elsif ($data =~ /^\s*(\[|\]|#.*?)\s*$/) + { + print $dat "$1\n"; + } + } + close $dat; +} + +# Remove column values for which there is a matching default, +# or if the value can be computed from other columns. +sub strip_default_values +{ + my ($row, $schema, $catname) = @_; + + # Delete values that match defaults. + foreach my $column (@$schema) + { + my $attname = $column->{name}; + + # It's okay if we have no oid value, since it will be assigned + # automatically before bootstrap. + die "strip_default_values: $catname.$attname undefined\n" + if !defined $row->{$attname} and $attname ne 'oid'; + + if (defined $column->{default} + and ($row->{$attname} eq $column->{default})) + { + delete $row->{$attname}; + } + } + + # Delete computed values. See AddDefaultValues() in Catalog.pm. + # Note: This must be done after deleting values matching defaults. + if ($catname eq 'pg_proc') + { + delete $row->{pronargs} if defined $row->{proargtypes}; + } + + # If a pg_type entry has an auto-generated array type, then its + # typarray field is a computed value too (see GenerateArrayTypes). + if ($catname eq 'pg_type') + { + delete $row->{typarray} if defined $row->{array_type_oid}; + } + + return; +} + +# Format the individual elements of a Perl hash into a valid string +# representation. We do this ourselves, rather than use native Perl +# facilities, so we can keep control over the exact formatting of the +# data files. +sub format_hash +{ + my $data = shift; + my @orig_attnames = @_; + + # Copy attname to new array if it has a value, so we can determine + # the last populated element. We do this because we may have default + # values or empty metadata fields. + my @attnames; + foreach my $orig_attname (@orig_attnames) + { + push @attnames, $orig_attname + if defined $data->{$orig_attname}; + } + + # When calling this function, we ether have an open-bracket or a + # leading space already. + my $char_count = 1; + + my $threshold; + my $hash_str = ''; + my $element_count = 0; + + foreach my $attname (@attnames) + { + $element_count++; + + # To limit the line to 80 chars, we need to account for the + # trailing characters. + if ($element_count == $#attnames + 1) + { + # Last element, so allow space for ' },' + $threshold = 77; + } + else + { + # Just need space for trailing comma + $threshold = 79; + } + + if ($element_count > 1) + { + $hash_str .= ','; + $char_count++; + } + + my $value = $data->{$attname}; + + # Escape single quotes. + $value =~ s/'/\\'/g; + + # Include a leading space in the key-value pair, since this will + # always go after either a comma or an additional padding space on + # the next line. + my $element = " $attname => '$value'"; + my $element_length = length($element); + + # If adding the element to the current line would expand the line + # beyond 80 chars, put it on the next line. We don't do this for + # the first element, since that would create a blank line. + if ($element_count > 1 and $char_count + $element_length > $threshold) + { + + # Put on next line with an additional space preceding. There + # are now two spaces in front of the key-value pair, lining + # it up with the line above it. + $hash_str .= "\n $element"; + $char_count = $element_length + 1; + } + else + { + $hash_str .= $element; + $char_count += $element_length; + } + } + return $hash_str; +} + +sub usage +{ + die <<EOM; +Usage: reformat_dat_file.pl [options] datafile... + +Options: + --output PATH output directory (default '.') + --full-tuples write out full tuples, including default values + +Non-option arguments are the names of input .dat files. +Updated files are written to the output directory, +possibly overwriting the input files. + +EOM +} diff --git a/src/include/catalog/renumber_oids.pl b/src/include/catalog/renumber_oids.pl new file mode 100755 index 0000000..1e33450 --- /dev/null +++ b/src/include/catalog/renumber_oids.pl @@ -0,0 +1,311 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# renumber_oids.pl +# Perl script that shifts a range of OIDs in the Postgres catalog data +# to a different range, skipping any OIDs that are already in use. +# +# Note: This does not reformat the .dat files, so you may want +# to run reformat_dat_file.pl afterwards. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/renumber_oids.pl +# +#---------------------------------------------------------------------- + +use strict; +use warnings; + +use FindBin; +use Getopt::Long; + +# Must run in src/include/catalog +chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n"; + +use lib "$FindBin::RealBin/../../backend/catalog/"; +use Catalog; + +# We'll need this number. +my $FirstGenbkiObjectId = + Catalog::FindDefinedSymbol('access/transam.h', '..', 'FirstGenbkiObjectId'); + +# Process command line switches. +my $output_path = ''; +my $first_mapped_oid = 0; +my $last_mapped_oid = $FirstGenbkiObjectId - 1; +my $target_oid = 0; + +GetOptions( + 'output=s' => \$output_path, + 'first-mapped-oid=i' => \$first_mapped_oid, + 'last-mapped-oid=i' => \$last_mapped_oid, + 'target-oid=i' => \$target_oid) || usage(); + +# Sanity check arguments. +die "Unexpected non-switch arguments.\n" if @ARGV; +die "--first-mapped-oid must be specified.\n" + if $first_mapped_oid <= 0; +die "Empty mapped OID range.\n" + if $last_mapped_oid < $first_mapped_oid; +die "--target-oid must be specified.\n" + if $target_oid <= 0; +die "--target-oid must not be within mapped OID range.\n" + if $target_oid >= $first_mapped_oid && $target_oid <= $last_mapped_oid; + +# Make sure output_path ends in a slash. +if ($output_path ne '' && substr($output_path, -1) ne '/') +{ + $output_path .= '/'; +} + +# Collect all the existing assigned OIDs (including those to be remapped). +my @header_files = glob("pg_*.h"); +my $oids = Catalog::FindAllOidsFromHeaders(@header_files); + +# Hash-ify the existing OIDs for convenient lookup. +my %oidhash; +@oidhash{@$oids} = undef; + +# Select new OIDs for existing OIDs in the mapped range. +# We do this first so that we preserve the ordering of the mapped OIDs +# (for reproducibility's sake), and so that if we fail due to running out +# of OID room, that happens before we've overwritten any files. +my %maphash; +my $next_oid = $target_oid; + +for ( + my $mapped_oid = $first_mapped_oid; + $mapped_oid <= $last_mapped_oid; + $mapped_oid++) +{ + next if !exists $oidhash{$mapped_oid}; + $next_oid++ + while ( + exists $oidhash{$next_oid} + || ( $next_oid >= $first_mapped_oid + && $next_oid <= $last_mapped_oid)); + die "Reached FirstGenbkiObjectId before assigning all OIDs.\n" + if $next_oid >= $FirstGenbkiObjectId; + $maphash{$mapped_oid} = $next_oid; + $next_oid++; +} + +die "There are no OIDs in the mapped range.\n" if $next_oid == $target_oid; + +# Read each .h file and write out modified data. +foreach my $input_file (@header_files) +{ + $input_file =~ /(\w+)\.h$/ + or die "Input file $input_file needs to be a .h file.\n"; + my $catname = $1; + + # Ignore generated *_d.h files. + next if $catname =~ /_d$/; + + open(my $ifd, '<', $input_file) || die "$input_file: $!"; + + # Write output files to specified directory. + # Use a .tmp suffix, then rename into place, in case we're overwriting. + my $output_file = "$output_path$catname.h"; + my $tmp_output_file = "$output_file.tmp"; + open my $ofd, '>', $tmp_output_file + or die "can't open $tmp_output_file: $!"; + my $changed = 0; + + # Scan the input file. + while (<$ifd>) + { + my $line = $_; + + # Check for OID-defining macros that Catalog::ParseHeader knows about, + # and update OIDs as needed. + if ($line =~ m/^(DECLARE_TOAST\(\s*\w+,\s*)(\d+)(,\s*)(\d+)\)/) + { + my $oid2 = $2; + my $oid4 = $4; + if (exists $maphash{$oid2}) + { + $oid2 = $maphash{$oid2}; + my $repl = $1 . $oid2 . $3 . $oid4 . ")"; + $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/; + $changed = 1; + } + if (exists $maphash{$oid4}) + { + $oid4 = $maphash{$oid4}; + my $repl = $1 . $oid2 . $3 . $oid4 . ")"; + $line =~ s/^DECLARE_TOAST\(\s*\w+,\s*\d+,\s*\d+\)/$repl/; + $changed = 1; + } + } + elsif ($line =~ + m/^(DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*)(\d+)(,\s*)(\d+)(,\s*\w+,\s*\w+)\)/ + ) + { + my $oid2 = $2; + my $oid4 = $4; + if (exists $maphash{$oid2}) + { + $oid2 = $maphash{$oid2}; + my $repl = $1 . $oid2 . $3 . $oid4 . $5 . ")"; + $line =~ + s/^DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*\d+,\s*\d+,\s*\w+,\s*\w+\)/$repl/; + $changed = 1; + } + if (exists $maphash{$oid4}) + { + $oid4 = $maphash{$oid4}; + my $repl = $1 . $oid2 . $3 . $oid4 . $5 . ")"; + $line =~ + s/^DECLARE_TOAST_WITH_MACRO\(\s*\w+,\s*\d+,\s*\d+,\s*\w+,\s*\w+\)/$repl/; + $changed = 1; + } + } + elsif ($line =~ + m/^(DECLARE_(UNIQUE_)?INDEX(_PKEY)?\(\s*\w+,\s*)(\d+)(,\s*.+)\)/) + { + if (exists $maphash{$4}) + { + my $repl = $1 . $maphash{$4} . $5 . ")"; + $line =~ + s/^DECLARE_(UNIQUE_)?INDEX(_PKEY)?\(\s*\w+,\s*\d+,\s*.+\)/$repl/; + $changed = 1; + } + } + elsif (/^(DECLARE_OID_DEFINING_MACRO\(\s*\w+,\s*)(\d+)\)/) + { + if (exists $maphash{$2}) + { + my $repl = $1 . $maphash{$2} . ")"; + $line =~ + s/^DECLARE_OID_DEFINING_MACRO\(\s*\w+,\s*\d+\)/$repl/; + $changed = 1; + } + } + elsif ($line =~ m/^CATALOG\((\w+),(\d+),(\w+)\)/) + { + if (exists $maphash{$2}) + { + my $repl = + "CATALOG(" . $1 . "," . $maphash{$2} . "," . $3 . ")"; + $line =~ s/^CATALOG\(\w+,\d+,\w+\)/$repl/; + $changed = 1; + } + + if ($line =~ m/BKI_ROWTYPE_OID\((\d+),(\w+)\)/) + { + if (exists $maphash{$1}) + { + my $repl = + "BKI_ROWTYPE_OID(" . $maphash{$1} . "," . $2 . ")"; + $line =~ s/BKI_ROWTYPE_OID\(\d+,\w+\)/$repl/; + $changed = 1; + } + } + } + + print $ofd $line; + } + + close $ifd; + close $ofd; + + # Avoid updating files if we didn't change them. + if ($changed || $output_path ne '') + { + rename $tmp_output_file, $output_file + or die "can't rename $tmp_output_file to $output_file: $!"; + } + else + { + unlink $tmp_output_file + or die "can't unlink $tmp_output_file: $!"; + } +} + +# Likewise, read each .dat file and write out modified data. +foreach my $input_file (glob("pg_*.dat")) +{ + $input_file =~ /(\w+)\.dat$/ + or die "Input file $input_file needs to be a .dat file.\n"; + my $catname = $1; + + open(my $ifd, '<', $input_file) || die "$input_file: $!"; + + # Write output files to specified directory. + # Use a .tmp suffix, then rename into place, in case we're overwriting. + my $output_file = "$output_path$catname.dat"; + my $tmp_output_file = "$output_file.tmp"; + open my $ofd, '>', $tmp_output_file + or die "can't open $tmp_output_file: $!"; + my $changed = 0; + + # Scan the input file. + while (<$ifd>) + { + my $line = $_; + + # Check for oid => 'nnnn', and replace if within mapped range. + if ($line =~ m/\b(oid\s*=>\s*)'(\d+)'/) + { + if (exists $maphash{$2}) + { + my $repl = $1 . "'" . $maphash{$2} . "'"; + $line =~ s/\boid\s*=>\s*'\d+'/$repl/; + $changed = 1; + } + } + + # Likewise for array_type_oid. + if ($line =~ m/\b(array_type_oid\s*=>\s*)'(\d+)'/) + { + if (exists $maphash{$2}) + { + my $repl = $1 . "'" . $maphash{$2} . "'"; + $line =~ s/\barray_type_oid\s*=>\s*'\d+'/$repl/; + $changed = 1; + } + } + + print $ofd $line; + } + + close $ifd; + close $ofd; + + # Avoid updating files if we didn't change them. + if ($changed || $output_path ne '') + { + rename $tmp_output_file, $output_file + or die "can't rename $tmp_output_file to $output_file: $!"; + } + else + { + unlink $tmp_output_file + or die "can't unlink $tmp_output_file: $!"; + } +} + +sub usage +{ + my $last = $FirstGenbkiObjectId - 1; + die <<EOM; +Usage: renumber_oids.pl [--output PATH] --first-mapped-oid X [--last-mapped-oid Y] --target-oid Z + +Options: + --output PATH output directory (default '.') + --first-mapped-oid X first OID to be moved + --last-mapped-oid Y last OID to be moved (default $last) + --target-oid Z first OID to move to + +Catalog *.h and *.dat files are updated and written to the +output directory; by default, this overwrites the input files. + +Caution: the output PATH will be interpreted relative to +src/include/catalog, even if you start the script +in some other directory. + +EOM +} diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h new file mode 100644 index 0000000..59f3404 --- /dev/null +++ b/src/include/catalog/storage.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * storage.h + * prototypes for functions in backend/catalog/storage.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/storage.h + * + *------------------------------------------------------------------------- + */ +#ifndef STORAGE_H +#define STORAGE_H + +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "storage/smgr.h" +#include "utils/relcache.h" + +/* GUC variables */ +extern PGDLLIMPORT int wal_skip_threshold; + +extern SMgrRelation RelationCreateStorage(RelFileNode rnode, + char relpersistence, + bool register_delete); +extern void RelationDropStorage(Relation rel); +extern void RelationPreserveStorage(RelFileNode rnode, bool atCommit); +extern void RelationPreTruncate(Relation rel); +extern void RelationTruncate(Relation rel, BlockNumber nblocks); +extern void RelationCopyStorage(SMgrRelation src, SMgrRelation dst, + ForkNumber forkNum, char relpersistence); +extern bool RelFileNodeSkippingWAL(RelFileNode rnode); +extern Size EstimatePendingSyncsSpace(void); +extern void SerializePendingSyncs(Size maxSize, char *startAddress); +extern void RestorePendingSyncs(char *startAddress); + +/* + * These functions used to be in storage/smgr/smgr.c, which explains the + * naming + */ +extern void smgrDoPendingDeletes(bool isCommit); +extern void smgrDoPendingSyncs(bool isCommit, bool isParallelWorker); +extern int smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr); +extern void AtSubCommit_smgr(void); +extern void AtSubAbort_smgr(void); +extern void PostPrepare_smgr(void); + +#endif /* STORAGE_H */ diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h new file mode 100644 index 0000000..622de22 --- /dev/null +++ b/src/include/catalog/storage_xlog.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * storage_xlog.h + * prototypes for XLog support for backend/catalog/storage.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/storage_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef STORAGE_XLOG_H +#define STORAGE_XLOG_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/block.h" +#include "storage/relfilenode.h" + +/* + * Declarations for smgr-related XLOG records + * + * Note: we log file creation and truncation here, but logging of deletion + * actions is handled by xact.c, because it is part of transaction commit. + */ + +/* XLOG gives us high 4 bits */ +#define XLOG_SMGR_CREATE 0x10 +#define XLOG_SMGR_TRUNCATE 0x20 + +typedef struct xl_smgr_create +{ + RelFileNode rnode; + ForkNumber forkNum; +} xl_smgr_create; + +/* flags for xl_smgr_truncate */ +#define SMGR_TRUNCATE_HEAP 0x0001 +#define SMGR_TRUNCATE_VM 0x0002 +#define SMGR_TRUNCATE_FSM 0x0004 +#define SMGR_TRUNCATE_ALL \ + (SMGR_TRUNCATE_HEAP|SMGR_TRUNCATE_VM|SMGR_TRUNCATE_FSM) + +typedef struct xl_smgr_truncate +{ + BlockNumber blkno; + RelFileNode rnode; + int flags; +} xl_smgr_truncate; + +extern void log_smgrcreate(const RelFileNode *rnode, ForkNumber forkNum); + +extern void smgr_redo(XLogReaderState *record); +extern void smgr_desc(StringInfo buf, XLogReaderState *record); +extern const char *smgr_identify(uint8 info); + +#endif /* STORAGE_XLOG_H */ diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h new file mode 100644 index 0000000..51e3ba7 --- /dev/null +++ b/src/include/catalog/toasting.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * toasting.h + * This file provides some definitions to support creation of toast tables + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/toasting.h + * + *------------------------------------------------------------------------- + */ +#ifndef TOASTING_H +#define TOASTING_H + +#include "storage/lock.h" + +/* + * toasting.c prototypes + */ +extern void NewRelationCreateToastTable(Oid relOid, Datum reloptions); +extern void NewHeapCreateToastTable(Oid relOid, Datum reloptions, + LOCKMODE lockmode, Oid OIDOldToast); +extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions, + LOCKMODE lockmode); +extern void BootstrapToastTable(char *relName, + Oid toastOid, Oid toastIndexOid); + +#endif /* TOASTING_H */ diff --git a/src/include/catalog/unused_oids b/src/include/catalog/unused_oids new file mode 100755 index 0000000..e55bc6f --- /dev/null +++ b/src/include/catalog/unused_oids @@ -0,0 +1,78 @@ +#!/usr/bin/perl +#---------------------------------------------------------------------- +# +# unused_oids +# Finds blocks of manually-assignable OIDs that have not already been +# claimed by previous hackers. The main use is for finding available +# OIDs for new internal functions. The numbers printed are inclusive +# ranges of unused OIDs. +# +# Before using a large empty block, make sure you aren't about +# to take over what was intended as expansion space for something +# else. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/unused_oids +# +#---------------------------------------------------------------------- + +use strict; +use warnings; + +# Must run in src/include/catalog +use FindBin; +chdir $FindBin::RealBin or die "could not cd to $FindBin::RealBin: $!\n"; + +use lib "$FindBin::RealBin/../../backend/catalog/"; +use Catalog; + +my @input_files = glob("pg_*.h"); + +my $oids = Catalog::FindAllOidsFromHeaders(@input_files); + +# Also push FirstGenbkiObjectId to serve as a terminator for the last gap. +my $FirstGenbkiObjectId = + Catalog::FindDefinedSymbol('access/transam.h', '..', 'FirstGenbkiObjectId'); +push @{$oids}, $FirstGenbkiObjectId; + +my $prev_oid = 0; +my @sortedoids = sort { $a <=> $b } @{$oids}; +foreach my $oid (@sortedoids) +{ + if ($oid > $prev_oid + 1) + { + if ($oid > $prev_oid + 2) + { + printf "%d - %d\n", $prev_oid + 1, $oid - 1; + } + else + { + printf "%d\n", $prev_oid + 1; + } + } + $prev_oid = $oid; +} + +my $suggestion; +do +{ + $suggestion = int(8000 + rand(2000)); +} while (grep(/^$suggestion$/, @{$oids})); + +my $navailable = 0; +foreach my $oid (@sortedoids) +{ + if ($oid > $suggestion) + { + $navailable = $oid - $suggestion; + last; + } +} + +printf "Patches should use a more-or-less consecutive range of OIDs.\n"; +printf + "Best practice is to start with a random choice in the range 8000-9999.\n"; +printf + "Suggested random unused OID: $suggestion ($navailable consecutive OID(s) available starting here)\n"; diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h new file mode 100644 index 0000000..52f5e6f --- /dev/null +++ b/src/include/commands/alter.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * alter.h + * prototypes for commands/alter.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/alter.h + * + *------------------------------------------------------------------------- + */ +#ifndef ALTER_H +#define ALTER_H + +#include "catalog/dependency.h" +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" +#include "utils/relcache.h" + +extern ObjectAddress ExecRenameStmt(RenameStmt *stmt); + +extern ObjectAddress ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, + ObjectAddress *refAddress); +extern ObjectAddress ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt, + ObjectAddress *oldSchemaAddr); +extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, + ObjectAddresses *objsMoved); + +extern ObjectAddress ExecAlterOwnerStmt(AlterOwnerStmt *stmt); +extern void AlterObjectOwner_internal(Relation catalog, Oid objectId, + Oid new_ownerId); + +#endif /* ALTER_H */ diff --git a/src/include/commands/async.h b/src/include/commands/async.h new file mode 100644 index 0000000..926af93 --- /dev/null +++ b/src/include/commands/async.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * async.h + * Asynchronous notification: NOTIFY, LISTEN, UNLISTEN + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/async.h + * + *------------------------------------------------------------------------- + */ +#ifndef ASYNC_H +#define ASYNC_H + +#include <signal.h> + +/* + * The number of SLRU page buffers we use for the notification queue. + */ +#define NUM_NOTIFY_BUFFERS 8 + +extern PGDLLIMPORT bool Trace_notify; +extern PGDLLIMPORT volatile sig_atomic_t notifyInterruptPending; + +extern Size AsyncShmemSize(void); +extern void AsyncShmemInit(void); + +extern void NotifyMyFrontEnd(const char *channel, + const char *payload, + int32 srcPid); + +/* notify-related SQL statements */ +extern void Async_Notify(const char *channel, const char *payload); +extern void Async_Listen(const char *channel); +extern void Async_Unlisten(const char *channel); +extern void Async_UnlistenAll(void); + +/* perform (or cancel) outbound notify processing at transaction commit */ +extern void PreCommit_Notify(void); +extern void AtCommit_Notify(void); +extern void AtAbort_Notify(void); +extern void AtSubCommit_Notify(void); +extern void AtSubAbort_Notify(void); +extern void AtPrepare_Notify(void); + +/* signal handler for inbound notifies (PROCSIG_NOTIFY_INTERRUPT) */ +extern void HandleNotifyInterrupt(void); + +/* process interrupts */ +extern void ProcessNotifyInterrupt(bool flush); + +#endif /* ASYNC_H */ diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h new file mode 100644 index 0000000..df8e73a --- /dev/null +++ b/src/include/commands/cluster.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * cluster.h + * header file for postgres cluster command stuff + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994-5, Regents of the University of California + * + * src/include/commands/cluster.h + * + *------------------------------------------------------------------------- + */ +#ifndef CLUSTER_H +#define CLUSTER_H + +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "storage/lock.h" +#include "utils/relcache.h" + + +/* flag bits for ClusterParams->options */ +#define CLUOPT_VERBOSE 0x01 /* print progress info */ +#define CLUOPT_RECHECK 0x02 /* recheck relation state */ +#define CLUOPT_RECHECK_ISCLUSTERED 0x04 /* recheck relation state for + * indisclustered */ + +/* options for CLUSTER */ +typedef struct ClusterParams +{ + bits32 options; /* bitmask of CLUOPT_* */ +} ClusterParams; + +extern void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel); +extern void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params); +extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, + LOCKMODE lockmode); +extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal); + +extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, + char relpersistence, LOCKMODE lockmode); +extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, + bool is_system_catalog, + bool swap_toast_by_content, + bool check_constraints, + bool is_internal, + TransactionId frozenXid, + MultiXactId minMulti, + char newrelpersistence); + +#endif /* CLUSTER_H */ diff --git a/src/include/commands/collationcmds.h b/src/include/commands/collationcmds.h new file mode 100644 index 0000000..201b19f --- /dev/null +++ b/src/include/commands/collationcmds.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * collationcmds.h + * prototypes for collationcmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/collationcmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef COLLATIONCMDS_H +#define COLLATIONCMDS_H + +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" + +extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists); +extern void IsThereCollationInNamespace(const char *collname, Oid nspOid); +extern ObjectAddress AlterCollation(AlterCollationStmt *stmt); + +#endif /* COLLATIONCMDS_H */ diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h new file mode 100644 index 0000000..2547ab0 --- /dev/null +++ b/src/include/commands/comment.h @@ -0,0 +1,45 @@ +/* + * src/include/commands/comment.h + * + *------------------------------------------------------------------------- + * + * comment.h + * + * Prototypes for functions in commands/comment.c + * + * Copyright (c) 1999-2022, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ + +#ifndef COMMENT_H +#define COMMENT_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +/*------------------------------------------------------------------ + * Function Prototypes -- + * + * The following prototypes define the public functions of the comment + * related routines. CommentObject() implements the SQL "COMMENT ON" + * command. DeleteComments() deletes all comments for an object. + * CreateComments creates (or deletes, if comment is NULL) a comment + * for a specific key. There are versions of these two methods for + * both normal and shared objects. + *------------------------------------------------------------------ + */ + +extern ObjectAddress CommentObject(CommentStmt *stmt); + +extern void DeleteComments(Oid oid, Oid classoid, int32 subid); + +extern void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment); + +extern void DeleteSharedComments(Oid oid, Oid classoid); + +extern void CreateSharedComments(Oid oid, Oid classoid, const char *comment); + +extern char *GetComment(Oid oid, Oid classoid, int32 subid); + +#endif /* COMMENT_H */ diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h new file mode 100644 index 0000000..ab736fb --- /dev/null +++ b/src/include/commands/conversioncmds.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * conversioncmds.h + * prototypes for conversioncmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/conversioncmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef CONVERSIONCMDS_H +#define CONVERSIONCMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern ObjectAddress CreateConversionCommand(CreateConversionStmt *parsetree); + +#endif /* CONVERSIONCMDS_H */ diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h new file mode 100644 index 0000000..cb0096a --- /dev/null +++ b/src/include/commands/copy.h @@ -0,0 +1,100 @@ +/*------------------------------------------------------------------------- + * + * copy.h + * Definitions for using the POSTGRES copy command. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/copy.h + * + *------------------------------------------------------------------------- + */ +#ifndef COPY_H +#define COPY_H + +#include "nodes/execnodes.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "tcop/dest.h" + +/* + * Represents whether a header line should be present, and whether it must + * match the actual names (which implies "true"). + */ +typedef enum CopyHeaderChoice +{ + COPY_HEADER_FALSE = 0, + COPY_HEADER_TRUE, + COPY_HEADER_MATCH, +} CopyHeaderChoice; + +/* + * A struct to hold COPY options, in a parsed form. All of these are related + * to formatting, except for 'freeze', which doesn't really belong here, but + * it's expedient to parse it along with all the other options. + */ +typedef struct CopyFormatOptions +{ + /* parameters from the COPY command */ + int file_encoding; /* file or remote side's character encoding, + * -1 if not specified */ + bool binary; /* binary format? */ + bool freeze; /* freeze rows on loading? */ + bool csv_mode; /* Comma Separated Value format? */ + CopyHeaderChoice header_line; /* header line? */ + char *null_print; /* NULL marker string (server encoding!) */ + int null_print_len; /* length of same */ + char *null_print_client; /* same converted to file encoding */ + char *delim; /* column delimiter (must be 1 byte) */ + char *quote; /* CSV quote char (must be 1 byte) */ + char *escape; /* CSV escape char (must be 1 byte) */ + List *force_quote; /* list of column names */ + bool force_quote_all; /* FORCE_QUOTE *? */ + bool *force_quote_flags; /* per-column CSV FQ flags */ + List *force_notnull; /* list of column names */ + bool *force_notnull_flags; /* per-column CSV FNN flags */ + List *force_null; /* list of column names */ + bool *force_null_flags; /* per-column CSV FN flags */ + bool convert_selectively; /* do selective binary conversion? */ + List *convert_select; /* list of column names (can be NIL) */ +} CopyFormatOptions; + +/* These are private in commands/copy[from|to].c */ +typedef struct CopyFromStateData *CopyFromState; +typedef struct CopyToStateData *CopyToState; + +typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread); + +extern void DoCopy(ParseState *state, const CopyStmt *stmt, + int stmt_location, int stmt_len, + uint64 *processed); + +extern void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *ops_out, bool is_from, List *options); +extern CopyFromState BeginCopyFrom(ParseState *pstate, Relation rel, Node *whereClause, + const char *filename, + bool is_program, copy_data_source_cb data_source_cb, List *attnamelist, List *options); +extern void EndCopyFrom(CopyFromState cstate); +extern bool NextCopyFrom(CopyFromState cstate, ExprContext *econtext, + Datum *values, bool *nulls); +extern bool NextCopyFromRawFields(CopyFromState cstate, + char ***fields, int *nfields); +extern void CopyFromErrorCallback(void *arg); + +extern uint64 CopyFrom(CopyFromState cstate); + +extern DestReceiver *CreateCopyDestReceiver(void); + +/* + * internal prototypes + */ +extern CopyToState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query, + Oid queryRelId, const char *filename, bool is_program, + List *attnamelist, List *options); +extern void EndCopyTo(CopyToState cstate); +extern uint64 DoCopyTo(CopyToState cstate); +extern List *CopyGetAttnums(TupleDesc tupDesc, Relation rel, + List *attnamelist); + +#endif /* COPY_H */ diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h new file mode 100644 index 0000000..3df1c5a --- /dev/null +++ b/src/include/commands/copyfrom_internal.h @@ -0,0 +1,172 @@ +/*------------------------------------------------------------------------- + * + * copyfrom_internal.h + * Internal definitions for COPY FROM command. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/copyfrom_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef COPYFROM_INTERNAL_H +#define COPYFROM_INTERNAL_H + +#include "commands/copy.h" +#include "commands/trigger.h" + +/* + * Represents the different source cases we need to worry about at + * the bottom level + */ +typedef enum CopySource +{ + COPY_FILE, /* from file (or a piped program) */ + COPY_FRONTEND, /* from frontend */ + COPY_CALLBACK /* from callback function */ +} CopySource; + +/* + * Represents the end-of-line terminator type of the input + */ +typedef enum EolType +{ + EOL_UNKNOWN, + EOL_NL, + EOL_CR, + EOL_CRNL +} EolType; + +/* + * Represents the heap insert method to be used during COPY FROM. + */ +typedef enum CopyInsertMethod +{ + CIM_SINGLE, /* use table_tuple_insert or fdw routine */ + CIM_MULTI, /* always use table_multi_insert */ + CIM_MULTI_CONDITIONAL /* use table_multi_insert only if valid */ +} CopyInsertMethod; + +/* + * This struct contains all the state variables used throughout a COPY FROM + * operation. + */ +typedef struct CopyFromStateData +{ + /* low-level state data */ + CopySource copy_src; /* type of copy source */ + FILE *copy_file; /* used if copy_src == COPY_FILE */ + StringInfo fe_msgbuf; /* used if copy_src == COPY_NEW_FE */ + + EolType eol_type; /* EOL type of input */ + int file_encoding; /* file or remote side's character encoding */ + bool need_transcoding; /* file encoding diff from server? */ + Oid conversion_proc; /* encoding conversion function */ + + /* parameters from the COPY command */ + Relation rel; /* relation to copy from */ + List *attnumlist; /* integer list of attnums to copy */ + char *filename; /* filename, or NULL for STDIN */ + bool is_program; /* is 'filename' a program to popen? */ + copy_data_source_cb data_source_cb; /* function for reading data */ + + CopyFormatOptions opts; + bool *convert_select_flags; /* per-column CSV/TEXT CS flags */ + Node *whereClause; /* WHERE condition (or NULL) */ + + /* these are just for error messages, see CopyFromErrorCallback */ + const char *cur_relname; /* table name for error messages */ + uint64 cur_lineno; /* line number for error messages */ + const char *cur_attname; /* current att for error messages */ + const char *cur_attval; /* current att value for error messages */ + + /* + * Working state + */ + MemoryContext copycontext; /* per-copy execution context */ + + AttrNumber num_defaults; + FmgrInfo *in_functions; /* array of input functions for each attrs */ + Oid *typioparams; /* array of element types for in_functions */ + int *defmap; /* array of default att numbers */ + ExprState **defexprs; /* array of default att expressions */ + bool volatile_defexprs; /* is any of defexprs volatile? */ + List *range_table; + ExprState *qualexpr; + + TransitionCaptureState *transition_capture; + + /* + * These variables are used to reduce overhead in COPY FROM. + * + * attribute_buf holds the separated, de-escaped text for each field of + * the current line. The CopyReadAttributes functions return arrays of + * pointers into this buffer. We avoid palloc/pfree overhead by re-using + * the buffer on each cycle. + * + * In binary COPY FROM, attribute_buf holds the binary data for the + * current field, but the usage is otherwise similar. + */ + StringInfoData attribute_buf; + + /* field raw data pointers found by COPY FROM */ + + int max_fields; + char **raw_fields; + + /* + * Similarly, line_buf holds the whole input line being processed. The + * input cycle is first to read the whole line into line_buf, and then + * extract the individual attribute fields into attribute_buf. line_buf + * is preserved unmodified so that we can display it in error messages if + * appropriate. (In binary mode, line_buf is not used.) + */ + StringInfoData line_buf; + bool line_buf_valid; /* contains the row being processed? */ + + /* + * input_buf holds input data, already converted to database encoding. + * + * In text mode, CopyReadLine parses this data sufficiently to locate line + * boundaries, then transfers the data to line_buf. We guarantee that + * there is a \0 at input_buf[input_buf_len] at all times. (In binary + * mode, input_buf is not used.) + * + * If encoding conversion is not required, input_buf is not a separate + * buffer but points directly to raw_buf. In that case, input_buf_len + * tracks the number of bytes that have been verified as valid in the + * database encoding, and raw_buf_len is the total number of bytes stored + * in the buffer. + */ +#define INPUT_BUF_SIZE 65536 /* we palloc INPUT_BUF_SIZE+1 bytes */ + char *input_buf; + int input_buf_index; /* next byte to process */ + int input_buf_len; /* total # of bytes stored */ + bool input_reached_eof; /* true if we reached EOF */ + bool input_reached_error; /* true if a conversion error happened */ + /* Shorthand for number of unconsumed bytes available in input_buf */ +#define INPUT_BUF_BYTES(cstate) ((cstate)->input_buf_len - (cstate)->input_buf_index) + + /* + * raw_buf holds raw input data read from the data source (file or client + * connection), not yet converted to the database encoding. Like with + * 'input_buf', we guarantee that there is a \0 at raw_buf[raw_buf_len]. + */ +#define RAW_BUF_SIZE 65536 /* we palloc RAW_BUF_SIZE+1 bytes */ + char *raw_buf; + int raw_buf_index; /* next byte to process */ + int raw_buf_len; /* total # of bytes stored */ + bool raw_reached_eof; /* true if we reached EOF */ + + /* Shorthand for number of unconsumed bytes available in raw_buf */ +#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index) + + uint64 bytes_processed; /* number of bytes processed so far */ +} CopyFromStateData; + +extern void ReceiveCopyBegin(CopyFromState cstate); +extern void ReceiveCopyBinaryHeader(CopyFromState cstate); + +#endif /* COPYFROM_INTERNAL_H */ diff --git a/src/include/commands/createas.h b/src/include/commands/createas.h new file mode 100644 index 0000000..54a3849 --- /dev/null +++ b/src/include/commands/createas.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * createas.h + * prototypes for createas.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/createas.h + * + *------------------------------------------------------------------------- + */ +#ifndef CREATEAS_H +#define CREATEAS_H + +#include "catalog/objectaddress.h" +#include "nodes/params.h" +#include "parser/parse_node.h" +#include "tcop/dest.h" +#include "utils/queryenvironment.h" + + +extern ObjectAddress ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt, + ParamListInfo params, QueryEnvironment *queryEnv, + QueryCompletion *qc); + +extern int GetIntoRelEFlags(IntoClause *intoClause); + +extern DestReceiver *CreateIntoRelDestReceiver(IntoClause *intoClause); + +extern bool CreateTableAsRelExists(CreateTableAsStmt *ctas); + +#endif /* CREATEAS_H */ diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h new file mode 100644 index 0000000..c4947fa --- /dev/null +++ b/src/include/commands/dbcommands.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------- + * + * dbcommands.h + * Database management commands (create/drop database). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/dbcommands.h + * + *------------------------------------------------------------------------- + */ +#ifndef DBCOMMANDS_H +#define DBCOMMANDS_H + +#include "access/xlogreader.h" +#include "catalog/objectaddress.h" +#include "lib/stringinfo.h" +#include "parser/parse_node.h" + +extern Oid createdb(ParseState *pstate, const CreatedbStmt *stmt); +extern void dropdb(const char *dbname, bool missing_ok, bool force); +extern void DropDatabase(ParseState *pstate, DropdbStmt *stmt); +extern ObjectAddress RenameDatabase(const char *oldname, const char *newname); +extern Oid AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel); +extern ObjectAddress AlterDatabaseRefreshColl(AlterDatabaseRefreshCollStmt *stmt); +extern Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt); +extern ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId); + +extern Oid get_database_oid(const char *dbname, bool missing_ok); +extern char *get_database_name(Oid dbid); + +extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype); + +#endif /* DBCOMMANDS_H */ diff --git a/src/include/commands/dbcommands_xlog.h b/src/include/commands/dbcommands_xlog.h new file mode 100644 index 0000000..0ee2452 --- /dev/null +++ b/src/include/commands/dbcommands_xlog.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * dbcommands_xlog.h + * Database resource manager XLOG definitions (create/drop database). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/dbcommands_xlog.h + * + *------------------------------------------------------------------------- + */ +#ifndef DBCOMMANDS_XLOG_H +#define DBCOMMANDS_XLOG_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" + +/* record types */ +#define XLOG_DBASE_CREATE_FILE_COPY 0x00 +#define XLOG_DBASE_CREATE_WAL_LOG 0x10 +#define XLOG_DBASE_DROP 0x20 + +/* + * Single WAL record for an entire CREATE DATABASE operation. This is used + * by the FILE_COPY strategy. + */ +typedef struct xl_dbase_create_file_copy_rec +{ + Oid db_id; + Oid tablespace_id; + Oid src_db_id; + Oid src_tablespace_id; +} xl_dbase_create_file_copy_rec; + +/* + * WAL record for the beginning of a CREATE DATABASE operation, when the + * WAL_LOG strategy is used. Each individual block will be logged separately + * afterward. + */ +typedef struct xl_dbase_create_wal_log_rec +{ + Oid db_id; + Oid tablespace_id; +} xl_dbase_create_wal_log_rec; + +typedef struct xl_dbase_drop_rec +{ + Oid db_id; + int ntablespaces; /* number of tablespace IDs */ + Oid tablespace_ids[FLEXIBLE_ARRAY_MEMBER]; +} xl_dbase_drop_rec; +#define MinSizeOfDbaseDropRec offsetof(xl_dbase_drop_rec, tablespace_ids) + +extern void dbase_redo(XLogReaderState *rptr); +extern void dbase_desc(StringInfo buf, XLogReaderState *rptr); +extern const char *dbase_identify(uint8 info); + +#endif /* DBCOMMANDS_XLOG_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h new file mode 100644 index 0000000..1d3ce24 --- /dev/null +++ b/src/include/commands/defrem.h @@ -0,0 +1,160 @@ +/*------------------------------------------------------------------------- + * + * defrem.h + * POSTGRES define and remove utility definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/defrem.h + * + *------------------------------------------------------------------------- + */ +#ifndef DEFREM_H +#define DEFREM_H + +#include "catalog/objectaddress.h" +#include "nodes/params.h" +#include "parser/parse_node.h" +#include "tcop/dest.h" +#include "utils/array.h" + +/* commands/dropcmds.c */ +extern void RemoveObjects(DropStmt *stmt); + +/* commands/indexcmds.c */ +extern ObjectAddress DefineIndex(Oid relationId, + IndexStmt *stmt, + Oid indexRelationId, + Oid parentIndexId, + Oid parentConstraintId, + bool is_alter_table, + bool check_rights, + bool check_not_in_use, + bool skip_build, + bool quiet); +extern void ExecReindex(ParseState *pstate, ReindexStmt *stmt, bool isTopLevel); +extern char *makeObjectName(const char *name1, const char *name2, + const char *label); +extern char *ChooseRelationName(const char *name1, const char *name2, + const char *label, Oid namespaceid, + bool isconstraint); +extern bool CheckIndexCompatible(Oid oldId, + const char *accessMethodName, + List *attributeList, + List *exclusionOpNames); +extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); +extern Oid ResolveOpClass(List *opclass, Oid attrType, + const char *accessMethodName, Oid accessMethodId); + +/* commands/functioncmds.c */ +extern ObjectAddress CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt); +extern void RemoveFunctionById(Oid funcOid); +extern ObjectAddress AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt); +extern ObjectAddress CreateCast(CreateCastStmt *stmt); +extern ObjectAddress CreateTransform(CreateTransformStmt *stmt); +extern void IsThereFunctionInNamespace(const char *proname, int pronargs, + oidvector *proargtypes, Oid nspOid); +extern void ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic); +extern void ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest); +extern TupleDesc CallStmtResultDesc(CallStmt *stmt); +extern Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok); +extern void interpret_function_parameter_list(ParseState *pstate, + List *parameters, + Oid languageOid, + ObjectType objtype, + oidvector **parameterTypes, + List **parameterTypes_list, + ArrayType **allParameterTypes, + ArrayType **parameterModes, + ArrayType **parameterNames, + List **inParameterNames_list, + List **parameterDefaults, + Oid *variadicArgType, + Oid *requiredResultType); + +/* commands/operatorcmds.c */ +extern ObjectAddress DefineOperator(List *names, List *parameters); +extern void RemoveOperatorById(Oid operOid); +extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt); + +/* commands/statscmds.c */ +extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt); +extern ObjectAddress AlterStatistics(AlterStatsStmt *stmt); +extern void RemoveStatisticsById(Oid statsOid); +extern void RemoveStatisticsDataById(Oid statsOid, bool inh); +extern Oid StatisticsGetRelation(Oid statId, bool missing_ok); + +/* commands/aggregatecmds.c */ +extern ObjectAddress DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, + List *parameters, bool replace); + +/* commands/opclasscmds.c */ +extern ObjectAddress DefineOpClass(CreateOpClassStmt *stmt); +extern ObjectAddress DefineOpFamily(CreateOpFamilyStmt *stmt); +extern Oid AlterOpFamily(AlterOpFamilyStmt *stmt); +extern void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, + Oid opcnamespace); +extern void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, + Oid opfnamespace); +extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok); +extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok); + +/* commands/tsearchcmds.c */ +extern ObjectAddress DefineTSParser(List *names, List *parameters); + +extern ObjectAddress DefineTSDictionary(List *names, List *parameters); +extern ObjectAddress AlterTSDictionary(AlterTSDictionaryStmt *stmt); + +extern ObjectAddress DefineTSTemplate(List *names, List *parameters); + +extern ObjectAddress DefineTSConfiguration(List *names, List *parameters, + ObjectAddress *copied); +extern void RemoveTSConfigurationById(Oid cfgId); +extern ObjectAddress AlterTSConfiguration(AlterTSConfigurationStmt *stmt); + +extern text *serialize_deflist(List *deflist); +extern List *deserialize_deflist(Datum txt); + +/* commands/foreigncmds.c */ +extern ObjectAddress AlterForeignServerOwner(const char *name, Oid newOwnerId); +extern void AlterForeignServerOwner_oid(Oid, Oid newOwnerId); +extern ObjectAddress AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId); +extern void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId); +extern ObjectAddress CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt); +extern ObjectAddress AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt); +extern ObjectAddress CreateForeignServer(CreateForeignServerStmt *stmt); +extern ObjectAddress AlterForeignServer(AlterForeignServerStmt *stmt); +extern ObjectAddress CreateUserMapping(CreateUserMappingStmt *stmt); +extern ObjectAddress AlterUserMapping(AlterUserMappingStmt *stmt); +extern Oid RemoveUserMapping(DropUserMappingStmt *stmt); +extern void CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid); +extern void ImportForeignSchema(ImportForeignSchemaStmt *stmt); +extern Datum transformGenericOptions(Oid catalogId, + Datum oldOptions, + List *options, + Oid fdwvalidator); + +/* commands/amcmds.c */ +extern ObjectAddress CreateAccessMethod(CreateAmStmt *stmt); +extern Oid get_index_am_oid(const char *amname, bool missing_ok); +extern Oid get_table_am_oid(const char *amname, bool missing_ok); +extern Oid get_am_oid(const char *amname, bool missing_ok); +extern char *get_am_name(Oid amOid); + +/* support routines in commands/define.c */ + +extern char *defGetString(DefElem *def); +extern double defGetNumeric(DefElem *def); +extern bool defGetBoolean(DefElem *def); +extern int32 defGetInt32(DefElem *def); +extern int64 defGetInt64(DefElem *def); +extern Oid defGetObjectId(DefElem *def); +extern List *defGetQualifiedName(DefElem *def); +extern TypeName *defGetTypeName(DefElem *def); +extern int defGetTypeLength(DefElem *def); +extern List *defGetStringList(DefElem *def); +extern void errorConflictingDefElem(DefElem *defel, ParseState *pstate) pg_attribute_noreturn(); + +#endif /* DEFREM_H */ diff --git a/src/include/commands/discard.h b/src/include/commands/discard.h new file mode 100644 index 0000000..86d9339 --- /dev/null +++ b/src/include/commands/discard.h @@ -0,0 +1,20 @@ +/*------------------------------------------------------------------------- + * + * discard.h + * prototypes for discard.c. + * + * + * Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/commands/discard.h + * + *------------------------------------------------------------------------- + */ +#ifndef DISCARD_H +#define DISCARD_H + +#include "nodes/parsenodes.h" + +extern void DiscardCommand(DiscardStmt *stmt, bool isTopLevel); + +#endif /* DISCARD_H */ diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h new file mode 100644 index 0000000..10091c3 --- /dev/null +++ b/src/include/commands/event_trigger.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------- + * + * event_trigger.h + * Declarations for command trigger handling. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/event_trigger.h + * + *------------------------------------------------------------------------- + */ +#ifndef EVENT_TRIGGER_H +#define EVENT_TRIGGER_H + +#include "catalog/dependency.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_event_trigger.h" +#include "nodes/parsenodes.h" +#include "tcop/cmdtag.h" +#include "tcop/deparse_utility.h" +#include "utils/aclchk_internal.h" + +typedef struct EventTriggerData +{ + NodeTag type; + const char *event; /* event name */ + Node *parsetree; /* parse tree */ + CommandTag tag; +} EventTriggerData; + +#define AT_REWRITE_ALTER_PERSISTENCE 0x01 +#define AT_REWRITE_DEFAULT_VAL 0x02 +#define AT_REWRITE_COLUMN_REWRITE 0x04 +#define AT_REWRITE_ACCESS_METHOD 0x08 + +/* + * EventTriggerData is the node type that is passed as fmgr "context" info + * when a function is called by the event trigger manager. + */ +#define CALLED_AS_EVENT_TRIGGER(fcinfo) \ + ((fcinfo)->context != NULL && IsA((fcinfo)->context, EventTriggerData)) + +extern Oid CreateEventTrigger(CreateEventTrigStmt *stmt); +extern Oid get_event_trigger_oid(const char *trigname, bool missing_ok); + +extern Oid AlterEventTrigger(AlterEventTrigStmt *stmt); +extern ObjectAddress AlterEventTriggerOwner(const char *name, Oid newOwnerId); +extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId); + +extern bool EventTriggerSupportsObjectType(ObjectType obtype); +extern bool EventTriggerSupportsObjectClass(ObjectClass objclass); +extern void EventTriggerDDLCommandStart(Node *parsetree); +extern void EventTriggerDDLCommandEnd(Node *parsetree); +extern void EventTriggerSQLDrop(Node *parsetree); +extern void EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason); + +extern bool EventTriggerBeginCompleteQuery(void); +extern void EventTriggerEndCompleteQuery(void); +extern bool trackDroppedObjectsNeeded(void); +extern void EventTriggerSQLDropAddObject(const ObjectAddress *object, + bool original, bool normal); + +extern void EventTriggerInhibitCommandCollection(void); +extern void EventTriggerUndoInhibitCommandCollection(void); + +extern void EventTriggerCollectSimpleCommand(ObjectAddress address, + ObjectAddress secondaryObject, + Node *parsetree); + +extern void EventTriggerAlterTableStart(Node *parsetree); +extern void EventTriggerAlterTableRelid(Oid objectId); +extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd, + ObjectAddress address); +extern void EventTriggerAlterTableEnd(void); + +extern void EventTriggerCollectGrant(InternalGrant *istmt); +extern void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, + Oid opfamoid, List *operators, + List *procedures); +extern void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, + Oid opcoid, List *operators, + List *procedures); +extern void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, + Oid cfgId, Oid *dictIds, int ndicts); +extern void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt); + +#endif /* EVENT_TRIGGER_H */ diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h new file mode 100644 index 0000000..666977f --- /dev/null +++ b/src/include/commands/explain.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------- + * + * explain.h + * prototypes for explain.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994-5, Regents of the University of California + * + * src/include/commands/explain.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXPLAIN_H +#define EXPLAIN_H + +#include "executor/executor.h" +#include "lib/stringinfo.h" +#include "parser/parse_node.h" + +typedef enum ExplainFormat +{ + EXPLAIN_FORMAT_TEXT, + EXPLAIN_FORMAT_XML, + EXPLAIN_FORMAT_JSON, + EXPLAIN_FORMAT_YAML +} ExplainFormat; + +typedef struct ExplainWorkersState +{ + int num_workers; /* # of worker processes the plan used */ + bool *worker_inited; /* per-worker state-initialized flags */ + StringInfoData *worker_str; /* per-worker transient output buffers */ + int *worker_state_save; /* per-worker grouping state save areas */ + StringInfo prev_str; /* saved output buffer while redirecting */ +} ExplainWorkersState; + +typedef struct ExplainState +{ + StringInfo str; /* output buffer */ + /* options */ + bool verbose; /* be verbose */ + bool analyze; /* print actual times */ + bool costs; /* print estimated costs */ + bool buffers; /* print buffer usage */ + bool wal; /* print WAL usage */ + bool timing; /* print detailed node timing */ + bool summary; /* print total planning and execution timing */ + bool settings; /* print modified settings */ + ExplainFormat format; /* output format */ + /* state for output formatting --- not reset for each new plan tree */ + int indent; /* current indentation level */ + List *grouping_stack; /* format-specific grouping state */ + /* state related to the current plan tree (filled by ExplainPrintPlan) */ + PlannedStmt *pstmt; /* top of plan */ + List *rtable; /* range table */ + List *rtable_names; /* alias names for RTEs */ + List *deparse_cxt; /* context list for deparsing expressions */ + Bitmapset *printed_subplans; /* ids of SubPlans we've printed */ + bool hide_workers; /* set if we find an invisible Gather */ + /* state related to the current plan node */ + ExplainWorkersState *workers_state; /* needed if parallel plan */ +} ExplainState; + +/* Hook for plugins to get control in ExplainOneQuery() */ +typedef void (*ExplainOneQuery_hook_type) (Query *query, + int cursorOptions, + IntoClause *into, + ExplainState *es, + const char *queryString, + ParamListInfo params, + QueryEnvironment *queryEnv); +extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook; + +/* Hook for plugins to get control in explain_get_index_name() */ +typedef const char *(*explain_get_index_name_hook_type) (Oid indexId); +extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook; + + +extern void ExplainQuery(ParseState *pstate, ExplainStmt *stmt, + ParamListInfo params, DestReceiver *dest); + +extern ExplainState *NewExplainState(void); + +extern TupleDesc ExplainResultDesc(ExplainStmt *stmt); + +extern void ExplainOneUtility(Node *utilityStmt, IntoClause *into, + ExplainState *es, const char *queryString, + ParamListInfo params, QueryEnvironment *queryEnv); + +extern void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, + ExplainState *es, const char *queryString, + ParamListInfo params, QueryEnvironment *queryEnv, + const instr_time *planduration, + const BufferUsage *bufusage); + +extern void ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc); +extern void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc); + +extern void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc); + +extern void ExplainQueryText(ExplainState *es, QueryDesc *queryDesc); + +extern void ExplainBeginOutput(ExplainState *es); +extern void ExplainEndOutput(ExplainState *es); +extern void ExplainSeparatePlans(ExplainState *es); + +extern void ExplainPropertyList(const char *qlabel, List *data, + ExplainState *es); +extern void ExplainPropertyListNested(const char *qlabel, List *data, + ExplainState *es); +extern void ExplainPropertyText(const char *qlabel, const char *value, + ExplainState *es); +extern void ExplainPropertyInteger(const char *qlabel, const char *unit, + int64 value, ExplainState *es); +extern void ExplainPropertyUInteger(const char *qlabel, const char *unit, + uint64 value, ExplainState *es); +extern void ExplainPropertyFloat(const char *qlabel, const char *unit, + double value, int ndigits, ExplainState *es); +extern void ExplainPropertyBool(const char *qlabel, bool value, + ExplainState *es); + +extern void ExplainOpenGroup(const char *objtype, const char *labelname, + bool labeled, ExplainState *es); +extern void ExplainCloseGroup(const char *objtype, const char *labelname, + bool labeled, ExplainState *es); + +#endif /* EXPLAIN_H */ diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h new file mode 100644 index 0000000..e24e375 --- /dev/null +++ b/src/include/commands/extension.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * extension.h + * Extension management commands (create/drop extension). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/extension.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXTENSION_H +#define EXTENSION_H + +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" + + +/* + * creating_extension is only true while running a CREATE EXTENSION or ALTER + * EXTENSION UPDATE command. It instructs recordDependencyOnCurrentExtension() + * to register a dependency on the current pg_extension object for each SQL + * object created by an extension script. It also instructs performDeletion() + * to remove such dependencies without following them, so that extension + * scripts can drop member objects without having to explicitly dissociate + * them from the extension first. + */ +extern PGDLLIMPORT bool creating_extension; +extern PGDLLIMPORT Oid CurrentExtensionObject; + + +extern ObjectAddress CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt); + +extern void RemoveExtensionById(Oid extId); + +extern ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, + Oid schemaOid, bool relocatable, const char *extVersion, + Datum extConfig, Datum extCondition, + List *requiredExtensions); + +extern ObjectAddress ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt); + +extern ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt, + ObjectAddress *objAddr); + +extern Oid get_extension_oid(const char *extname, bool missing_ok); +extern char *get_extension_name(Oid ext_oid); +extern bool extension_file_exists(const char *extensionName); + +extern ObjectAddress AlterExtensionNamespace(const char *extensionName, const char *newschema, + Oid *oldschema); + +#endif /* EXTENSION_H */ diff --git a/src/include/commands/lockcmds.h b/src/include/commands/lockcmds.h new file mode 100644 index 0000000..871b241 --- /dev/null +++ b/src/include/commands/lockcmds.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * lockcmds.h + * prototypes for lockcmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/lockcmds.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOCKCMDS_H +#define LOCKCMDS_H + +#include "nodes/parsenodes.h" + +/* + * LOCK + */ +extern void LockTableCommand(LockStmt *lockstmt); + +#endif /* LOCKCMDS_H */ diff --git a/src/include/commands/matview.h b/src/include/commands/matview.h new file mode 100644 index 0000000..a067da3 --- /dev/null +++ b/src/include/commands/matview.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * matview.h + * prototypes for matview.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/matview.h + * + *------------------------------------------------------------------------- + */ +#ifndef MATVIEW_H +#define MATVIEW_H + +#include "catalog/objectaddress.h" +#include "nodes/params.h" +#include "nodes/parsenodes.h" +#include "tcop/dest.h" +#include "utils/relcache.h" + + +extern void SetMatViewPopulatedState(Relation relation, bool newstate); + +extern ObjectAddress ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, + ParamListInfo params, QueryCompletion *qc); + +extern DestReceiver *CreateTransientRelDestReceiver(Oid oid); + +extern bool MatViewIncrementalMaintenanceIsEnabled(void); + +#endif /* MATVIEW_H */ diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h new file mode 100644 index 0000000..c5f3753 --- /dev/null +++ b/src/include/commands/policy.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * policy.h + * prototypes for policy.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/policy.h + * + *------------------------------------------------------------------------- + */ + +#ifndef POLICY_H +#define POLICY_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" +#include "utils/relcache.h" + +extern void RelationBuildRowSecurity(Relation relation); + +extern void RemovePolicyById(Oid policy_id); + +extern bool RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid objid); + +extern ObjectAddress CreatePolicy(CreatePolicyStmt *stmt); +extern ObjectAddress AlterPolicy(AlterPolicyStmt *stmt); + +extern Oid get_relation_policy_oid(Oid relid, const char *policy_name, + bool missing_ok); + +extern ObjectAddress rename_policy(RenameStmt *stmt); + +extern bool relation_has_policies(Relation rel); + +#endif /* POLICY_H */ diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h new file mode 100644 index 0000000..ab52c82 --- /dev/null +++ b/src/include/commands/portalcmds.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * portalcmds.h + * prototypes for portalcmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/portalcmds.h + * + *------------------------------------------------------------------------- + */ +#ifndef PORTALCMDS_H +#define PORTALCMDS_H + +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "utils/portal.h" + + +extern void PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo params, + bool isTopLevel); + +extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, + QueryCompletion *qc); + +extern void PerformPortalClose(const char *name); + +extern void PortalCleanup(Portal portal); + +extern void PersistHoldablePortal(Portal portal); + +#endif /* PORTALCMDS_H */ diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h new file mode 100644 index 0000000..e30df8f --- /dev/null +++ b/src/include/commands/prepare.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * prepare.h + * PREPARE, EXECUTE and DEALLOCATE commands, and prepared-stmt storage + * + * + * Copyright (c) 2002-2022, PostgreSQL Global Development Group + * + * src/include/commands/prepare.h + * + *------------------------------------------------------------------------- + */ +#ifndef PREPARE_H +#define PREPARE_H + +#include "commands/explain.h" +#include "datatype/timestamp.h" +#include "utils/plancache.h" + +/* + * The data structure representing a prepared statement. This is now just + * a thin veneer over a plancache entry --- the main addition is that of + * a name. + * + * Note: all subsidiary storage lives in the referenced plancache entry. + */ +typedef struct +{ + /* dynahash.c requires key to be first field */ + char stmt_name[NAMEDATALEN]; + CachedPlanSource *plansource; /* the actual cached plan */ + bool from_sql; /* prepared via SQL, not FE/BE protocol? */ + TimestampTz prepare_time; /* the time when the stmt was prepared */ +} PreparedStatement; + + +/* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */ +extern void PrepareQuery(ParseState *pstate, PrepareStmt *stmt, + int stmt_location, int stmt_len); +extern void ExecuteQuery(ParseState *pstate, + ExecuteStmt *stmt, IntoClause *intoClause, + ParamListInfo params, + DestReceiver *dest, QueryCompletion *qc); +extern void DeallocateQuery(DeallocateStmt *stmt); +extern void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, + ExplainState *es, const char *queryString, + ParamListInfo params, QueryEnvironment *queryEnv); + +/* Low-level access to stored prepared statements */ +extern void StorePreparedStatement(const char *stmt_name, + CachedPlanSource *plansource, + bool from_sql); +extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, + bool throwError); +extern void DropPreparedStatement(const char *stmt_name, bool showError); +extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt); +extern List *FetchPreparedStatementTargetList(PreparedStatement *stmt); + +extern void DropAllPreparedStatements(void); + +#endif /* PREPARE_H */ diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h new file mode 100644 index 0000000..60d461b --- /dev/null +++ b/src/include/commands/proclang.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * proclang.h + * prototypes for proclang.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/proclang.h + * + *------------------------------------------------------------------------- + */ +#ifndef PROCLANG_H +#define PROCLANG_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern ObjectAddress CreateProceduralLanguage(CreatePLangStmt *stmt); + +extern Oid get_language_oid(const char *langname, bool missing_ok); + +#endif /* PROCLANG_H */ diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h new file mode 100644 index 0000000..a28938c --- /dev/null +++ b/src/include/commands/progress.h @@ -0,0 +1,154 @@ +/*------------------------------------------------------------------------- + * + * progress.h + * Constants used with the progress reporting facilities defined in + * backend_status.h. These are possibly interesting to extensions, so we + * expose them via this header file. Note that if you update these + * constants, you probably also need to update the views based on them + * in system_views.sql. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/progress.h + * + *------------------------------------------------------------------------- + */ +#ifndef PROGRESS_H +#define PROGRESS_H + +/* Progress parameters for (lazy) vacuum */ +#define PROGRESS_VACUUM_PHASE 0 +#define PROGRESS_VACUUM_TOTAL_HEAP_BLKS 1 +#define PROGRESS_VACUUM_HEAP_BLKS_SCANNED 2 +#define PROGRESS_VACUUM_HEAP_BLKS_VACUUMED 3 +#define PROGRESS_VACUUM_NUM_INDEX_VACUUMS 4 +#define PROGRESS_VACUUM_MAX_DEAD_TUPLES 5 +#define PROGRESS_VACUUM_NUM_DEAD_TUPLES 6 + +/* Phases of vacuum (as advertised via PROGRESS_VACUUM_PHASE) */ +#define PROGRESS_VACUUM_PHASE_SCAN_HEAP 1 +#define PROGRESS_VACUUM_PHASE_VACUUM_INDEX 2 +#define PROGRESS_VACUUM_PHASE_VACUUM_HEAP 3 +#define PROGRESS_VACUUM_PHASE_INDEX_CLEANUP 4 +#define PROGRESS_VACUUM_PHASE_TRUNCATE 5 +#define PROGRESS_VACUUM_PHASE_FINAL_CLEANUP 6 + +/* Progress parameters for analyze */ +#define PROGRESS_ANALYZE_PHASE 0 +#define PROGRESS_ANALYZE_BLOCKS_TOTAL 1 +#define PROGRESS_ANALYZE_BLOCKS_DONE 2 +#define PROGRESS_ANALYZE_EXT_STATS_TOTAL 3 +#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED 4 +#define PROGRESS_ANALYZE_CHILD_TABLES_TOTAL 5 +#define PROGRESS_ANALYZE_CHILD_TABLES_DONE 6 +#define PROGRESS_ANALYZE_CURRENT_CHILD_TABLE_RELID 7 + +/* Phases of analyze (as advertised via PROGRESS_ANALYZE_PHASE) */ +#define PROGRESS_ANALYZE_PHASE_ACQUIRE_SAMPLE_ROWS 1 +#define PROGRESS_ANALYZE_PHASE_ACQUIRE_SAMPLE_ROWS_INH 2 +#define PROGRESS_ANALYZE_PHASE_COMPUTE_STATS 3 +#define PROGRESS_ANALYZE_PHASE_COMPUTE_EXT_STATS 4 +#define PROGRESS_ANALYZE_PHASE_FINALIZE_ANALYZE 5 + +/* Progress parameters for cluster */ +#define PROGRESS_CLUSTER_COMMAND 0 +#define PROGRESS_CLUSTER_PHASE 1 +#define PROGRESS_CLUSTER_INDEX_RELID 2 +#define PROGRESS_CLUSTER_HEAP_TUPLES_SCANNED 3 +#define PROGRESS_CLUSTER_HEAP_TUPLES_WRITTEN 4 +#define PROGRESS_CLUSTER_TOTAL_HEAP_BLKS 5 +#define PROGRESS_CLUSTER_HEAP_BLKS_SCANNED 6 +#define PROGRESS_CLUSTER_INDEX_REBUILD_COUNT 7 + +/* Phases of cluster (as advertised via PROGRESS_CLUSTER_PHASE) */ +#define PROGRESS_CLUSTER_PHASE_SEQ_SCAN_HEAP 1 +#define PROGRESS_CLUSTER_PHASE_INDEX_SCAN_HEAP 2 +#define PROGRESS_CLUSTER_PHASE_SORT_TUPLES 3 +#define PROGRESS_CLUSTER_PHASE_WRITE_NEW_HEAP 4 +#define PROGRESS_CLUSTER_PHASE_SWAP_REL_FILES 5 +#define PROGRESS_CLUSTER_PHASE_REBUILD_INDEX 6 +#define PROGRESS_CLUSTER_PHASE_FINAL_CLEANUP 7 + +/* Commands of PROGRESS_CLUSTER */ +#define PROGRESS_CLUSTER_COMMAND_CLUSTER 1 +#define PROGRESS_CLUSTER_COMMAND_VACUUM_FULL 2 + +/* Progress parameters for CREATE INDEX */ +/* 3, 4 and 5 reserved for "waitfor" metrics */ +#define PROGRESS_CREATEIDX_COMMAND 0 +#define PROGRESS_CREATEIDX_INDEX_OID 6 +#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID 8 +#define PROGRESS_CREATEIDX_PHASE 9 /* AM-agnostic phase # */ +#define PROGRESS_CREATEIDX_SUBPHASE 10 /* phase # filled by AM */ +#define PROGRESS_CREATEIDX_TUPLES_TOTAL 11 +#define PROGRESS_CREATEIDX_TUPLES_DONE 12 +#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL 13 +#define PROGRESS_CREATEIDX_PARTITIONS_DONE 14 +/* 15 and 16 reserved for "block number" metrics */ + +/* Phases of CREATE INDEX (as advertised via PROGRESS_CREATEIDX_PHASE) */ +#define PROGRESS_CREATEIDX_PHASE_WAIT_1 1 +#define PROGRESS_CREATEIDX_PHASE_BUILD 2 +#define PROGRESS_CREATEIDX_PHASE_WAIT_2 3 +#define PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXSCAN 4 +#define PROGRESS_CREATEIDX_PHASE_VALIDATE_SORT 5 +#define PROGRESS_CREATEIDX_PHASE_VALIDATE_TABLESCAN 6 +#define PROGRESS_CREATEIDX_PHASE_WAIT_3 7 +#define PROGRESS_CREATEIDX_PHASE_WAIT_4 8 +#define PROGRESS_CREATEIDX_PHASE_WAIT_5 9 + +/* + * Subphases of CREATE INDEX, for index_build. + */ +#define PROGRESS_CREATEIDX_SUBPHASE_INITIALIZE 1 +/* Additional phases are defined by each AM */ + +/* Commands of PROGRESS_CREATEIDX */ +#define PROGRESS_CREATEIDX_COMMAND_CREATE 1 +#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY 2 +#define PROGRESS_CREATEIDX_COMMAND_REINDEX 3 +#define PROGRESS_CREATEIDX_COMMAND_REINDEX_CONCURRENTLY 4 + +/* Lock holder wait counts */ +#define PROGRESS_WAITFOR_TOTAL 3 +#define PROGRESS_WAITFOR_DONE 4 +#define PROGRESS_WAITFOR_CURRENT_PID 5 + +/* Block numbers in a generic relation scan */ +#define PROGRESS_SCAN_BLOCKS_TOTAL 15 +#define PROGRESS_SCAN_BLOCKS_DONE 16 + +/* Progress parameters for pg_basebackup */ +#define PROGRESS_BASEBACKUP_PHASE 0 +#define PROGRESS_BASEBACKUP_BACKUP_TOTAL 1 +#define PROGRESS_BASEBACKUP_BACKUP_STREAMED 2 +#define PROGRESS_BASEBACKUP_TBLSPC_TOTAL 3 +#define PROGRESS_BASEBACKUP_TBLSPC_STREAMED 4 + +/* Phases of pg_basebackup (as advertised via PROGRESS_BASEBACKUP_PHASE) */ +#define PROGRESS_BASEBACKUP_PHASE_WAIT_CHECKPOINT 1 +#define PROGRESS_BASEBACKUP_PHASE_ESTIMATE_BACKUP_SIZE 2 +#define PROGRESS_BASEBACKUP_PHASE_STREAM_BACKUP 3 +#define PROGRESS_BASEBACKUP_PHASE_WAIT_WAL_ARCHIVE 4 +#define PROGRESS_BASEBACKUP_PHASE_TRANSFER_WAL 5 + +/* Progress parameters for PROGRESS_COPY */ +#define PROGRESS_COPY_BYTES_PROCESSED 0 +#define PROGRESS_COPY_BYTES_TOTAL 1 +#define PROGRESS_COPY_TUPLES_PROCESSED 2 +#define PROGRESS_COPY_TUPLES_EXCLUDED 3 +#define PROGRESS_COPY_COMMAND 4 +#define PROGRESS_COPY_TYPE 5 + +/* Commands of COPY (as advertised via PROGRESS_COPY_COMMAND) */ +#define PROGRESS_COPY_COMMAND_FROM 1 +#define PROGRESS_COPY_COMMAND_TO 2 + +/* Types of COPY commands (as advertised via PROGRESS_COPY_TYPE) */ +#define PROGRESS_COPY_TYPE_FILE 1 +#define PROGRESS_COPY_TYPE_PROGRAM 2 +#define PROGRESS_COPY_TYPE_PIPE 3 +#define PROGRESS_COPY_TYPE_CALLBACK 4 + +#endif diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h new file mode 100644 index 0000000..57df3fc --- /dev/null +++ b/src/include/commands/publicationcmds.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * publicationcmds.h + * prototypes for publicationcmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/publicationcmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PUBLICATIONCMDS_H +#define PUBLICATIONCMDS_H + +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" +#include "utils/inval.h" + +/* Same as MAXNUMMESSAGES in sinvaladt.c */ +#define MAX_RELCACHE_INVAL_MSGS 4096 + +extern ObjectAddress CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt); +extern void AlterPublication(ParseState *pstate, AlterPublicationStmt *stmt); +extern void RemovePublicationById(Oid pubid); +extern void RemovePublicationRelById(Oid proid); +extern void RemovePublicationSchemaById(Oid psoid); + +extern ObjectAddress AlterPublicationOwner(const char *name, Oid newOwnerId); +extern void AlterPublicationOwner_oid(Oid pubid, Oid newOwnerId); +extern void InvalidatePublicationRels(List *relids); +extern bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, + List *ancestors, bool pubviaroot); +extern bool pub_collist_contains_invalid_column(Oid pubid, Relation relation, + List *ancestors, bool pubviaroot); + +#endif /* PUBLICATIONCMDS_H */ diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h new file mode 100644 index 0000000..8c21f2a --- /dev/null +++ b/src/include/commands/schemacmds.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * schemacmds.h + * prototypes for schemacmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/schemacmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SCHEMACMDS_H +#define SCHEMACMDS_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern Oid CreateSchemaCommand(CreateSchemaStmt *parsetree, + const char *queryString, + int stmt_location, int stmt_len); + +extern ObjectAddress RenameSchema(const char *oldname, const char *newname); +extern ObjectAddress AlterSchemaOwner(const char *name, Oid newOwnerId); +extern void AlterSchemaOwner_oid(Oid schemaOid, Oid newOwnerId); + +#endif /* SCHEMACMDS_H */ diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h new file mode 100644 index 0000000..1577988 --- /dev/null +++ b/src/include/commands/seclabel.h @@ -0,0 +1,34 @@ +/* + * seclabel.h + * + * Prototypes for functions in commands/seclabel.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ +#ifndef SECLABEL_H +#define SECLABEL_H + +#include "catalog/objectaddress.h" + +/* + * Internal APIs + */ +extern char *GetSecurityLabel(const ObjectAddress *object, + const char *provider); +extern void SetSecurityLabel(const ObjectAddress *object, + const char *provider, const char *label); +extern void DeleteSecurityLabel(const ObjectAddress *object); +extern void DeleteSharedSecurityLabel(Oid objectId, Oid classId); + +/* + * Statement and ESP hook support + */ +extern ObjectAddress ExecSecLabelStmt(SecLabelStmt *stmt); + +typedef void (*check_object_relabel_type) (const ObjectAddress *object, + const char *seclabel); +extern void register_label_provider(const char *provider, + check_object_relabel_type hook); + +#endif /* SECLABEL_H */ diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h new file mode 100644 index 0000000..9da2300 --- /dev/null +++ b/src/include/commands/sequence.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- + * + * sequence.h + * prototypes for sequence.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/sequence.h + * + *------------------------------------------------------------------------- + */ +#ifndef SEQUENCE_H +#define SEQUENCE_H + +#include "access/xlogreader.h" +#include "catalog/objectaddress.h" +#include "fmgr.h" +#include "lib/stringinfo.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "storage/relfilenode.h" + + +typedef struct FormData_pg_sequence_data +{ + int64 last_value; + int64 log_cnt; + bool is_called; +} FormData_pg_sequence_data; + +typedef FormData_pg_sequence_data *Form_pg_sequence_data; + +/* + * Columns of a sequence relation + */ + +#define SEQ_COL_LASTVAL 1 +#define SEQ_COL_LOG 2 +#define SEQ_COL_CALLED 3 + +#define SEQ_COL_FIRSTCOL SEQ_COL_LASTVAL +#define SEQ_COL_LASTCOL SEQ_COL_CALLED + +/* XLOG stuff */ +#define XLOG_SEQ_LOG 0x00 + +typedef struct xl_seq_rec +{ + RelFileNode node; + /* SEQUENCE TUPLE DATA FOLLOWS AT THE END */ +} xl_seq_rec; + +extern int64 nextval_internal(Oid relid, bool check_permissions); +extern Datum nextval(PG_FUNCTION_ARGS); +extern List *sequence_options(Oid relid); + +extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *stmt); +extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt); +extern void SequenceChangePersistence(Oid relid, char newrelpersistence); +extern void DeleteSequenceTuple(Oid relid); +extern void ResetSequence(Oid seq_relid); +extern void ResetSequenceCaches(void); + +extern void seq_redo(XLogReaderState *rptr); +extern void seq_desc(StringInfo buf, XLogReaderState *rptr); +extern const char *seq_identify(uint8 info); +extern void seq_mask(char *pagedata, BlockNumber blkno); + +#endif /* SEQUENCE_H */ diff --git a/src/include/commands/subscriptioncmds.h b/src/include/commands/subscriptioncmds.h new file mode 100644 index 0000000..2cbe7d7 --- /dev/null +++ b/src/include/commands/subscriptioncmds.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * subscriptioncmds.h + * prototypes for subscriptioncmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/subscriptioncmds.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SUBSCRIPTIONCMDS_H +#define SUBSCRIPTIONCMDS_H + +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" + +extern ObjectAddress CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, + bool isTopLevel); +extern ObjectAddress AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt, bool isTopLevel); +extern void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel); + +extern ObjectAddress AlterSubscriptionOwner(const char *name, Oid newOwnerId); +extern void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId); + +#endif /* SUBSCRIPTIONCMDS_H */ diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h new file mode 100644 index 0000000..5d4037f --- /dev/null +++ b/src/include/commands/tablecmds.h @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------- + * + * tablecmds.h + * prototypes for tablecmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/tablecmds.h + * + *------------------------------------------------------------------------- + */ +#ifndef TABLECMDS_H +#define TABLECMDS_H + +#include "access/htup.h" +#include "catalog/dependency.h" +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" +#include "storage/lock.h" +#include "utils/relcache.h" + +struct AlterTableUtilityContext; /* avoid including tcop/utility.h here */ + + +extern ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, + ObjectAddress *typaddress, const char *queryString); + +extern void RemoveRelations(DropStmt *drop); + +extern Oid AlterTableLookupRelation(AlterTableStmt *stmt, LOCKMODE lockmode); + +extern void AlterTable(AlterTableStmt *stmt, LOCKMODE lockmode, + struct AlterTableUtilityContext *context); + +extern LOCKMODE AlterTableGetLockLevel(List *cmds); + +extern void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode); + +extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); + +extern Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt); + +extern ObjectAddress AlterTableNamespace(AlterObjectSchemaStmt *stmt, + Oid *oldschema); + +extern void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, + Oid nspOid, ObjectAddresses *objsMoved); + +extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, + Oid oldNspOid, Oid newNspOid, + bool hasDependEntry, + ObjectAddresses *objsMoved); + +extern void CheckTableNotInUse(Relation rel, const char *stmt); + +extern void ExecuteTruncate(TruncateStmt *stmt); +extern void ExecuteTruncateGuts(List *explicit_rels, + List *relids, + List *relids_logged, + DropBehavior behavior, + bool restart_seqs); + +extern void SetRelationHasSubclass(Oid relationId, bool relhassubclass); + +extern bool CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId); +extern void SetRelationTableSpace(Relation rel, Oid newTableSpaceId, + Oid newRelFileNode); + +extern ObjectAddress renameatt(RenameStmt *stmt); + +extern ObjectAddress RenameConstraint(RenameStmt *stmt); + +extern ObjectAddress RenameRelation(RenameStmt *stmt); + +extern void RenameRelationInternal(Oid myrelid, + const char *newrelname, bool is_internal, + bool is_index); + +extern void ResetRelRewrite(Oid myrelid); + +extern void find_composite_type_dependencies(Oid typeOid, + Relation origRelation, + const char *origTypeName); + +extern void check_of_type(HeapTuple typetuple); + +extern void register_on_commit_action(Oid relid, OnCommitAction action); +extern void remove_on_commit_action(Oid relid); + +extern void PreCommit_on_commit_actions(void); +extern void AtEOXact_on_commit_actions(bool isCommit); +extern void AtEOSubXact_on_commit_actions(bool isCommit, + SubTransactionId mySubid, + SubTransactionId parentSubid); + +extern void RangeVarCallbackOwnsTable(const RangeVar *relation, + Oid relId, Oid oldRelId, void *arg); + +extern void RangeVarCallbackOwnsRelation(const RangeVar *relation, + Oid relId, Oid oldRelId, void *arg); +extern bool PartConstraintImpliedByRelConstraint(Relation scanrel, + List *partConstraint); + +#endif /* TABLECMDS_H */ diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h new file mode 100644 index 0000000..24b6473 --- /dev/null +++ b/src/include/commands/tablespace.h @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------- + * + * tablespace.h + * Tablespace management commands (create/drop tablespace). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/tablespace.h + * + *------------------------------------------------------------------------- + */ +#ifndef TABLESPACE_H +#define TABLESPACE_H + +#include "access/xlogreader.h" +#include "catalog/objectaddress.h" +#include "lib/stringinfo.h" +#include "nodes/parsenodes.h" + +extern PGDLLIMPORT bool allow_in_place_tablespaces; + +/* XLOG stuff */ +#define XLOG_TBLSPC_CREATE 0x00 +#define XLOG_TBLSPC_DROP 0x10 + +typedef struct xl_tblspc_create_rec +{ + Oid ts_id; + char ts_path[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string */ +} xl_tblspc_create_rec; + +typedef struct xl_tblspc_drop_rec +{ + Oid ts_id; +} xl_tblspc_drop_rec; + +typedef struct TableSpaceOpts +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + float8 random_page_cost; + float8 seq_page_cost; + int effective_io_concurrency; + int maintenance_io_concurrency; +} TableSpaceOpts; + +extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt); +extern void DropTableSpace(DropTableSpaceStmt *stmt); +extern ObjectAddress RenameTableSpace(const char *oldname, const char *newname); +extern Oid AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt); + +extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); + +extern Oid GetDefaultTablespace(char relpersistence, bool partitioned); + +extern void PrepareTempTablespaces(void); + +extern Oid get_tablespace_oid(const char *tablespacename, bool missing_ok); +extern char *get_tablespace_name(Oid spc_oid); + +extern bool directory_is_empty(const char *path); +extern void remove_tablespace_symlink(const char *linkloc); + +extern void tblspc_redo(XLogReaderState *rptr); +extern void tblspc_desc(StringInfo buf, XLogReaderState *rptr); +extern const char *tblspc_identify(uint8 info); + +#endif /* TABLESPACE_H */ diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h new file mode 100644 index 0000000..fff8d16 --- /dev/null +++ b/src/include/commands/trigger.h @@ -0,0 +1,306 @@ +/*------------------------------------------------------------------------- + * + * trigger.h + * Declarations for trigger handling. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/trigger.h + * + *------------------------------------------------------------------------- + */ +#ifndef TRIGGER_H +#define TRIGGER_H + +#include "access/tableam.h" +#include "catalog/objectaddress.h" +#include "nodes/execnodes.h" +#include "nodes/parsenodes.h" + +/* + * TriggerData is the node type that is passed as fmgr "context" info + * when a function is called by the trigger manager. + */ + +#define CALLED_AS_TRIGGER(fcinfo) \ + ((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData)) + +typedef uint32 TriggerEvent; + +typedef struct TriggerData +{ + NodeTag type; + TriggerEvent tg_event; + Relation tg_relation; + HeapTuple tg_trigtuple; + HeapTuple tg_newtuple; + Trigger *tg_trigger; + TupleTableSlot *tg_trigslot; + TupleTableSlot *tg_newslot; + Tuplestorestate *tg_oldtable; + Tuplestorestate *tg_newtable; + const Bitmapset *tg_updatedcols; +} TriggerData; + +/* + * The state for capturing old and new tuples into transition tables for a + * single ModifyTable node (or other operation source, e.g. copyfrom.c). + * + * This is per-caller to avoid conflicts in setting + * tcs_original_insert_tuple. Note, however, that the pointed-to + * private data may be shared across multiple callers. + */ +struct AfterTriggersTableData; /* private in trigger.c */ + +typedef struct TransitionCaptureState +{ + /* + * Is there at least one trigger specifying each transition relation on + * the relation explicitly named in the DML statement or COPY command? + * Note: in current usage, these flags could be part of the private state, + * but it seems possibly useful to let callers see them. + */ + bool tcs_delete_old_table; + bool tcs_update_old_table; + bool tcs_update_new_table; + bool tcs_insert_new_table; + + /* + * For INSERT and COPY, it would be wasteful to convert tuples from child + * format to parent format after they have already been converted in the + * opposite direction during routing. In that case we bypass conversion + * and allow the inserting code (copyfrom.c and nodeModifyTable.c) to + * provide a slot containing the original tuple directly. + */ + TupleTableSlot *tcs_original_insert_tuple; + + /* + * Private data including the tuplestore(s) into which to insert tuples. + */ + struct AfterTriggersTableData *tcs_private; +} TransitionCaptureState; + +/* + * TriggerEvent bit flags + * + * Note that we assume different event types (INSERT/DELETE/UPDATE/TRUNCATE) + * can't be OR'd together in a single TriggerEvent. This is unlike the + * situation for pg_trigger rows, so pg_trigger.tgtype uses a different + * representation! + */ +#define TRIGGER_EVENT_INSERT 0x00000000 +#define TRIGGER_EVENT_DELETE 0x00000001 +#define TRIGGER_EVENT_UPDATE 0x00000002 +#define TRIGGER_EVENT_TRUNCATE 0x00000003 +#define TRIGGER_EVENT_OPMASK 0x00000003 + +#define TRIGGER_EVENT_ROW 0x00000004 + +#define TRIGGER_EVENT_BEFORE 0x00000008 +#define TRIGGER_EVENT_AFTER 0x00000000 +#define TRIGGER_EVENT_INSTEAD 0x00000010 +#define TRIGGER_EVENT_TIMINGMASK 0x00000018 + +/* More TriggerEvent flags, used only within trigger.c */ + +#define AFTER_TRIGGER_DEFERRABLE 0x00000020 +#define AFTER_TRIGGER_INITDEFERRED 0x00000040 + +#define TRIGGER_FIRED_BY_INSERT(event) \ + (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_INSERT) + +#define TRIGGER_FIRED_BY_DELETE(event) \ + (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_DELETE) + +#define TRIGGER_FIRED_BY_UPDATE(event) \ + (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_UPDATE) + +#define TRIGGER_FIRED_BY_TRUNCATE(event) \ + (((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_TRUNCATE) + +#define TRIGGER_FIRED_FOR_ROW(event) \ + ((event) & TRIGGER_EVENT_ROW) + +#define TRIGGER_FIRED_FOR_STATEMENT(event) \ + (!TRIGGER_FIRED_FOR_ROW(event)) + +#define TRIGGER_FIRED_BEFORE(event) \ + (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_BEFORE) + +#define TRIGGER_FIRED_AFTER(event) \ + (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_AFTER) + +#define TRIGGER_FIRED_INSTEAD(event) \ + (((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_INSTEAD) + +/* + * Definitions for replication role based firing. + */ +#define SESSION_REPLICATION_ROLE_ORIGIN 0 +#define SESSION_REPLICATION_ROLE_REPLICA 1 +#define SESSION_REPLICATION_ROLE_LOCAL 2 +extern PGDLLIMPORT int SessionReplicationRole; + +/* + * States at which a trigger can be fired. These are the + * possible values for pg_trigger.tgenabled. + */ +#define TRIGGER_FIRES_ON_ORIGIN 'O' +#define TRIGGER_FIRES_ALWAYS 'A' +#define TRIGGER_FIRES_ON_REPLICA 'R' +#define TRIGGER_DISABLED 'D' + +extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString, + Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, + Oid funcoid, Oid parentTriggerOid, Node *whenClause, + bool isInternal, bool in_partition); +extern ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString, + Oid relOid, Oid refRelOid, Oid constraintOid, + Oid indexOid, Oid funcoid, Oid parentTriggerOid, + Node *whenClause, bool isInternal, bool in_partition, + char trigger_fires_when); + +extern void TriggerSetParentTrigger(Relation trigRel, + Oid childTrigId, + Oid parentTrigId, + Oid childTableId); +extern void RemoveTriggerById(Oid trigOid); +extern Oid get_trigger_oid(Oid relid, const char *name, bool missing_ok); + +extern ObjectAddress renametrig(RenameStmt *stmt); + +extern void EnableDisableTriggerNew2(Relation rel, const char *tgname, Oid tgparent, + char fires_when, bool skip_system, bool recurse, + LOCKMODE lockmode); +extern void EnableDisableTriggerNew(Relation rel, const char *tgname, + char fires_when, bool skip_system, bool recurse, + LOCKMODE lockmode); +extern void EnableDisableTrigger(Relation rel, const char *tgname, + char fires_when, bool skip_system, LOCKMODE lockmode); + +extern void RelationBuildTriggers(Relation relation); + +extern TriggerDesc *CopyTriggerDesc(TriggerDesc *trigdesc); + +extern const char *FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc); + +extern TransitionCaptureState *MakeTransitionCaptureState(TriggerDesc *trigdesc, + Oid relid, CmdType cmdType); + +extern void FreeTriggerDesc(TriggerDesc *trigdesc); + +extern void ExecBSInsertTriggers(EState *estate, + ResultRelInfo *relinfo); +extern void ExecASInsertTriggers(EState *estate, + ResultRelInfo *relinfo, + TransitionCaptureState *transition_capture); +extern bool ExecBRInsertTriggers(EState *estate, + ResultRelInfo *relinfo, + TupleTableSlot *slot); +extern void ExecARInsertTriggers(EState *estate, + ResultRelInfo *relinfo, + TupleTableSlot *slot, + List *recheckIndexes, + TransitionCaptureState *transition_capture); +extern bool ExecIRInsertTriggers(EState *estate, + ResultRelInfo *relinfo, + TupleTableSlot *slot); +extern void ExecBSDeleteTriggers(EState *estate, + ResultRelInfo *relinfo); +extern void ExecASDeleteTriggers(EState *estate, + ResultRelInfo *relinfo, + TransitionCaptureState *transition_capture); +extern bool ExecBRDeleteTriggersNew(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot **epqslot, + TM_Result *tmresult, + TM_FailureData *tmfd); +extern bool ExecBRDeleteTriggers(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot **epqslot); +extern void ExecARDeleteTriggers(EState *estate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TransitionCaptureState *transition_capture, + bool is_crosspart_update); +extern bool ExecIRDeleteTriggers(EState *estate, + ResultRelInfo *relinfo, + HeapTuple trigtuple); +extern void ExecBSUpdateTriggers(EState *estate, + ResultRelInfo *relinfo); +extern void ExecASUpdateTriggers(EState *estate, + ResultRelInfo *relinfo, + TransitionCaptureState *transition_capture); +extern bool ExecBRUpdateTriggersNew(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot *newslot, + TM_Result *tmresult, + TM_FailureData *tmfd); +extern bool ExecBRUpdateTriggers(EState *estate, + EPQState *epqstate, + ResultRelInfo *relinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot *slot, + TM_FailureData *tmfdp); +extern void ExecARUpdateTriggers(EState *estate, + ResultRelInfo *relinfo, + ResultRelInfo *src_partinfo, + ResultRelInfo *dst_partinfo, + ItemPointer tupleid, + HeapTuple fdw_trigtuple, + TupleTableSlot *slot, + List *recheckIndexes, + TransitionCaptureState *transition_capture, + bool is_crosspart_update); +extern bool ExecIRUpdateTriggers(EState *estate, + ResultRelInfo *relinfo, + HeapTuple trigtuple, + TupleTableSlot *slot); +extern void ExecBSTruncateTriggers(EState *estate, + ResultRelInfo *relinfo); +extern void ExecASTruncateTriggers(EState *estate, + ResultRelInfo *relinfo); + +extern void AfterTriggerBeginXact(void); +extern void AfterTriggerBeginQuery(void); +extern void AfterTriggerEndQuery(EState *estate); +extern void AfterTriggerFireDeferred(void); +extern void AfterTriggerEndXact(bool isCommit); +extern void AfterTriggerBeginSubXact(void); +extern void AfterTriggerEndSubXact(bool isCommit); +extern void AfterTriggerSetState(ConstraintsSetStmt *stmt); +extern bool AfterTriggerPendingOnRel(Oid relid); + + +/* + * in utils/adt/ri_triggers.c + */ +extern bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, + TupleTableSlot *old_slot, TupleTableSlot *new_slot); +extern bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, + TupleTableSlot *old_slot, TupleTableSlot *new_slot); +extern bool RI_Initial_Check(Trigger *trigger, + Relation fk_rel, Relation pk_rel); +extern void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, + Relation pk_rel); + +/* result values for RI_FKey_trigger_type: */ +#define RI_TRIGGER_PK 1 /* is a trigger on the PK relation */ +#define RI_TRIGGER_FK 2 /* is a trigger on the FK relation */ +#define RI_TRIGGER_NONE 0 /* is not an RI trigger function */ + +extern int RI_FKey_trigger_type(Oid tgfoid); + +#endif /* TRIGGER_H */ diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h new file mode 100644 index 0000000..a17bedb --- /dev/null +++ b/src/include/commands/typecmds.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * typecmds.h + * prototypes for typecmds.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/typecmds.h + * + *------------------------------------------------------------------------- + */ +#ifndef TYPECMDS_H +#define TYPECMDS_H + +#include "access/htup.h" +#include "catalog/dependency.h" +#include "parser/parse_node.h" + + +#define DEFAULT_TYPDELIM ',' + +extern ObjectAddress DefineType(ParseState *pstate, List *names, List *parameters); +extern void RemoveTypeById(Oid typeOid); +extern ObjectAddress DefineDomain(CreateDomainStmt *stmt); +extern ObjectAddress DefineEnum(CreateEnumStmt *stmt); +extern ObjectAddress DefineRange(ParseState *pstate, CreateRangeStmt *stmt); +extern ObjectAddress AlterEnum(AlterEnumStmt *stmt); +extern ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist); +extern Oid AssignTypeArrayOid(void); +extern Oid AssignTypeMultirangeOid(void); +extern Oid AssignTypeMultirangeArrayOid(void); + +extern ObjectAddress AlterDomainDefault(List *names, Node *defaultRaw); +extern ObjectAddress AlterDomainNotNull(List *names, bool notNull); +extern ObjectAddress AlterDomainAddConstraint(List *names, Node *constr, + ObjectAddress *constrAddr); +extern ObjectAddress AlterDomainValidateConstraint(List *names, const char *constrName); +extern ObjectAddress AlterDomainDropConstraint(List *names, const char *constrName, + DropBehavior behavior, bool missing_ok); + +extern void checkDomainOwner(HeapTuple tup); + +extern ObjectAddress RenameType(RenameStmt *stmt); + +extern ObjectAddress AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype); +extern void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry); +extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId); + +extern ObjectAddress AlterTypeNamespace(List *names, const char *newschema, + ObjectType objecttype, Oid *oldschema); +extern Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved); +extern Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, + bool isImplicitArray, + bool errorOnTableType, + ObjectAddresses *objsMoved); + +extern ObjectAddress AlterType(AlterTypeStmt *stmt); + +#endif /* TYPECMDS_H */ diff --git a/src/include/commands/user.h b/src/include/commands/user.h new file mode 100644 index 0000000..d3dd830 --- /dev/null +++ b/src/include/commands/user.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * user.h + * Commands for manipulating roles (formerly called users). + * + * + * src/include/commands/user.h + * + *------------------------------------------------------------------------- + */ +#ifndef USER_H +#define USER_H + +#include "catalog/objectaddress.h" +#include "libpq/crypt.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" + +/* GUC. Is actually of type PasswordType. */ +extern PGDLLIMPORT int Password_encryption; + +/* Hook to check passwords in CreateRole() and AlterRole() */ +typedef void (*check_password_hook_type) (const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null); + +extern PGDLLIMPORT check_password_hook_type check_password_hook; + +extern Oid CreateRole(ParseState *pstate, CreateRoleStmt *stmt); +extern Oid AlterRole(ParseState *pstate, AlterRoleStmt *stmt); +extern Oid AlterRoleSet(AlterRoleSetStmt *stmt); +extern void DropRole(DropRoleStmt *stmt); +extern void GrantRole(GrantRoleStmt *stmt); +extern ObjectAddress RenameRole(const char *oldname, const char *newname); +extern void DropOwnedObjects(DropOwnedStmt *stmt); +extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt); +extern List *roleSpecsToIds(List *memberNames); + +#endif /* USER_H */ diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h new file mode 100644 index 0000000..f38e114 --- /dev/null +++ b/src/include/commands/vacuum.h @@ -0,0 +1,340 @@ +/*------------------------------------------------------------------------- + * + * vacuum.h + * header file for postgres vacuum cleaner and statistics analyzer + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/vacuum.h + * + *------------------------------------------------------------------------- + */ +#ifndef VACUUM_H +#define VACUUM_H + +#include "access/htup.h" +#include "access/genam.h" +#include "access/parallel.h" +#include "catalog/pg_class.h" +#include "catalog/pg_statistic.h" +#include "catalog/pg_type.h" +#include "parser/parse_node.h" +#include "storage/buf.h" +#include "storage/lock.h" +#include "utils/relcache.h" + +/* + * Flags for amparallelvacuumoptions to control the participation of bulkdelete + * and vacuumcleanup in parallel vacuum. + */ + +/* + * Both bulkdelete and vacuumcleanup are disabled by default. This will be + * used by IndexAM's that don't want to or cannot participate in parallel + * vacuum. For example, if an index AM doesn't have a way to communicate the + * index statistics allocated by the first ambulkdelete call to the subsequent + * ones until amvacuumcleanup, the index AM cannot participate in parallel + * vacuum. + */ +#define VACUUM_OPTION_NO_PARALLEL 0 + +/* + * bulkdelete can be performed in parallel. This option can be used by + * index AMs that need to scan indexes to delete tuples. + */ +#define VACUUM_OPTION_PARALLEL_BULKDEL (1 << 0) + +/* + * vacuumcleanup can be performed in parallel if bulkdelete is not performed + * yet. This will be used by IndexAM's that can scan the index if the + * bulkdelete is not performed. + */ +#define VACUUM_OPTION_PARALLEL_COND_CLEANUP (1 << 1) + +/* + * vacuumcleanup can be performed in parallel even if bulkdelete has already + * processed the index. This will be used by IndexAM's that scan the index + * during the cleanup phase of index irrespective of whether the index is + * already scanned or not during bulkdelete phase. + */ +#define VACUUM_OPTION_PARALLEL_CLEANUP (1 << 2) + +/* value for checking vacuum flags */ +#define VACUUM_OPTION_MAX_VALID_VALUE ((1 << 3) - 1) + +/* Abstract type for parallel vacuum state */ +typedef struct ParallelVacuumState ParallelVacuumState; + +/*---------- + * ANALYZE builds one of these structs for each attribute (column) that is + * to be analyzed. The struct and subsidiary data are in anl_context, + * so they live until the end of the ANALYZE operation. + * + * The type-specific typanalyze function is passed a pointer to this struct + * and must return true to continue analysis, false to skip analysis of this + * column. In the true case it must set the compute_stats and minrows fields, + * and can optionally set extra_data to pass additional info to compute_stats. + * minrows is its request for the minimum number of sample rows to be gathered + * (but note this request might not be honored, eg if there are fewer rows + * than that in the table). + * + * The compute_stats routine will be called after sample rows have been + * gathered. Aside from this struct, it is passed: + * fetchfunc: a function for accessing the column values from the + * sample rows + * samplerows: the number of sample tuples + * totalrows: estimated total number of rows in relation + * The fetchfunc may be called with rownum running from 0 to samplerows-1. + * It returns a Datum and an isNull flag. + * + * compute_stats should set stats_valid true if it is able to compute + * any useful statistics. If it does, the remainder of the struct holds + * the information to be stored in a pg_statistic row for the column. Be + * careful to allocate any pointed-to data in anl_context, which will NOT + * be CurrentMemoryContext when compute_stats is called. + * + * Note: all comparisons done for statistical purposes should use the + * underlying column's collation (attcollation), except in situations + * where a noncollatable container type contains a collatable type; + * in that case use the type's default collation. Be sure to record + * the appropriate collation in stacoll. + *---------- + */ +typedef struct VacAttrStats *VacAttrStatsP; + +typedef Datum (*AnalyzeAttrFetchFunc) (VacAttrStatsP stats, int rownum, + bool *isNull); + +typedef void (*AnalyzeAttrComputeStatsFunc) (VacAttrStatsP stats, + AnalyzeAttrFetchFunc fetchfunc, + int samplerows, + double totalrows); + +typedef struct VacAttrStats +{ + /* + * These fields are set up by the main ANALYZE code before invoking the + * type-specific typanalyze function. + * + * Note: do not assume that the data being analyzed has the same datatype + * shown in attr, ie do not trust attr->atttypid, attlen, etc. This is + * because some index opclasses store a different type than the underlying + * column/expression. Instead use attrtypid, attrtypmod, and attrtype for + * information about the datatype being fed to the typanalyze function. + * Likewise, use attrcollid not attr->attcollation. + */ + Form_pg_attribute attr; /* copy of pg_attribute row for column */ + Oid attrtypid; /* type of data being analyzed */ + int32 attrtypmod; /* typmod of data being analyzed */ + Form_pg_type attrtype; /* copy of pg_type row for attrtypid */ + Oid attrcollid; /* collation of data being analyzed */ + MemoryContext anl_context; /* where to save long-lived data */ + + /* + * These fields must be filled in by the typanalyze routine, unless it + * returns false. + */ + AnalyzeAttrComputeStatsFunc compute_stats; /* function pointer */ + int minrows; /* Minimum # of rows wanted for stats */ + void *extra_data; /* for extra type-specific data */ + + /* + * These fields are to be filled in by the compute_stats routine. (They + * are initialized to zero when the struct is created.) + */ + bool stats_valid; + float4 stanullfrac; /* fraction of entries that are NULL */ + int32 stawidth; /* average width of column values */ + float4 stadistinct; /* # distinct values */ + int16 stakind[STATISTIC_NUM_SLOTS]; + Oid staop[STATISTIC_NUM_SLOTS]; + Oid stacoll[STATISTIC_NUM_SLOTS]; + int numnumbers[STATISTIC_NUM_SLOTS]; + float4 *stanumbers[STATISTIC_NUM_SLOTS]; + int numvalues[STATISTIC_NUM_SLOTS]; + Datum *stavalues[STATISTIC_NUM_SLOTS]; + + /* + * These fields describe the stavalues[n] element types. They will be + * initialized to match attrtypid, but a custom typanalyze function might + * want to store an array of something other than the analyzed column's + * elements. It should then overwrite these fields. + */ + Oid statypid[STATISTIC_NUM_SLOTS]; + int16 statyplen[STATISTIC_NUM_SLOTS]; + bool statypbyval[STATISTIC_NUM_SLOTS]; + char statypalign[STATISTIC_NUM_SLOTS]; + + /* + * These fields are private to the main ANALYZE code and should not be + * looked at by type-specific functions. + */ + int tupattnum; /* attribute number within tuples */ + HeapTuple *rows; /* access info for std fetch function */ + TupleDesc tupDesc; + Datum *exprvals; /* access info for index fetch function */ + bool *exprnulls; + int rowstride; +} VacAttrStats; + +/* flag bits for VacuumParams->options */ +#define VACOPT_VACUUM 0x01 /* do VACUUM */ +#define VACOPT_ANALYZE 0x02 /* do ANALYZE */ +#define VACOPT_VERBOSE 0x04 /* output INFO instrumentation messages */ +#define VACOPT_FREEZE 0x08 /* FREEZE option */ +#define VACOPT_FULL 0x10 /* FULL (non-concurrent) vacuum */ +#define VACOPT_SKIP_LOCKED 0x20 /* skip if cannot get lock */ +#define VACOPT_PROCESS_TOAST 0x40 /* process the TOAST table, if any */ +#define VACOPT_DISABLE_PAGE_SKIPPING 0x80 /* don't skip any pages */ + +/* + * Values used by index_cleanup and truncate params. + * + * VACOPTVALUE_UNSPECIFIED is used as an initial placeholder when VACUUM + * command has no explicit value. When that happens the final usable value + * comes from the corresponding reloption (though the reloption default is + * usually used). + */ +typedef enum VacOptValue +{ + VACOPTVALUE_UNSPECIFIED = 0, + VACOPTVALUE_AUTO, + VACOPTVALUE_DISABLED, + VACOPTVALUE_ENABLED, +} VacOptValue; + +/* + * Parameters customizing behavior of VACUUM and ANALYZE. + * + * Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set + * in options. + */ +typedef struct VacuumParams +{ + bits32 options; /* bitmask of VACOPT_* */ + int freeze_min_age; /* min freeze age, -1 to use default */ + int freeze_table_age; /* age at which to scan whole table */ + int multixact_freeze_min_age; /* min multixact freeze age, -1 to + * use default */ + int multixact_freeze_table_age; /* multixact age at which to scan + * whole table */ + bool is_wraparound; /* force a for-wraparound vacuum */ + int log_min_duration; /* minimum execution threshold in ms at + * which autovacuum is logged, -1 to use + * default */ + VacOptValue index_cleanup; /* Do index vacuum and cleanup */ + VacOptValue truncate; /* Truncate empty pages at the end */ + + /* + * The number of parallel vacuum workers. 0 by default which means choose + * based on the number of indexes. -1 indicates parallel vacuum is + * disabled. + */ + int nworkers; +} VacuumParams; + +/* + * VacDeadItems stores TIDs whose index tuples are deleted by index vacuuming. + */ +typedef struct VacDeadItems +{ + int max_items; /* # slots allocated in array */ + int num_items; /* current # of entries */ + + /* Sorted array of TIDs to delete from indexes */ + ItemPointerData items[FLEXIBLE_ARRAY_MEMBER]; +} VacDeadItems; + +#define MAXDEADITEMS(avail_mem) \ + (((avail_mem) - offsetof(VacDeadItems, items)) / sizeof(ItemPointerData)) + +/* GUC parameters */ +extern PGDLLIMPORT int default_statistics_target; /* PGDLLIMPORT for PostGIS */ +extern PGDLLIMPORT int vacuum_freeze_min_age; +extern PGDLLIMPORT int vacuum_freeze_table_age; +extern PGDLLIMPORT int vacuum_multixact_freeze_min_age; +extern PGDLLIMPORT int vacuum_multixact_freeze_table_age; +extern PGDLLIMPORT int vacuum_failsafe_age; +extern PGDLLIMPORT int vacuum_multixact_failsafe_age; + +/* Variables for cost-based parallel vacuum */ +extern PGDLLIMPORT pg_atomic_uint32 *VacuumSharedCostBalance; +extern PGDLLIMPORT pg_atomic_uint32 *VacuumActiveNWorkers; +extern PGDLLIMPORT int VacuumCostBalanceLocal; + + +/* in commands/vacuum.c */ +extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel); +extern void vacuum(List *relations, VacuumParams *params, + BufferAccessStrategy bstrategy, bool isTopLevel); +extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, + int *nindexes, Relation **Irel); +extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode); +extern double vac_estimate_reltuples(Relation relation, + BlockNumber total_pages, + BlockNumber scanned_pages, + double scanned_tuples); +extern void vac_update_relstats(Relation relation, + BlockNumber num_pages, + double num_tuples, + BlockNumber num_all_visible_pages, + bool hasindex, + TransactionId frozenxid, + MultiXactId minmulti, + bool *frozenxid_updated, + bool *minmulti_updated, + bool in_outer_xact); +extern bool vacuum_set_xid_limits(Relation rel, + int freeze_min_age, int freeze_table_age, + int multixact_freeze_min_age, + int multixact_freeze_table_age, + TransactionId *oldestXmin, + MultiXactId *oldestMxact, + TransactionId *freezeLimit, + MultiXactId *multiXactCutoff); +extern bool vacuum_xid_failsafe_check(TransactionId relfrozenxid, + MultiXactId relminmxid); +extern void vac_update_datfrozenxid(void); +extern void vacuum_delay_point(void); +extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, + bits32 options); +extern Relation vacuum_open_relation(Oid relid, RangeVar *relation, + bits32 options, bool verbose, + LOCKMODE lmode); +extern IndexBulkDeleteResult *vac_bulkdel_one_index(IndexVacuumInfo *ivinfo, + IndexBulkDeleteResult *istat, + VacDeadItems *dead_items); +extern IndexBulkDeleteResult *vac_cleanup_one_index(IndexVacuumInfo *ivinfo, + IndexBulkDeleteResult *istat); +extern Size vac_max_items_to_alloc_size(int max_items); + +/* in commands/vacuumparallel.c */ +extern ParallelVacuumState *parallel_vacuum_init(Relation rel, Relation *indrels, + int nindexes, int nrequested_workers, + int max_items, int elevel, + BufferAccessStrategy bstrategy); +extern void parallel_vacuum_end(ParallelVacuumState *pvs, IndexBulkDeleteResult **istats); +extern VacDeadItems *parallel_vacuum_get_dead_items(ParallelVacuumState *pvs); +extern void parallel_vacuum_bulkdel_all_indexes(ParallelVacuumState *pvs, + long num_table_tuples, + int num_index_scans); +extern void parallel_vacuum_cleanup_all_indexes(ParallelVacuumState *pvs, + long num_table_tuples, + int num_index_scans, + bool estimated_count); +extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc); + +/* in commands/analyze.c */ +extern void analyze_rel(Oid relid, RangeVar *relation, + VacuumParams *params, List *va_cols, bool in_outer_xact, + BufferAccessStrategy bstrategy); +extern bool std_typanalyze(VacAttrStats *stats); + +/* in utils/misc/sampling.c --- duplicate of declarations in utils/sampling.h */ +extern double anl_random_fract(void); +extern double anl_init_selection_state(int n); +extern double anl_get_next_S(double t, int n, double *stateptr); + +#endif /* VACUUM_H */ diff --git a/src/include/commands/variable.h b/src/include/commands/variable.h new file mode 100644 index 0000000..0e5ddcb --- /dev/null +++ b/src/include/commands/variable.h @@ -0,0 +1,38 @@ +/* + * variable.h + * Routines for handling specialized SET variables. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/variable.h + */ +#ifndef VARIABLE_H +#define VARIABLE_H + +#include "utils/guc.h" + + +extern bool check_datestyle(char **newval, void **extra, GucSource source); +extern void assign_datestyle(const char *newval, void *extra); +extern bool check_timezone(char **newval, void **extra, GucSource source); +extern void assign_timezone(const char *newval, void *extra); +extern const char *show_timezone(void); +extern bool check_log_timezone(char **newval, void **extra, GucSource source); +extern void assign_log_timezone(const char *newval, void *extra); +extern const char *show_log_timezone(void); +extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); +extern bool check_XactIsoLevel(int *newval, void **extra, GucSource source); +extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); +extern bool check_random_seed(double *newval, void **extra, GucSource source); +extern void assign_random_seed(double newval, void *extra); +extern const char *show_random_seed(void); +extern bool check_client_encoding(char **newval, void **extra, GucSource source); +extern void assign_client_encoding(const char *newval, void *extra); +extern bool check_session_authorization(char **newval, void **extra, GucSource source); +extern void assign_session_authorization(const char *newval, void *extra); +extern bool check_role(char **newval, void **extra, GucSource source); +extern void assign_role(const char *newval, void *extra); +extern const char *show_role(void); + +#endif /* VARIABLE_H */ diff --git a/src/include/commands/view.h b/src/include/commands/view.h new file mode 100644 index 0000000..05fe44a --- /dev/null +++ b/src/include/commands/view.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * view.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/commands/view.h + * + *------------------------------------------------------------------------- + */ +#ifndef VIEW_H +#define VIEW_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" + +extern ObjectAddress DefineView(ViewStmt *stmt, const char *queryString, + int stmt_location, int stmt_len); + +extern void StoreViewQuery(Oid viewOid, Query *viewParse, bool replace); + +#endif /* VIEW_H */ diff --git a/src/include/common/archive.h b/src/include/common/archive.h new file mode 100644 index 0000000..bbb64c3 --- /dev/null +++ b/src/include/common/archive.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * archive.h + * Common WAL archive routines + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/archive.h + * + *------------------------------------------------------------------------- + */ +#ifndef ARCHIVE_H +#define ARCHIVE_H + +extern char *BuildRestoreCommand(const char *restoreCommand, + const char *xlogpath, /* %p */ + const char *xlogfname, /* %f */ + const char *lastRestartPointFname); /* %r */ + +#endif /* ARCHIVE_H */ diff --git a/src/include/common/base64.h b/src/include/common/base64.h new file mode 100644 index 0000000..8a040e8 --- /dev/null +++ b/src/include/common/base64.h @@ -0,0 +1,19 @@ +/* + * base64.h + * Encoding and decoding routines for base64 without whitespace + * support. + * + * Portions Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/common/base64.h + */ +#ifndef BASE64_H +#define BASE64_H + +/* base 64 */ +extern int pg_b64_encode(const char *src, int len, char *dst, int dstlen); +extern int pg_b64_decode(const char *src, int len, char *dst, int dstlen); +extern int pg_b64_enc_len(int srclen); +extern int pg_b64_dec_len(int srclen); + +#endif /* BASE64_H */ diff --git a/src/include/common/checksum_helper.h b/src/include/common/checksum_helper.h new file mode 100644 index 0000000..23816ca --- /dev/null +++ b/src/include/common/checksum_helper.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * checksum_helper.h + * Compute a checksum of any of various types using common routines + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/common/checksum_helper.h + * + *------------------------------------------------------------------------- + */ + +#ifndef CHECKSUM_HELPER_H +#define CHECKSUM_HELPER_H + +#include "common/cryptohash.h" +#include "common/sha2.h" +#include "port/pg_crc32c.h" + +/* + * Supported checksum types. It's not necessarily the case that code using + * these functions needs a cryptographically strong checksum; it may only + * need to detect accidental modification. That's why we include CRC-32C: it's + * much faster than any of the other algorithms. On the other hand, we omit + * MD5 here because any new that does need a cryptographically strong checksum + * should use something better. + */ +typedef enum pg_checksum_type +{ + CHECKSUM_TYPE_NONE, + CHECKSUM_TYPE_CRC32C, + CHECKSUM_TYPE_SHA224, + CHECKSUM_TYPE_SHA256, + CHECKSUM_TYPE_SHA384, + CHECKSUM_TYPE_SHA512 +} pg_checksum_type; + +/* + * This is just a union of all applicable context types. + */ +typedef union pg_checksum_raw_context +{ + pg_crc32c c_crc32c; + pg_cryptohash_ctx *c_sha2; +} pg_checksum_raw_context; + +/* + * This structure provides a convenient way to pass the checksum type and the + * checksum context around together. + */ +typedef struct pg_checksum_context +{ + pg_checksum_type type; + pg_checksum_raw_context raw_context; +} pg_checksum_context; + +/* + * This is the longest possible output for any checksum algorithm supported + * by this file. + */ +#define PG_CHECKSUM_MAX_LENGTH PG_SHA512_DIGEST_LENGTH + +extern bool pg_checksum_parse_type(char *name, pg_checksum_type *); +extern char *pg_checksum_type_name(pg_checksum_type); + +extern int pg_checksum_init(pg_checksum_context *, pg_checksum_type); +extern int pg_checksum_update(pg_checksum_context *, const uint8 *input, + size_t len); +extern int pg_checksum_final(pg_checksum_context *, uint8 *output); + +#endif diff --git a/src/include/common/compression.h b/src/include/common/compression.h new file mode 100644 index 0000000..bb80e88 --- /dev/null +++ b/src/include/common/compression.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * compression.h + * + * Shared definitions for compression methods and specifications. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/compression.h + *------------------------------------------------------------------------- + */ + +#ifndef PG_COMPRESSION_H +#define PG_COMPRESSION_H + +typedef enum pg_compress_algorithm +{ + PG_COMPRESSION_NONE, + PG_COMPRESSION_GZIP, + PG_COMPRESSION_LZ4, + PG_COMPRESSION_ZSTD +} pg_compress_algorithm; + +#define PG_COMPRESSION_OPTION_WORKERS (1 << 0) + +typedef struct pg_compress_specification +{ + pg_compress_algorithm algorithm; + unsigned options; /* OR of PG_COMPRESSION_OPTION constants */ + int level; + int workers; + char *parse_error; /* NULL if parsing was OK, else message */ +} pg_compress_specification; + +extern bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm); +extern const char *get_compress_algorithm_name(pg_compress_algorithm algorithm); + +extern void parse_compress_specification(pg_compress_algorithm algorithm, + char *specification, + pg_compress_specification *result); + +extern char *validate_compress_specification(pg_compress_specification *); + +#endif diff --git a/src/include/common/config_info.h b/src/include/common/config_info.h new file mode 100644 index 0000000..cb7df55 --- /dev/null +++ b/src/include/common/config_info.h @@ -0,0 +1,21 @@ +/* + * config_info.h + * Common code for pg_config output + * + * Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/common/config_info.h + */ +#ifndef COMMON_CONFIG_INFO_H +#define COMMON_CONFIG_INFO_H + +typedef struct ConfigData +{ + char *name; + char *setting; +} ConfigData; + +extern ConfigData *get_configdata(const char *my_exec_path, + size_t *configdata_len); + +#endif /* COMMON_CONFIG_INFO_H */ diff --git a/src/include/common/connect.h b/src/include/common/connect.h new file mode 100644 index 0000000..7fce19d --- /dev/null +++ b/src/include/common/connect.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * Interfaces in support of FE/BE connections. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/connect.h + * + *------------------------------------------------------------------------- + */ +#ifndef CONNECT_H +#define CONNECT_H + +/* + * This SQL statement installs an always-secure search path, so malicious + * users can't take control. CREATE of an unqualified name will fail, because + * this selects no creation schema. This does not demote pg_temp, so it is + * suitable where we control the entire FE/BE connection but not suitable in + * SECURITY DEFINER functions. This is portable to PostgreSQL 7.3, which + * introduced schemas. When connected to an older version from code that + * might work with the old server, skip this. + */ +#define ALWAYS_SECURE_SEARCH_PATH_SQL \ + "SELECT pg_catalog.set_config('search_path', '', false);" + +#endif /* CONNECT_H */ diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h new file mode 100644 index 0000000..b1dab75 --- /dev/null +++ b/src/include/common/controldata_utils.h @@ -0,0 +1,19 @@ +/* + * controldata_utils.h + * Common code for pg_controldata output + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/controldata_utils.h + */ +#ifndef COMMON_CONTROLDATA_UTILS_H +#define COMMON_CONTROLDATA_UTILS_H + +#include "catalog/pg_control.h" + +extern ControlFileData *get_controlfile(const char *DataDir, bool *crc_ok_p); +extern void update_controlfile(const char *DataDir, + ControlFileData *ControlFile, bool do_sync); + +#endif /* COMMON_CONTROLDATA_UTILS_H */ diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h new file mode 100644 index 0000000..8e339c8 --- /dev/null +++ b/src/include/common/cryptohash.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * cryptohash.h + * Generic headers for cryptographic hash functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/cryptohash.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_CRYPTOHASH_H +#define PG_CRYPTOHASH_H + +/* Context Structures for each hash function */ +typedef enum +{ + PG_MD5 = 0, + PG_SHA1, + PG_SHA224, + PG_SHA256, + PG_SHA384, + PG_SHA512 +} pg_cryptohash_type; + +/* opaque context, private to each cryptohash implementation */ +typedef struct pg_cryptohash_ctx pg_cryptohash_ctx; + +extern pg_cryptohash_ctx *pg_cryptohash_create(pg_cryptohash_type type); +extern int pg_cryptohash_init(pg_cryptohash_ctx *ctx); +extern int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len); +extern int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len); +extern void pg_cryptohash_free(pg_cryptohash_ctx *ctx); +extern const char *pg_cryptohash_error(pg_cryptohash_ctx *ctx); + +#endif /* PG_CRYPTOHASH_H */ diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h new file mode 100644 index 0000000..63f2b6a --- /dev/null +++ b/src/include/common/fe_memutils.h @@ -0,0 +1,73 @@ +/* + * fe_memutils.h + * memory management support for frontend code + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/common/fe_memutils.h + */ +#ifndef FE_MEMUTILS_H +#define FE_MEMUTILS_H + +/* + * Flags for pg_malloc_extended and palloc_extended, deliberately named + * the same as the backend flags. + */ +#define MCXT_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) not + * actually used for frontends */ +#define MCXT_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ +#define MCXT_ALLOC_ZERO 0x04 /* zero allocated memory */ + +/* + * "Safe" memory allocation functions --- these exit(1) on failure + * (except pg_malloc_extended with MCXT_ALLOC_NO_OOM) + */ +extern char *pg_strdup(const char *in); +extern void *pg_malloc(size_t size); +extern void *pg_malloc0(size_t size); +extern void *pg_malloc_extended(size_t size, int flags); +extern void *pg_realloc(void *pointer, size_t size); +extern void pg_free(void *pointer); + +/* + * Variants with easier notation and more type safety + */ + +/* + * Allocate space for one object of type "type" + */ +#define pg_malloc_object(type) ((type *) pg_malloc(sizeof(type))) +#define pg_malloc0_object(type) ((type *) pg_malloc0(sizeof(type))) + +/* + * Allocate space for "count" objects of type "type" + */ +#define pg_malloc_array(type, count) ((type *) pg_malloc(sizeof(type) * (count))) +#define pg_malloc0_array(type, count) ((type *) pg_malloc0(sizeof(type) * (count))) + +/* + * Change size of allocation pointed to by "pointer" to have space for "count" + * objects of type "type" + */ +#define pg_realloc_array(pointer, type, count) ((type *) pg_realloc(pointer, sizeof(type) * (count))) + +/* Equivalent functions, deliberately named the same as backend functions */ +extern char *pstrdup(const char *in); +extern char *pnstrdup(const char *in, Size size); +extern void *palloc(Size size); +extern void *palloc0(Size size); +extern void *palloc_extended(Size size, int flags); +extern void *repalloc(void *pointer, Size size); +extern void pfree(void *pointer); + +#define palloc_object(type) ((type *) palloc(sizeof(type))) +#define palloc0_object(type) ((type *) palloc0(sizeof(type))) +#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) +#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) +#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) + +/* sprintf into a palloc'd buffer --- these are in psprintf.c */ +extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2); +extern size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) pg_attribute_printf(3, 0); + +#endif /* FE_MEMUTILS_H */ diff --git a/src/include/common/file_perm.h b/src/include/common/file_perm.h new file mode 100644 index 0000000..48d68ef --- /dev/null +++ b/src/include/common/file_perm.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * File and directory permission definitions + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/file_perm.h + * + *------------------------------------------------------------------------- + */ +#ifndef FILE_PERM_H +#define FILE_PERM_H + +#include <sys/stat.h> + +/* + * Mode mask for data directory permissions that only allows the owner to + * read/write directories and files. + * + * This is the default. + */ +#define PG_MODE_MASK_OWNER (S_IRWXG | S_IRWXO) + +/* + * Mode mask for data directory permissions that also allows group read/execute. + */ +#define PG_MODE_MASK_GROUP (S_IWGRP | S_IRWXO) + +/* Default mode for creating directories */ +#define PG_DIR_MODE_OWNER S_IRWXU + +/* Mode for creating directories that allows group read/execute */ +#define PG_DIR_MODE_GROUP (S_IRWXU | S_IRGRP | S_IXGRP) + +/* Default mode for creating files */ +#define PG_FILE_MODE_OWNER (S_IRUSR | S_IWUSR) + +/* Mode for creating files that allows group read */ +#define PG_FILE_MODE_GROUP (S_IRUSR | S_IWUSR | S_IRGRP) + +/* Modes for creating directories and files in the data directory */ +extern PGDLLIMPORT int pg_dir_create_mode; +extern PGDLLIMPORT int pg_file_create_mode; + +/* Mode mask to pass to umask() */ +extern PGDLLIMPORT int pg_mode_mask; + +/* Set permissions and mask based on the provided mode */ +extern void SetDataDirectoryCreatePerm(int dataDirMode); + +/* Set permissions and mask based on the mode of the data directory */ +extern bool GetDataDirectoryCreatePerm(const char *dataDir); + +#endif /* FILE_PERM_H */ diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h new file mode 100644 index 0000000..2811744 --- /dev/null +++ b/src/include/common/file_utils.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * Assorted utility functions to work on files. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/file_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef FILE_UTILS_H +#define FILE_UTILS_H + +#include <dirent.h> + +typedef enum PGFileType +{ + PGFILETYPE_ERROR, + PGFILETYPE_UNKNOWN, + PGFILETYPE_REG, + PGFILETYPE_DIR, + PGFILETYPE_LNK +} PGFileType; + +#ifdef FRONTEND +extern int fsync_fname(const char *fname, bool isdir); +extern void fsync_pgdata(const char *pg_data, int serverVersion); +extern void fsync_dir_recurse(const char *dir); +extern int durable_rename(const char *oldfile, const char *newfile); +extern int fsync_parent_path(const char *fname); +#endif + +extern PGFileType get_dirent_type(const char *path, + const struct dirent *de, + bool look_through_symlinks, + int elevel); + +#endif /* FILE_UTILS_H */ diff --git a/src/include/common/hashfn.h b/src/include/common/hashfn.h new file mode 100644 index 0000000..8d539c0 --- /dev/null +++ b/src/include/common/hashfn.h @@ -0,0 +1,104 @@ +/* + * Utilities for working with hash values. + * + * Portions Copyright (c) 2017-2022, PostgreSQL Global Development Group + */ + +#ifndef HASHFN_H +#define HASHFN_H + + +/* + * Rotate the high 32 bits and the low 32 bits separately. The standard + * hash function sometimes rotates the low 32 bits by one bit when + * combining elements. We want extended hash functions to be compatible with + * that algorithm when the seed is 0, so we can't just do a normal rotation. + * This works, though. + */ +#define ROTATE_HIGH_AND_LOW_32BITS(v) \ + ((((v) << 1) & UINT64CONST(0xfffffffefffffffe)) | \ + (((v) >> 31) & UINT64CONST(0x100000001))) + + +extern uint32 hash_bytes(const unsigned char *k, int keylen); +extern uint64 hash_bytes_extended(const unsigned char *k, + int keylen, uint64 seed); +extern uint32 hash_bytes_uint32(uint32 k); +extern uint64 hash_bytes_uint32_extended(uint32 k, uint64 seed); + +#ifndef FRONTEND +static inline Datum +hash_any(const unsigned char *k, int keylen) +{ + return UInt32GetDatum(hash_bytes(k, keylen)); +} + +static inline Datum +hash_any_extended(const unsigned char *k, int keylen, uint64 seed) +{ + return UInt64GetDatum(hash_bytes_extended(k, keylen, seed)); +} + +static inline Datum +hash_uint32(uint32 k) +{ + return UInt32GetDatum(hash_bytes_uint32(k)); +} + +static inline Datum +hash_uint32_extended(uint32 k, uint64 seed) +{ + return UInt64GetDatum(hash_bytes_uint32_extended(k, seed)); +} +#endif + +extern uint32 string_hash(const void *key, Size keysize); +extern uint32 tag_hash(const void *key, Size keysize); +extern uint32 uint32_hash(const void *key, Size keysize); + +#define oid_hash uint32_hash /* Remove me eventually */ + +/* + * Combine two 32-bit hash values, resulting in another hash value, with + * decent bit mixing. + * + * Similar to boost's hash_combine(). + */ +static inline uint32 +hash_combine(uint32 a, uint32 b) +{ + a ^= b + 0x9e3779b9 + (a << 6) + (a >> 2); + return a; +} + +/* + * Combine two 64-bit hash values, resulting in another hash value, using the + * same kind of technique as hash_combine(). Testing shows that this also + * produces good bit mixing. + */ +static inline uint64 +hash_combine64(uint64 a, uint64 b) +{ + /* 0x49a0f4dd15e5a8e3 is 64bit random data */ + a ^= b + UINT64CONST(0x49a0f4dd15e5a8e3) + (a << 54) + (a >> 7); + return a; +} + +/* + * Simple inline murmur hash implementation hashing a 32 bit integer, for + * performance. + */ +static inline uint32 +murmurhash32(uint32 data) +{ + uint32 h = data; + + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +#endif /* HASHFN_H */ diff --git a/src/include/common/hmac.h b/src/include/common/hmac.h new file mode 100644 index 0000000..c18783f --- /dev/null +++ b/src/include/common/hmac.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * hmac.h + * Generic headers for HMAC + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/hmac.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_HMAC_H +#define PG_HMAC_H + +#include "common/cryptohash.h" + +/* opaque context, private to each HMAC implementation */ +typedef struct pg_hmac_ctx pg_hmac_ctx; + +extern pg_hmac_ctx *pg_hmac_create(pg_cryptohash_type type); +extern int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len); +extern int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len); +extern int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len); +extern void pg_hmac_free(pg_hmac_ctx *ctx); +extern const char *pg_hmac_error(pg_hmac_ctx *ctx); + +#endif /* PG_HMAC_H */ diff --git a/src/include/common/int.h b/src/include/common/int.h new file mode 100644 index 0000000..12a269d --- /dev/null +++ b/src/include/common/int.h @@ -0,0 +1,437 @@ +/*------------------------------------------------------------------------- + * + * int.h + * Routines to perform integer math, while checking for overflows. + * + * The routines in this file are intended to be well defined C, without + * relying on compiler flags like -fwrapv. + * + * To reduce the overhead of these routines try to use compiler intrinsics + * where available. That's not that important for the 16, 32 bit cases, but + * the 64 bit cases can be considerably faster with intrinsics. In case no + * intrinsics are available 128 bit math is used where available. + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/common/int.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMMON_INT_H +#define COMMON_INT_H + + +/*--------- + * The following guidelines apply to all the routines: + * - If a + b overflows, return true, otherwise store the result of a + b + * into *result. The content of *result is implementation defined in case of + * overflow. + * - If a - b overflows, return true, otherwise store the result of a - b + * into *result. The content of *result is implementation defined in case of + * overflow. + * - If a * b overflows, return true, otherwise store the result of a * b + * into *result. The content of *result is implementation defined in case of + * overflow. + *--------- + */ + +/*------------------------------------------------------------------------ + * Overflow routines for signed integers + *------------------------------------------------------------------------ + */ + +/* + * INT16 + */ +static inline bool +pg_add_s16_overflow(int16 a, int16 b, int16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + int32 res = (int32) a + (int32) b; + + if (res > PG_INT16_MAX || res < PG_INT16_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int16) res; + return false; +#endif +} + +static inline bool +pg_sub_s16_overflow(int16 a, int16 b, int16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + int32 res = (int32) a - (int32) b; + + if (res > PG_INT16_MAX || res < PG_INT16_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int16) res; + return false; +#endif +} + +static inline bool +pg_mul_s16_overflow(int16 a, int16 b, int16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#else + int32 res = (int32) a * (int32) b; + + if (res > PG_INT16_MAX || res < PG_INT16_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int16) res; + return false; +#endif +} + +/* + * INT32 + */ +static inline bool +pg_add_s32_overflow(int32 a, int32 b, int32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + int64 res = (int64) a + (int64) b; + + if (res > PG_INT32_MAX || res < PG_INT32_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int32) res; + return false; +#endif +} + +static inline bool +pg_sub_s32_overflow(int32 a, int32 b, int32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + int64 res = (int64) a - (int64) b; + + if (res > PG_INT32_MAX || res < PG_INT32_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int32) res; + return false; +#endif +} + +static inline bool +pg_mul_s32_overflow(int32 a, int32 b, int32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#else + int64 res = (int64) a * (int64) b; + + if (res > PG_INT32_MAX || res < PG_INT32_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int32) res; + return false; +#endif +} + +/* + * INT64 + */ +static inline bool +pg_add_s64_overflow(int64 a, int64 b, int64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#elif defined(HAVE_INT128) + int128 res = (int128) a + (int128) b; + + if (res > PG_INT64_MAX || res < PG_INT64_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int64) res; + return false; +#else + if ((a > 0 && b > 0 && a > PG_INT64_MAX - b) || + (a < 0 && b < 0 && a < PG_INT64_MIN - b)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a + b; + return false; +#endif +} + +static inline bool +pg_sub_s64_overflow(int64 a, int64 b, int64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#elif defined(HAVE_INT128) + int128 res = (int128) a - (int128) b; + + if (res > PG_INT64_MAX || res < PG_INT64_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int64) res; + return false; +#else + if ((a < 0 && b > 0 && a < PG_INT64_MIN + b) || + (a > 0 && b < 0 && a > PG_INT64_MAX + b)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a - b; + return false; +#endif +} + +static inline bool +pg_mul_s64_overflow(int64 a, int64 b, int64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#elif defined(HAVE_INT128) + int128 res = (int128) a * (int128) b; + + if (res > PG_INT64_MAX || res < PG_INT64_MIN) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (int64) res; + return false; +#else + /* + * Overflow can only happen if at least one value is outside the range + * sqrt(min)..sqrt(max) so check that first as the division can be quite a + * bit more expensive than the multiplication. + * + * Multiplying by 0 or 1 can't overflow of course and checking for 0 + * separately avoids any risk of dividing by 0. Be careful about dividing + * INT_MIN by -1 also, note reversing the a and b to ensure we're always + * dividing it by a positive value. + * + */ + if ((a > PG_INT32_MAX || a < PG_INT32_MIN || + b > PG_INT32_MAX || b < PG_INT32_MIN) && + a != 0 && a != 1 && b != 0 && b != 1 && + ((a > 0 && b > 0 && a > PG_INT64_MAX / b) || + (a > 0 && b < 0 && b < PG_INT64_MIN / a) || + (a < 0 && b > 0 && a < PG_INT64_MIN / b) || + (a < 0 && b < 0 && a < PG_INT64_MAX / b))) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a * b; + return false; +#endif +} + +/*------------------------------------------------------------------------ + * Overflow routines for unsigned integers + *------------------------------------------------------------------------ + */ + +/* + * UINT16 + */ +static inline bool +pg_add_u16_overflow(uint16 a, uint16 b, uint16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + uint16 res = a + b; + + if (res < a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +static inline bool +pg_sub_u16_overflow(uint16 a, uint16 b, uint16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + if (b > a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a - b; + return false; +#endif +} + +static inline bool +pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#else + uint32 res = (uint32) a * (uint32) b; + + if (res > PG_UINT16_MAX) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (uint16) res; + return false; +#endif +} + +/* + * INT32 + */ +static inline bool +pg_add_u32_overflow(uint32 a, uint32 b, uint32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + uint32 res = a + b; + + if (res < a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +static inline bool +pg_sub_u32_overflow(uint32 a, uint32 b, uint32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + if (b > a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a - b; + return false; +#endif +} + +static inline bool +pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#else + uint64 res = (uint64) a * (uint64) b; + + if (res > PG_UINT32_MAX) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (uint32) res; + return false; +#endif +} + +/* + * UINT64 + */ +static inline bool +pg_add_u64_overflow(uint64 a, uint64 b, uint64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_add_overflow(a, b, result); +#else + uint64 res = a + b; + + if (res < a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +static inline bool +pg_sub_u64_overflow(uint64 a, uint64 b, uint64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(a, b, result); +#else + if (b > a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = a - b; + return false; +#endif +} + +static inline bool +pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_mul_overflow(a, b, result); +#elif defined(HAVE_INT128) + uint128 res = (uint128) a * (uint128) b; + + if (res > PG_UINT64_MAX) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = (uint64) res; + return false; +#else + uint64 res = a * b; + + if (a != 0 && b != res / a) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + +#endif /* COMMON_INT_H */ diff --git a/src/include/common/int128.h b/src/include/common/int128.h new file mode 100644 index 0000000..8f035cf --- /dev/null +++ b/src/include/common/int128.h @@ -0,0 +1,276 @@ +/*------------------------------------------------------------------------- + * + * int128.h + * Roll-our-own 128-bit integer arithmetic. + * + * We make use of the native int128 type if there is one, otherwise + * implement things the hard way based on two int64 halves. + * + * See src/tools/testint128.c for a simple test harness for this file. + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/common/int128.h + * + *------------------------------------------------------------------------- + */ +#ifndef INT128_H +#define INT128_H + +/* + * For testing purposes, use of native int128 can be switched on/off by + * predefining USE_NATIVE_INT128. + */ +#ifndef USE_NATIVE_INT128 +#ifdef HAVE_INT128 +#define USE_NATIVE_INT128 1 +#else +#define USE_NATIVE_INT128 0 +#endif +#endif + + +#if USE_NATIVE_INT128 + +typedef int128 INT128; + +/* + * Add an unsigned int64 value into an INT128 variable. + */ +static inline void +int128_add_uint64(INT128 *i128, uint64 v) +{ + *i128 += v; +} + +/* + * Add a signed int64 value into an INT128 variable. + */ +static inline void +int128_add_int64(INT128 *i128, int64 v) +{ + *i128 += v; +} + +/* + * Add the 128-bit product of two int64 values into an INT128 variable. + * + * XXX with a stupid compiler, this could actually be less efficient than + * the other implementation; maybe we should do it by hand always? + */ +static inline void +int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y) +{ + *i128 += (int128) x * (int128) y; +} + +/* + * Compare two INT128 values, return -1, 0, or +1. + */ +static inline int +int128_compare(INT128 x, INT128 y) +{ + if (x < y) + return -1; + if (x > y) + return 1; + return 0; +} + +/* + * Widen int64 to INT128. + */ +static inline INT128 +int64_to_int128(int64 v) +{ + return (INT128) v; +} + +/* + * Convert INT128 to int64 (losing any high-order bits). + * This also works fine for casting down to uint64. + */ +static inline int64 +int128_to_int64(INT128 val) +{ + return (int64) val; +} + +#else /* !USE_NATIVE_INT128 */ + +/* + * We lay out the INT128 structure with the same content and byte ordering + * that a native int128 type would (probably) have. This makes no difference + * for ordinary use of INT128, but allows union'ing INT128 with int128 for + * testing purposes. + */ +typedef struct +{ +#ifdef WORDS_BIGENDIAN + int64 hi; /* most significant 64 bits, including sign */ + uint64 lo; /* least significant 64 bits, without sign */ +#else + uint64 lo; /* least significant 64 bits, without sign */ + int64 hi; /* most significant 64 bits, including sign */ +#endif +} INT128; + +/* + * Add an unsigned int64 value into an INT128 variable. + */ +static inline void +int128_add_uint64(INT128 *i128, uint64 v) +{ + /* + * First add the value to the .lo part, then check to see if a carry needs + * to be propagated into the .hi part. A carry is needed if both inputs + * have high bits set, or if just one input has high bit set while the new + * .lo part doesn't. Remember that .lo part is unsigned; we cast to + * signed here just as a cheap way to check the high bit. + */ + uint64 oldlo = i128->lo; + + i128->lo += v; + if (((int64) v < 0 && (int64) oldlo < 0) || + (((int64) v < 0 || (int64) oldlo < 0) && (int64) i128->lo >= 0)) + i128->hi++; +} + +/* + * Add a signed int64 value into an INT128 variable. + */ +static inline void +int128_add_int64(INT128 *i128, int64 v) +{ + /* + * This is much like the above except that the carry logic differs for + * negative v. Ordinarily we'd need to subtract 1 from the .hi part + * (corresponding to adding the sign-extended bits of v to it); but if + * there is a carry out of the .lo part, that cancels and we do nothing. + */ + uint64 oldlo = i128->lo; + + i128->lo += v; + if (v >= 0) + { + if ((int64) oldlo < 0 && (int64) i128->lo >= 0) + i128->hi++; + } + else + { + if (!((int64) oldlo < 0 || (int64) i128->lo >= 0)) + i128->hi--; + } +} + +/* + * INT64_AU32 extracts the most significant 32 bits of int64 as int64, while + * INT64_AL32 extracts the least significant 32 bits as uint64. + */ +#define INT64_AU32(i64) ((i64) >> 32) +#define INT64_AL32(i64) ((i64) & UINT64CONST(0xFFFFFFFF)) + +/* + * Add the 128-bit product of two int64 values into an INT128 variable. + */ +static inline void +int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y) +{ + /* INT64_AU32 must use arithmetic right shift */ + StaticAssertStmt(((int64) -1 >> 1) == (int64) -1, + "arithmetic right shift is needed"); + + /*---------- + * Form the 128-bit product x * y using 64-bit arithmetic. + * Considering each 64-bit input as having 32-bit high and low parts, + * we can compute + * + * x * y = ((x.hi << 32) + x.lo) * (((y.hi << 32) + y.lo) + * = (x.hi * y.hi) << 64 + + * (x.hi * y.lo) << 32 + + * (x.lo * y.hi) << 32 + + * x.lo * y.lo + * + * Each individual product is of 32-bit terms so it won't overflow when + * computed in 64-bit arithmetic. Then we just have to shift it to the + * correct position while adding into the 128-bit result. We must also + * keep in mind that the "lo" parts must be treated as unsigned. + *---------- + */ + + /* No need to work hard if product must be zero */ + if (x != 0 && y != 0) + { + int64 x_u32 = INT64_AU32(x); + uint64 x_l32 = INT64_AL32(x); + int64 y_u32 = INT64_AU32(y); + uint64 y_l32 = INT64_AL32(y); + int64 tmp; + + /* the first term */ + i128->hi += x_u32 * y_u32; + + /* the second term: sign-extend it only if x is negative */ + tmp = x_u32 * y_l32; + if (x < 0) + i128->hi += INT64_AU32(tmp); + else + i128->hi += ((uint64) tmp) >> 32; + int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32); + + /* the third term: sign-extend it only if y is negative */ + tmp = x_l32 * y_u32; + if (y < 0) + i128->hi += INT64_AU32(tmp); + else + i128->hi += ((uint64) tmp) >> 32; + int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32); + + /* the fourth term: always unsigned */ + int128_add_uint64(i128, x_l32 * y_l32); + } +} + +/* + * Compare two INT128 values, return -1, 0, or +1. + */ +static inline int +int128_compare(INT128 x, INT128 y) +{ + if (x.hi < y.hi) + return -1; + if (x.hi > y.hi) + return 1; + if (x.lo < y.lo) + return -1; + if (x.lo > y.lo) + return 1; + return 0; +} + +/* + * Widen int64 to INT128. + */ +static inline INT128 +int64_to_int128(int64 v) +{ + INT128 val; + + val.lo = (uint64) v; + val.hi = (v < 0) ? -INT64CONST(1) : INT64CONST(0); + return val; +} + +/* + * Convert INT128 to int64 (losing any high-order bits). + * This also works fine for casting down to uint64. + */ +static inline int64 +int128_to_int64(INT128 val) +{ + return (int64) val.lo; +} + +#endif /* USE_NATIVE_INT128 */ + +#endif /* INT128_H */ diff --git a/src/include/common/ip.h b/src/include/common/ip.h new file mode 100644 index 0000000..8414520 --- /dev/null +++ b/src/include/common/ip.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * ip.h + * Definitions for IPv6-aware network access. + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/common/ip.h + * + *------------------------------------------------------------------------- + */ +#ifndef IP_H +#define IP_H + +#include "getaddrinfo.h" /* pgrminclude ignore */ +#include "libpq/pqcomm.h" /* pgrminclude ignore */ + + +extern int pg_getaddrinfo_all(const char *hostname, const char *servname, + const struct addrinfo *hintp, + struct addrinfo **result); +extern void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai); + +extern int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, + char *node, int nodelen, + char *service, int servicelen, + int flags); + +#endif /* IP_H */ diff --git a/src/include/common/jsonapi.h b/src/include/common/jsonapi.h new file mode 100644 index 0000000..8d31630 --- /dev/null +++ b/src/include/common/jsonapi.h @@ -0,0 +1,169 @@ +/*------------------------------------------------------------------------- + * + * jsonapi.h + * Declarations for JSON API support. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/jsonapi.h + * + *------------------------------------------------------------------------- + */ + +#ifndef JSONAPI_H +#define JSONAPI_H + +#include "lib/stringinfo.h" + +typedef enum +{ + JSON_TOKEN_INVALID, + JSON_TOKEN_STRING, + JSON_TOKEN_NUMBER, + JSON_TOKEN_OBJECT_START, + JSON_TOKEN_OBJECT_END, + JSON_TOKEN_ARRAY_START, + JSON_TOKEN_ARRAY_END, + JSON_TOKEN_COMMA, + JSON_TOKEN_COLON, + JSON_TOKEN_TRUE, + JSON_TOKEN_FALSE, + JSON_TOKEN_NULL, + JSON_TOKEN_END +} JsonTokenType; + +typedef enum +{ + JSON_SUCCESS, + JSON_ESCAPING_INVALID, + JSON_ESCAPING_REQUIRED, + JSON_EXPECTED_ARRAY_FIRST, + JSON_EXPECTED_ARRAY_NEXT, + JSON_EXPECTED_COLON, + JSON_EXPECTED_END, + JSON_EXPECTED_JSON, + JSON_EXPECTED_MORE, + JSON_EXPECTED_OBJECT_FIRST, + JSON_EXPECTED_OBJECT_NEXT, + JSON_EXPECTED_STRING, + JSON_INVALID_TOKEN, + JSON_UNICODE_CODE_POINT_ZERO, + JSON_UNICODE_ESCAPE_FORMAT, + JSON_UNICODE_HIGH_ESCAPE, + JSON_UNICODE_HIGH_SURROGATE, + JSON_UNICODE_LOW_SURROGATE +} JsonParseErrorType; + + +/* + * All the fields in this structure should be treated as read-only. + * + * If strval is not null, then it should contain the de-escaped value + * of the lexeme if it's a string. Otherwise most of these field names + * should be self-explanatory. + * + * line_number and line_start are principally for use by the parser's + * error reporting routines. + * token_terminator and prev_token_terminator point to the character + * AFTER the end of the token, i.e. where there would be a nul byte + * if we were using nul-terminated strings. + */ +typedef struct JsonLexContext +{ + char *input; + int input_length; + int input_encoding; + char *token_start; + char *token_terminator; + char *prev_token_terminator; + JsonTokenType token_type; + int lex_level; + int line_number; /* line number, starting from 1 */ + char *line_start; /* where that line starts within input */ + StringInfo strval; +} JsonLexContext; + +typedef void (*json_struct_action) (void *state); +typedef void (*json_ofield_action) (void *state, char *fname, bool isnull); +typedef void (*json_aelem_action) (void *state, bool isnull); +typedef void (*json_scalar_action) (void *state, char *token, JsonTokenType tokentype); + + +/* + * Semantic Action structure for use in parsing json. + * Any of these actions can be NULL, in which case nothing is done at that + * point, Likewise, semstate can be NULL. Using an all-NULL structure amounts + * to doing a pure parse with no side-effects, and is therefore exactly + * what the json input routines do. + * + * The 'fname' and 'token' strings passed to these actions are palloc'd. + * They are not free'd or used further by the parser, so the action function + * is free to do what it wishes with them. + */ +typedef struct JsonSemAction +{ + void *semstate; + json_struct_action object_start; + json_struct_action object_end; + json_struct_action array_start; + json_struct_action array_end; + json_ofield_action object_field_start; + json_ofield_action object_field_end; + json_aelem_action array_element_start; + json_aelem_action array_element_end; + json_scalar_action scalar; +} JsonSemAction; + +/* + * pg_parse_json will parse the string in the lex calling the + * action functions in sem at the appropriate points. It is + * up to them to keep what state they need in semstate. If they + * need access to the state of the lexer, then its pointer + * should be passed to them as a member of whatever semstate + * points to. If the action pointers are NULL the parser + * does nothing and just continues. + */ +extern JsonParseErrorType pg_parse_json(JsonLexContext *lex, + JsonSemAction *sem); + +/* the null action object used for pure validation */ +extern PGDLLIMPORT JsonSemAction nullSemAction; + +/* + * json_count_array_elements performs a fast secondary parse to determine the + * number of elements in passed array lex context. It should be called from an + * array_start action. + * + * The return value indicates whether any error occurred, while the number + * of elements is stored into *elements (but only if the return value is + * JSON_SUCCESS). + */ +extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex, + int *elements); + +/* + * constructor for JsonLexContext, with or without strval element. + * If supplied, the strval element will contain a de-escaped version of + * the lexeme. However, doing this imposes a performance penalty, so + * it should be avoided if the de-escaped lexeme is not required. + */ +extern JsonLexContext *makeJsonLexContextCstringLen(char *json, + int len, + int encoding, + bool need_escapes); + +/* lex one token */ +extern JsonParseErrorType json_lex(JsonLexContext *lex); + +/* construct an error detail string for a json error */ +extern char *json_errdetail(JsonParseErrorType error, JsonLexContext *lex); + +/* + * Utility function to check if a string is a valid JSON number. + * + * str argument does not need to be nul-terminated. + */ +extern bool IsValidJsonNumber(const char *str, int len); + +#endif /* JSONAPI_H */ diff --git a/src/include/common/keywords.h b/src/include/common/keywords.h new file mode 100644 index 0000000..b85237f --- /dev/null +++ b/src/include/common/keywords.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * keywords.h + * PostgreSQL's list of SQL keywords + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/keywords.h + * + *------------------------------------------------------------------------- + */ +#ifndef KEYWORDS_H +#define KEYWORDS_H + +#include "common/kwlookup.h" + +/* Keyword categories --- should match lists in gram.y */ +#define UNRESERVED_KEYWORD 0 +#define COL_NAME_KEYWORD 1 +#define TYPE_FUNC_NAME_KEYWORD 2 +#define RESERVED_KEYWORD 3 + +extern PGDLLIMPORT const ScanKeywordList ScanKeywords; +extern PGDLLIMPORT const uint8 ScanKeywordCategories[]; +extern PGDLLIMPORT const bool ScanKeywordBareLabel[]; + +#endif /* KEYWORDS_H */ diff --git a/src/include/common/kwlookup.h b/src/include/common/kwlookup.h new file mode 100644 index 0000000..48d7f08 --- /dev/null +++ b/src/include/common/kwlookup.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * kwlookup.h + * Key word lookup for PostgreSQL + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/kwlookup.h + * + *------------------------------------------------------------------------- + */ +#ifndef KWLOOKUP_H +#define KWLOOKUP_H + +/* Hash function used by ScanKeywordLookup */ +typedef int (*ScanKeywordHashFunc) (const void *key, size_t keylen); + +/* + * This struct contains the data needed by ScanKeywordLookup to perform a + * search within a set of keywords. The contents are typically generated by + * src/tools/gen_keywordlist.pl from a header containing PG_KEYWORD macros. + */ +typedef struct ScanKeywordList +{ + const char *kw_string; /* all keywords in order, separated by \0 */ + const uint16 *kw_offsets; /* offsets to the start of each keyword */ + ScanKeywordHashFunc hash; /* perfect hash function for keywords */ + int num_keywords; /* number of keywords */ + int max_kw_len; /* length of longest keyword */ +} ScanKeywordList; + + +extern int ScanKeywordLookup(const char *text, const ScanKeywordList *keywords); + +/* Code that wants to retrieve the text of the N'th keyword should use this. */ +static inline const char * +GetScanKeyword(int n, const ScanKeywordList *keywords) +{ + return keywords->kw_string + keywords->kw_offsets[n]; +} + +#endif /* KWLOOKUP_H */ diff --git a/src/include/common/link-canary.h b/src/include/common/link-canary.h new file mode 100644 index 0000000..4733cd2 --- /dev/null +++ b/src/include/common/link-canary.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * link-canary.h + * Detect whether src/common functions came from frontend or backend. + * + * Copyright (c) 2018-2022, PostgreSQL Global Development Group + * + * src/include/common/link-canary.h + * + *------------------------------------------------------------------------- + */ +#ifndef LINK_CANARY_H +#define LINK_CANARY_H + +extern bool pg_link_canary_is_frontend(void); + +#endif /* LINK_CANARY_H */ diff --git a/src/include/common/logging.h b/src/include/common/logging.h new file mode 100644 index 0000000..9f426c3 --- /dev/null +++ b/src/include/common/logging.h @@ -0,0 +1,156 @@ +/*------------------------------------------------------------------------- + * Logging framework for frontend programs + * + * Copyright (c) 2018-2022, PostgreSQL Global Development Group + * + * src/include/common/logging.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMMON_LOGGING_H +#define COMMON_LOGGING_H + +/* + * Log levels are informational only. They do not affect program flow. + */ +enum pg_log_level +{ + /* + * Not initialized yet (not to be used as an actual message log level). + */ + PG_LOG_NOTSET = 0, + + /* + * Low level messages that are normally off by default. + */ + PG_LOG_DEBUG, + + /* + * Any program messages that go to stderr, shown by default. (The + * program's normal output should go to stdout and not use the logging + * system.) + */ + PG_LOG_INFO, + + /* + * Warnings and "almost" errors, depends on the program + */ + PG_LOG_WARNING, + + /* + * Errors + */ + PG_LOG_ERROR, + + /* + * Turn all logging off (not to be used as an actual message log level). + */ + PG_LOG_OFF, +}; + +/* + * __pg_log_level is the minimum log level that will actually be shown. + */ +extern enum pg_log_level __pg_log_level; + +/* + * A log message can have several parts. The primary message is required, + * others are optional. When emitting multiple parts, do so in the order of + * this enum, for consistency. + */ +enum pg_log_part +{ + /* + * The primary message. Try to keep it to one line; follow the backend's + * style guideline for primary messages. + */ + PG_LOG_PRIMARY, + + /* + * Additional detail. Follow the backend's style guideline for detail + * messages. + */ + PG_LOG_DETAIL, + + /* + * Hint (not guaranteed correct) about how to fix the problem. Follow the + * backend's style guideline for hint messages. + */ + PG_LOG_HINT, +}; + +/* + * Kind of a hack to be able to produce the psql output exactly as required by + * the regression tests. + */ +#define PG_LOG_FLAG_TERSE 1 + +void pg_logging_init(const char *argv0); +void pg_logging_config(int new_flags); +void pg_logging_set_level(enum pg_log_level new_level); +void pg_logging_increase_verbosity(void); +void pg_logging_set_pre_callback(void (*cb) (void)); +void pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno)); + +void pg_log_generic(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt,...) + pg_attribute_printf(3, 4); +void pg_log_generic_v(enum pg_log_level level, enum pg_log_part part, + const char *pg_restrict fmt, va_list ap) + pg_attribute_printf(3, 0); + +/* + * Preferred style is to use these macros to perform logging; don't call + * pg_log_generic[_v] directly, except perhaps in error interface code. + */ +#define pg_log_error(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_error_detail(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_error_hint(...) \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_warning(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_warning_detail(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_warning_hint(...) \ + pg_log_generic(PG_LOG_WARNING, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_info(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_PRIMARY, __VA_ARGS__) + +#define pg_log_info_detail(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_DETAIL, __VA_ARGS__) + +#define pg_log_info_hint(...) \ + pg_log_generic(PG_LOG_INFO, PG_LOG_HINT, __VA_ARGS__) + +#define pg_log_debug(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_PRIMARY, __VA_ARGS__); \ + } while(0) + +#define pg_log_debug_detail(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_DETAIL, __VA_ARGS__); \ + } while(0) + +#define pg_log_debug_hint(...) do { \ + if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) \ + pg_log_generic(PG_LOG_DEBUG, PG_LOG_HINT, __VA_ARGS__); \ + } while(0) + +/* + * A common shortcut: pg_log_error() and immediately exit(1). + */ +#define pg_fatal(...) do { \ + pg_log_generic(PG_LOG_ERROR, PG_LOG_PRIMARY, __VA_ARGS__); \ + exit(1); \ + } while(0) + +#endif /* COMMON_LOGGING_H */ diff --git a/src/include/common/md5.h b/src/include/common/md5.h new file mode 100644 index 0000000..942ca42 --- /dev/null +++ b/src/include/common/md5.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * md5.h + * Constants and common utilities related to MD5. + * + * These definitions are needed by both frontend and backend code to work + * with MD5-encrypted passwords. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/md5.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_MD5_H +#define PG_MD5_H + +/* Size of result generated by MD5 computation */ +#define MD5_DIGEST_LENGTH 16 +/* Block size for MD5 */ +#define MD5_BLOCK_SIZE 64 + +/* password-related data */ +#define MD5_PASSWD_CHARSET "0123456789abcdef" +#define MD5_PASSWD_LEN 35 + +/* Utilities common to all the MD5 implementations, as of md5_common.c */ +extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum, + const char **errstr); +extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf, + const char **errstr); +extern bool pg_md5_encrypt(const char *passwd, const char *salt, + size_t salt_len, char *buf, + const char **errstr); + +#endif /* PG_MD5_H */ diff --git a/src/include/common/openssl.h b/src/include/common/openssl.h new file mode 100644 index 0000000..aae5a34 --- /dev/null +++ b/src/include/common/openssl.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * openssl.h + * OpenSSL supporting functionality shared between frontend and backend + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/openssl.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMMON_OPENSSL_H +#define COMMON_OPENSSL_H + +#ifdef USE_OPENSSL +#include <openssl/ssl.h> + +/* + * OpenSSL doesn't provide any very nice way to identify the min/max + * protocol versions the library supports, so we fake it as best we can. + * Note in particular that this doesn't account for restrictions that + * might be specified in the installation's openssl.cnf. + * + * We disable SSLv3 and older in library setup, so TLSv1 is the oldest + * protocol version of interest. + */ +#define MIN_OPENSSL_TLS_VERSION "TLSv1" + +#if defined(TLS1_3_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.3" +#elif defined(TLS1_2_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.2" +#elif defined(TLS1_1_VERSION) +#define MAX_OPENSSL_TLS_VERSION "TLSv1.1" +#else +#define MAX_OPENSSL_TLS_VERSION "TLSv1" +#endif + +/* src/common/protocol_openssl.c */ +#ifndef SSL_CTX_set_min_proto_version +extern int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version); +extern int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version); +#endif + +#endif /* USE_OPENSSL */ + +#endif /* COMMON_OPENSSL_H */ diff --git a/src/include/common/pg_lzcompress.h b/src/include/common/pg_lzcompress.h new file mode 100644 index 0000000..2a12b33 --- /dev/null +++ b/src/include/common/pg_lzcompress.h @@ -0,0 +1,93 @@ +/* ---------- + * pg_lzcompress.h - + * + * Definitions for the builtin LZ compressor + * + * src/include/common/pg_lzcompress.h + * ---------- + */ + +#ifndef _PG_LZCOMPRESS_H_ +#define _PG_LZCOMPRESS_H_ + + +/* ---------- + * PGLZ_MAX_OUTPUT - + * + * Macro to compute the buffer size required by pglz_compress(). + * We allow 4 bytes for overrun before detecting compression failure. + * ---------- + */ +#define PGLZ_MAX_OUTPUT(_dlen) ((_dlen) + 4) + + +/* ---------- + * PGLZ_Strategy - + * + * Some values that control the compression algorithm. + * + * min_input_size Minimum input data size to consider compression. + * + * max_input_size Maximum input data size to consider compression. + * + * min_comp_rate Minimum compression rate (0-99%) to require. + * Regardless of min_comp_rate, the output must be + * smaller than the input, else we don't store + * compressed. + * + * first_success_by Abandon compression if we find no compressible + * data within the first this-many bytes. + * + * match_size_good The initial GOOD match size when starting history + * lookup. When looking up the history to find a + * match that could be expressed as a tag, the + * algorithm does not always walk back entirely. + * A good match fast is usually better than the + * best possible one very late. For each iteration + * in the lookup, this value is lowered so the + * longer the lookup takes, the smaller matches + * are considered good. + * + * match_size_drop The percentage by which match_size_good is lowered + * after each history check. Allowed values are + * 0 (no change until end) to 100 (only check + * latest history entry at all). + * ---------- + */ +typedef struct PGLZ_Strategy +{ + int32 min_input_size; + int32 max_input_size; + int32 min_comp_rate; + int32 first_success_by; + int32 match_size_good; + int32 match_size_drop; +} PGLZ_Strategy; + + +/* ---------- + * The standard strategies + * + * PGLZ_strategy_default Recommended default strategy for TOAST. + * + * PGLZ_strategy_always Try to compress inputs of any length. + * Fallback to uncompressed storage only if + * output would be larger than input. + * ---------- + */ +extern PGDLLIMPORT const PGLZ_Strategy *const PGLZ_strategy_default; +extern PGDLLIMPORT const PGLZ_Strategy *const PGLZ_strategy_always; + + +/* ---------- + * Global function declarations + * ---------- + */ +extern int32 pglz_compress(const char *source, int32 slen, char *dest, + const PGLZ_Strategy *strategy); +extern int32 pglz_decompress(const char *source, int32 slen, char *dest, + int32 rawsize, bool check_complete); +extern int32 pglz_maximum_compressed_size(int32 rawsize, + int32 total_compressed_size); + +#endif /* _PG_LZCOMPRESS_H_ */ diff --git a/src/include/common/pg_prng.h b/src/include/common/pg_prng.h new file mode 100644 index 0000000..d9895b4 --- /dev/null +++ b/src/include/common/pg_prng.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * Pseudo-Random Number Generator + * + * Copyright (c) 2021-2022, PostgreSQL Global Development Group + * + * src/include/common/pg_prng.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PRNG_H +#define PG_PRNG_H + +/* + * State vector for PRNG generation. Callers should treat this as an + * opaque typedef, but we expose its definition to allow it to be + * embedded in other structs. + */ +typedef struct pg_prng_state +{ + uint64 s0, + s1; +} pg_prng_state; + +/* + * Callers not needing local PRNG series may use this global state vector, + * after initializing it with one of the pg_prng_...seed functions. + */ +extern PGDLLIMPORT pg_prng_state pg_global_prng_state; + +extern void pg_prng_seed(pg_prng_state *state, uint64 seed); +extern void pg_prng_fseed(pg_prng_state *state, double fseed); +extern bool pg_prng_seed_check(pg_prng_state *state); + +/* + * Initialize the PRNG state from the pg_strong_random source, + * taking care that we don't produce all-zeroes. If this returns false, + * caller should initialize the PRNG state from some other random seed, + * using pg_prng_[f]seed. + * + * We implement this as a macro, so that the pg_strong_random() call is + * in the caller. If it were in pg_prng.c, programs using pg_prng.c + * but not needing strong seeding would nonetheless be forced to pull in + * pg_strong_random.c and thence OpenSSL. + */ +#define pg_prng_strong_seed(state) \ + (pg_strong_random((void *) (state), sizeof(pg_prng_state)) ? \ + pg_prng_seed_check(state) : false) + +extern uint64 pg_prng_uint64(pg_prng_state *state); +extern uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax); +extern int64 pg_prng_int64(pg_prng_state *state); +extern int64 pg_prng_int64p(pg_prng_state *state); +extern uint32 pg_prng_uint32(pg_prng_state *state); +extern int32 pg_prng_int32(pg_prng_state *state); +extern int32 pg_prng_int32p(pg_prng_state *state); +extern double pg_prng_double(pg_prng_state *state); +extern bool pg_prng_bool(pg_prng_state *state); + +#endif /* PG_PRNG_H */ diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h new file mode 100644 index 0000000..13849a3 --- /dev/null +++ b/src/include/common/relpath.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * relpath.h + * Declarations for GetRelationPath() and friends + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/relpath.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELPATH_H +#define RELPATH_H + +/* + * 'pgrminclude ignore' needed here because CppAsString2() does not throw + * an error if the symbol is not defined. + */ +#include "catalog/catversion.h" /* pgrminclude ignore */ + + +/* + * Name of major-version-specific tablespace subdirectories + */ +#define TABLESPACE_VERSION_DIRECTORY "PG_" PG_MAJORVERSION "_" \ + CppAsString2(CATALOG_VERSION_NO) + +/* Characters to allow for an OID in a relation path */ +#define OIDCHARS 10 /* max chars printed by %u */ + +/* + * Stuff for fork names. + * + * The physical storage of a relation consists of one or more forks. + * The main fork is always created, but in addition to that there can be + * additional forks for storing various metadata. ForkNumber is used when + * we need to refer to a specific fork in a relation. + */ +typedef enum ForkNumber +{ + InvalidForkNumber = -1, + MAIN_FORKNUM = 0, + FSM_FORKNUM, + VISIBILITYMAP_FORKNUM, + INIT_FORKNUM + + /* + * NOTE: if you add a new fork, change MAX_FORKNUM and possibly + * FORKNAMECHARS below, and update the forkNames array in + * src/common/relpath.c + */ +} ForkNumber; + +#define MAX_FORKNUM INIT_FORKNUM + +#define FORKNAMECHARS 4 /* max chars for a fork name */ + +extern PGDLLIMPORT const char *const forkNames[]; + +extern ForkNumber forkname_to_number(const char *forkName); +extern int forkname_chars(const char *str, ForkNumber *fork); + +/* + * Stuff for computing filesystem pathnames for relations. + */ +extern char *GetDatabasePath(Oid dbNode, Oid spcNode); + +extern char *GetRelationPath(Oid dbNode, Oid spcNode, Oid relNode, + int backendId, ForkNumber forkNumber); + +/* + * Wrapper macros for GetRelationPath. Beware of multiple + * evaluation of the RelFileNode or RelFileNodeBackend argument! + */ + +/* First argument is a RelFileNode */ +#define relpathbackend(rnode, backend, forknum) \ + GetRelationPath((rnode).dbNode, (rnode).spcNode, (rnode).relNode, \ + backend, forknum) + +/* First argument is a RelFileNode */ +#define relpathperm(rnode, forknum) \ + relpathbackend(rnode, InvalidBackendId, forknum) + +/* First argument is a RelFileNodeBackend */ +#define relpath(rnode, forknum) \ + relpathbackend((rnode).node, (rnode).backend, forknum) + +#endif /* RELPATH_H */ diff --git a/src/include/common/restricted_token.h b/src/include/common/restricted_token.h new file mode 100644 index 0000000..0b6bdaf --- /dev/null +++ b/src/include/common/restricted_token.h @@ -0,0 +1,24 @@ +/* + * restricted_token.h + * helper routine to ensure restricted token on Windows + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/restricted_token.h + */ +#ifndef COMMON_RESTRICTED_TOKEN_H +#define COMMON_RESTRICTED_TOKEN_H + +/* + * On Windows make sure that we are running with a restricted token, + * On other platforms do nothing. + */ +void get_restricted_token(void); + +#ifdef WIN32 +/* Create a restricted token and execute the specified process with it. */ +HANDLE CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo); +#endif + +#endif /* COMMON_RESTRICTED_TOKEN_H */ diff --git a/src/include/common/saslprep.h b/src/include/common/saslprep.h new file mode 100644 index 0000000..305c8f4 --- /dev/null +++ b/src/include/common/saslprep.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * saslprep.h + * SASLprep normalization, for SCRAM authentication + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/common/saslprep.h + * + *------------------------------------------------------------------------- + */ +#ifndef SASLPREP_H +#define SASLPREP_H + +/* + * Return codes for pg_saslprep() function. + */ +typedef enum +{ + SASLPREP_SUCCESS = 0, + SASLPREP_OOM = -1, /* out of memory (only in frontend) */ + SASLPREP_INVALID_UTF8 = -2, /* input is not a valid UTF-8 string */ + SASLPREP_PROHIBITED = -3 /* output would contain prohibited characters */ +} pg_saslprep_rc; + +extern pg_saslprep_rc pg_saslprep(const char *input, char **output); + +#endif /* SASLPREP_H */ diff --git a/src/include/common/scram-common.h b/src/include/common/scram-common.h new file mode 100644 index 0000000..d1f840c --- /dev/null +++ b/src/include/common/scram-common.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- + * + * scram-common.h + * Declarations for helper functions used for SCRAM authentication + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/scram-common.h + * + *------------------------------------------------------------------------- + */ +#ifndef SCRAM_COMMON_H +#define SCRAM_COMMON_H + +#include "common/cryptohash.h" +#include "common/sha2.h" + +/* Name of SCRAM mechanisms per IANA */ +#define SCRAM_SHA_256_NAME "SCRAM-SHA-256" +#define SCRAM_SHA_256_PLUS_NAME "SCRAM-SHA-256-PLUS" /* with channel binding */ + +/* Length of SCRAM keys (client and server) */ +#define SCRAM_KEY_LEN PG_SHA256_DIGEST_LENGTH + +/* length of HMAC */ +#define SHA256_HMAC_B PG_SHA256_BLOCK_LENGTH + +/* + * Size of random nonce generated in the authentication exchange. This + * is in "raw" number of bytes, the actual nonces sent over the wire are + * encoded using only ASCII-printable characters. + */ +#define SCRAM_RAW_NONCE_LEN 18 + +/* + * Length of salt when generating new secrets, in bytes. (It will be stored + * and sent over the wire encoded in Base64.) 16 bytes is what the example in + * RFC 7677 uses. + */ +#define SCRAM_DEFAULT_SALT_LEN 16 + +/* + * Default number of iterations when generating secret. Should be at least + * 4096 per RFC 7677. + */ +#define SCRAM_DEFAULT_ITERATIONS 4096 + +extern int scram_SaltedPassword(const char *password, const char *salt, + int saltlen, int iterations, uint8 *result, + const char **errstr); +extern int scram_H(const uint8 *str, int len, uint8 *result, + const char **errstr); +extern int scram_ClientKey(const uint8 *salted_password, uint8 *result, + const char **errstr); +extern int scram_ServerKey(const uint8 *salted_password, uint8 *result, + const char **errstr); + +extern char *scram_build_secret(const char *salt, int saltlen, int iterations, + const char *password, const char **errstr); + +#endif /* SCRAM_COMMON_H */ diff --git a/src/include/common/sha1.h b/src/include/common/sha1.h new file mode 100644 index 0000000..e8cb360 --- /dev/null +++ b/src/include/common/sha1.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * sha1.h + * Constants related to SHA1. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/sha1.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHA1_H +#define PG_SHA1_H + +/* Size of result generated by SHA1 computation */ +#define SHA1_DIGEST_LENGTH 20 +/* Block size for SHA1 */ +#define SHA1_BLOCK_SIZE 64 + +#endif /* PG_SHA1_H */ diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h new file mode 100644 index 0000000..fe248e9 --- /dev/null +++ b/src/include/common/sha2.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * sha2.h + * Constants related to SHA224, 256, 384 AND 512. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/sha2.h + * + *------------------------------------------------------------------------- + */ + +#ifndef _PG_SHA2_H_ +#define _PG_SHA2_H_ + +/*** SHA224/256/384/512 Various Length Definitions ***********************/ +#define PG_SHA224_BLOCK_LENGTH 64 +#define PG_SHA224_DIGEST_LENGTH 28 +#define PG_SHA224_DIGEST_STRING_LENGTH (PG_SHA224_DIGEST_LENGTH * 2 + 1) +#define PG_SHA256_BLOCK_LENGTH 64 +#define PG_SHA256_DIGEST_LENGTH 32 +#define PG_SHA256_DIGEST_STRING_LENGTH (PG_SHA256_DIGEST_LENGTH * 2 + 1) +#define PG_SHA384_BLOCK_LENGTH 128 +#define PG_SHA384_DIGEST_LENGTH 48 +#define PG_SHA384_DIGEST_STRING_LENGTH (PG_SHA384_DIGEST_LENGTH * 2 + 1) +#define PG_SHA512_BLOCK_LENGTH 128 +#define PG_SHA512_DIGEST_LENGTH 64 +#define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1) + +#endif /* _PG_SHA2_H_ */ diff --git a/src/include/common/shortest_dec.h b/src/include/common/shortest_dec.h new file mode 100644 index 0000000..f919f7f --- /dev/null +++ b/src/include/common/shortest_dec.h @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------- + * + * Ryu floating-point output. + * + * Portions Copyright (c) 2018-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/common/shortest_dec.h + * + * This is a modification of code taken from github.com/ulfjack/ryu under the + * terms of the Boost license (not the Apache license). The original copyright + * notice follows: + * + * Copyright 2018 Ulf Adams + * + * The contents of this file may be used under the terms of the Apache + * License, Version 2.0. + * + * (See accompanying file LICENSE-Apache or copy at + * http://www.apache.org/licenses/LICENSE-2.0) + * + * Alternatively, the contents of this file may be used under the terms of the + * Boost Software License, Version 1.0. + * + * (See accompanying file LICENSE-Boost or copy at + * https://www.boost.org/LICENSE_1_0.txt) + * + * Unless required by applicable law or agreed to in writing, this software is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. + * + *--------------------------------------------------------------------------- + */ +#ifndef SHORTEST_DEC_H +#define SHORTEST_DEC_H + +/*---- + * The length of 25 comes from: + * + * Case 1: -9.9999999999999999e-299 = 24 bytes, plus 1 for null + * + * Case 2: -0.00099999999999999999 = 23 bytes, plus 1 for null + */ +#define DOUBLE_SHORTEST_DECIMAL_LEN 25 + +int double_to_shortest_decimal_bufn(double f, char *result); +int double_to_shortest_decimal_buf(double f, char *result); +char *double_to_shortest_decimal(double f); + +/* + * The length of 16 comes from: + * + * Case 1: -9.99999999e+29 = 15 bytes, plus 1 for null + * + * Case 2: -0.000999999999 = 15 bytes, plus 1 for null + */ +#define FLOAT_SHORTEST_DECIMAL_LEN 16 + +int float_to_shortest_decimal_bufn(float f, char *result); +int float_to_shortest_decimal_buf(float f, char *result); +char *float_to_shortest_decimal(float f); + +#endif /* SHORTEST_DEC_H */ diff --git a/src/include/common/string.h b/src/include/common/string.h new file mode 100644 index 0000000..cf00fb5 --- /dev/null +++ b/src/include/common/string.h @@ -0,0 +1,42 @@ +/* + * string.h + * string handling helpers + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/string.h + */ +#ifndef COMMON_STRING_H +#define COMMON_STRING_H + +struct StringInfoData; /* avoid including stringinfo.h here */ + +typedef struct PromptInterruptContext +{ + /* To avoid including <setjmp.h> here, jmpbuf is declared "void *" */ + void *jmpbuf; /* existing longjmp buffer */ + volatile bool *enabled; /* flag that enables longjmp-on-interrupt */ + bool canceled; /* indicates whether cancellation occurred */ +} PromptInterruptContext; + +/* functions in src/common/string.c */ +extern bool pg_str_endswith(const char *str, const char *end); +extern int strtoint(const char *pg_restrict str, char **pg_restrict endptr, + int base); +extern void pg_clean_ascii(char *str); +extern int pg_strip_crlf(char *str); +extern bool pg_is_ascii(const char *str); + +/* functions in src/common/pg_get_line.c */ +extern char *pg_get_line(FILE *stream, PromptInterruptContext *prompt_ctx); +extern bool pg_get_line_buf(FILE *stream, struct StringInfoData *buf); +extern bool pg_get_line_append(FILE *stream, struct StringInfoData *buf, + PromptInterruptContext *prompt_ctx); + +/* functions in src/common/sprompt.c */ +extern char *simple_prompt(const char *prompt, bool echo); +extern char *simple_prompt_extended(const char *prompt, bool echo, + PromptInterruptContext *prompt_ctx); + +#endif /* COMMON_STRING_H */ diff --git a/src/include/common/unicode_combining_table.h b/src/include/common/unicode_combining_table.h new file mode 100644 index 0000000..de1eab3 --- /dev/null +++ b/src/include/common/unicode_combining_table.h @@ -0,0 +1,308 @@ +/* generated by src/common/unicode/generate-unicode_combining_table.pl, do not edit */ + +static const struct mbinterval combining[] = { + {0x0300, 0x036F}, + {0x0483, 0x0489}, + {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, + {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, + {0x0610, 0x061A}, + {0x064B, 0x065F}, + {0x0670, 0x0670}, + {0x06D6, 0x06DC}, + {0x06DF, 0x06E4}, + {0x06E7, 0x06E8}, + {0x06EA, 0x06ED}, + {0x0711, 0x0711}, + {0x0730, 0x074A}, + {0x07A6, 0x07B0}, + {0x07EB, 0x07F3}, + {0x07FD, 0x07FD}, + {0x0816, 0x0819}, + {0x081B, 0x0823}, + {0x0825, 0x0827}, + {0x0829, 0x082D}, + {0x0859, 0x085B}, + {0x0898, 0x089F}, + {0x08CA, 0x08E1}, + {0x08E3, 0x0902}, + {0x093A, 0x093A}, + {0x093C, 0x093C}, + {0x0941, 0x0948}, + {0x094D, 0x094D}, + {0x0951, 0x0957}, + {0x0962, 0x0963}, + {0x0981, 0x0981}, + {0x09BC, 0x09BC}, + {0x09C1, 0x09C4}, + {0x09CD, 0x09CD}, + {0x09E2, 0x09E3}, + {0x09FE, 0x0A02}, + {0x0A3C, 0x0A3C}, + {0x0A41, 0x0A51}, + {0x0A70, 0x0A71}, + {0x0A75, 0x0A75}, + {0x0A81, 0x0A82}, + {0x0ABC, 0x0ABC}, + {0x0AC1, 0x0AC8}, + {0x0ACD, 0x0ACD}, + {0x0AE2, 0x0AE3}, + {0x0AFA, 0x0B01}, + {0x0B3C, 0x0B3C}, + {0x0B3F, 0x0B3F}, + {0x0B41, 0x0B44}, + {0x0B4D, 0x0B56}, + {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, + {0x0BC0, 0x0BC0}, + {0x0BCD, 0x0BCD}, + {0x0C00, 0x0C00}, + {0x0C04, 0x0C04}, + {0x0C3C, 0x0C3C}, + {0x0C3E, 0x0C40}, + {0x0C46, 0x0C56}, + {0x0C62, 0x0C63}, + {0x0C81, 0x0C81}, + {0x0CBC, 0x0CBC}, + {0x0CBF, 0x0CBF}, + {0x0CC6, 0x0CC6}, + {0x0CCC, 0x0CCD}, + {0x0CE2, 0x0CE3}, + {0x0D00, 0x0D01}, + {0x0D3B, 0x0D3C}, + {0x0D41, 0x0D44}, + {0x0D4D, 0x0D4D}, + {0x0D62, 0x0D63}, + {0x0D81, 0x0D81}, + {0x0DCA, 0x0DCA}, + {0x0DD2, 0x0DD6}, + {0x0E31, 0x0E31}, + {0x0E34, 0x0E3A}, + {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, + {0x0EB4, 0x0EBC}, + {0x0EC8, 0x0ECD}, + {0x0F18, 0x0F19}, + {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, + {0x0F71, 0x0F7E}, + {0x0F80, 0x0F84}, + {0x0F86, 0x0F87}, + {0x0F8D, 0x0FBC}, + {0x0FC6, 0x0FC6}, + {0x102D, 0x1030}, + {0x1032, 0x1037}, + {0x1039, 0x103A}, + {0x103D, 0x103E}, + {0x1058, 0x1059}, + {0x105E, 0x1060}, + {0x1071, 0x1074}, + {0x1082, 0x1082}, + {0x1085, 0x1086}, + {0x108D, 0x108D}, + {0x109D, 0x109D}, + {0x135D, 0x135F}, + {0x1712, 0x1714}, + {0x1732, 0x1733}, + {0x1752, 0x1753}, + {0x1772, 0x1773}, + {0x17B4, 0x17B5}, + {0x17B7, 0x17BD}, + {0x17C6, 0x17C6}, + {0x17C9, 0x17D3}, + {0x17DD, 0x17DD}, + {0x180B, 0x180D}, + {0x180F, 0x180F}, + {0x1885, 0x1886}, + {0x18A9, 0x18A9}, + {0x1920, 0x1922}, + {0x1927, 0x1928}, + {0x1932, 0x1932}, + {0x1939, 0x193B}, + {0x1A17, 0x1A18}, + {0x1A1B, 0x1A1B}, + {0x1A56, 0x1A56}, + {0x1A58, 0x1A60}, + {0x1A62, 0x1A62}, + {0x1A65, 0x1A6C}, + {0x1A73, 0x1A7F}, + {0x1AB0, 0x1B03}, + {0x1B34, 0x1B34}, + {0x1B36, 0x1B3A}, + {0x1B3C, 0x1B3C}, + {0x1B42, 0x1B42}, + {0x1B6B, 0x1B73}, + {0x1B80, 0x1B81}, + {0x1BA2, 0x1BA5}, + {0x1BA8, 0x1BA9}, + {0x1BAB, 0x1BAD}, + {0x1BE6, 0x1BE6}, + {0x1BE8, 0x1BE9}, + {0x1BED, 0x1BED}, + {0x1BEF, 0x1BF1}, + {0x1C2C, 0x1C33}, + {0x1C36, 0x1C37}, + {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE0}, + {0x1CE2, 0x1CE8}, + {0x1CED, 0x1CED}, + {0x1CF4, 0x1CF4}, + {0x1CF8, 0x1CF9}, + {0x1DC0, 0x1DFF}, + {0x20D0, 0x20F0}, + {0x2CEF, 0x2CF1}, + {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, + {0x302A, 0x302D}, + {0x3099, 0x309A}, + {0xA66F, 0xA672}, + {0xA674, 0xA67D}, + {0xA69E, 0xA69F}, + {0xA6F0, 0xA6F1}, + {0xA802, 0xA802}, + {0xA806, 0xA806}, + {0xA80B, 0xA80B}, + {0xA825, 0xA826}, + {0xA82C, 0xA82C}, + {0xA8C4, 0xA8C5}, + {0xA8E0, 0xA8F1}, + {0xA8FF, 0xA8FF}, + {0xA926, 0xA92D}, + {0xA947, 0xA951}, + {0xA980, 0xA982}, + {0xA9B3, 0xA9B3}, + {0xA9B6, 0xA9B9}, + {0xA9BC, 0xA9BD}, + {0xA9E5, 0xA9E5}, + {0xAA29, 0xAA2E}, + {0xAA31, 0xAA32}, + {0xAA35, 0xAA36}, + {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4C}, + {0xAA7C, 0xAA7C}, + {0xAAB0, 0xAAB0}, + {0xAAB2, 0xAAB4}, + {0xAAB7, 0xAAB8}, + {0xAABE, 0xAABF}, + {0xAAC1, 0xAAC1}, + {0xAAEC, 0xAAED}, + {0xAAF6, 0xAAF6}, + {0xABE5, 0xABE5}, + {0xABE8, 0xABE8}, + {0xABED, 0xABED}, + {0xFB1E, 0xFB1E}, + {0xFE00, 0xFE0F}, + {0xFE20, 0xFE2F}, + {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, + {0x10376, 0x1037A}, + {0x10A01, 0x10A0F}, + {0x10A38, 0x10A3F}, + {0x10AE5, 0x10AE6}, + {0x10D24, 0x10D27}, + {0x10EAB, 0x10EAC}, + {0x10F46, 0x10F50}, + {0x10F82, 0x10F85}, + {0x11001, 0x11001}, + {0x11038, 0x11046}, + {0x11070, 0x11070}, + {0x11073, 0x11074}, + {0x1107F, 0x11081}, + {0x110B3, 0x110B6}, + {0x110B9, 0x110BA}, + {0x110C2, 0x110C2}, + {0x11100, 0x11102}, + {0x11127, 0x1112B}, + {0x1112D, 0x11134}, + {0x11173, 0x11173}, + {0x11180, 0x11181}, + {0x111B6, 0x111BE}, + {0x111C9, 0x111CC}, + {0x111CF, 0x111CF}, + {0x1122F, 0x11231}, + {0x11234, 0x11234}, + {0x11236, 0x11237}, + {0x1123E, 0x1123E}, + {0x112DF, 0x112DF}, + {0x112E3, 0x112EA}, + {0x11300, 0x11301}, + {0x1133B, 0x1133C}, + {0x11340, 0x11340}, + {0x11366, 0x11374}, + {0x11438, 0x1143F}, + {0x11442, 0x11444}, + {0x11446, 0x11446}, + {0x1145E, 0x1145E}, + {0x114B3, 0x114B8}, + {0x114BA, 0x114BA}, + {0x114BF, 0x114C0}, + {0x114C2, 0x114C3}, + {0x115B2, 0x115B5}, + {0x115BC, 0x115BD}, + {0x115BF, 0x115C0}, + {0x115DC, 0x115DD}, + {0x11633, 0x1163A}, + {0x1163D, 0x1163D}, + {0x1163F, 0x11640}, + {0x116AB, 0x116AB}, + {0x116AD, 0x116AD}, + {0x116B0, 0x116B5}, + {0x116B7, 0x116B7}, + {0x1171D, 0x1171F}, + {0x11722, 0x11725}, + {0x11727, 0x1172B}, + {0x1182F, 0x11837}, + {0x11839, 0x1183A}, + {0x1193B, 0x1193C}, + {0x1193E, 0x1193E}, + {0x11943, 0x11943}, + {0x119D4, 0x119DB}, + {0x119E0, 0x119E0}, + {0x11A01, 0x11A0A}, + {0x11A33, 0x11A38}, + {0x11A3B, 0x11A3E}, + {0x11A47, 0x11A47}, + {0x11A51, 0x11A56}, + {0x11A59, 0x11A5B}, + {0x11A8A, 0x11A96}, + {0x11A98, 0x11A99}, + {0x11C30, 0x11C3D}, + {0x11C3F, 0x11C3F}, + {0x11C92, 0x11CA7}, + {0x11CAA, 0x11CB0}, + {0x11CB2, 0x11CB3}, + {0x11CB5, 0x11CB6}, + {0x11D31, 0x11D45}, + {0x11D47, 0x11D47}, + {0x11D90, 0x11D91}, + {0x11D95, 0x11D95}, + {0x11D97, 0x11D97}, + {0x11EF3, 0x11EF4}, + {0x16AF0, 0x16AF4}, + {0x16B30, 0x16B36}, + {0x16F4F, 0x16F4F}, + {0x16F8F, 0x16F92}, + {0x16FE4, 0x16FE4}, + {0x1BC9D, 0x1BC9E}, + {0x1CF00, 0x1CF46}, + {0x1D167, 0x1D169}, + {0x1D17B, 0x1D182}, + {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, + {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, + {0x1DA75, 0x1DA75}, + {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DAAF}, + {0x1E000, 0x1E02A}, + {0x1E130, 0x1E136}, + {0x1E2AE, 0x1E2AE}, + {0x1E2EC, 0x1E2EF}, + {0x1E8D0, 0x1E8D6}, + {0x1E944, 0x1E94A}, + {0xE0100, 0xE01EF}, +}; diff --git a/src/include/common/unicode_east_asian_fw_table.h b/src/include/common/unicode_east_asian_fw_table.h new file mode 100644 index 0000000..e9abfa2 --- /dev/null +++ b/src/include/common/unicode_east_asian_fw_table.h @@ -0,0 +1,125 @@ +/* generated by src/common/unicode/generate-unicode_east_asian_fw_table.pl, do not edit */ + +static const struct mbinterval east_asian_fw[] = { + {0x1100, 0x115F}, + {0x231A, 0x231B}, + {0x2329, 0x232A}, + {0x23E9, 0x23EC}, + {0x23F0, 0x23F0}, + {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, + {0x2614, 0x2615}, + {0x2648, 0x2653}, + {0x267F, 0x267F}, + {0x2693, 0x2693}, + {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, + {0x26BD, 0x26BE}, + {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, + {0x26D4, 0x26D4}, + {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, + {0x26F5, 0x26F5}, + {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, + {0x2705, 0x2705}, + {0x270A, 0x270B}, + {0x2728, 0x2728}, + {0x274C, 0x274C}, + {0x274E, 0x274E}, + {0x2753, 0x2755}, + {0x2757, 0x2757}, + {0x2795, 0x2797}, + {0x27B0, 0x27B0}, + {0x27BF, 0x27BF}, + {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, + {0x2B55, 0x2B55}, + {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, + {0x2F00, 0x2FD5}, + {0x2FF0, 0x2FFB}, + {0x3000, 0x303E}, + {0x3041, 0x3096}, + {0x3099, 0x30FF}, + {0x3105, 0x312F}, + {0x3131, 0x318E}, + {0x3190, 0x31E3}, + {0x31F0, 0x321E}, + {0x3220, 0x3247}, + {0x3250, 0x4DBF}, + {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, + {0xA960, 0xA97C}, + {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, + {0xFE10, 0xFE19}, + {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, + {0xFE68, 0xFE6B}, + {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, + {0x16FE0, 0x16FE4}, + {0x16FF0, 0x16FF1}, + {0x17000, 0x187F7}, + {0x18800, 0x18CD5}, + {0x18D00, 0x18D08}, + {0x1AFF0, 0x1AFF3}, + {0x1AFF5, 0x1AFFB}, + {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, + {0x1B150, 0x1B152}, + {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, + {0x1F210, 0x1F23B}, + {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, + {0x1F260, 0x1F265}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, + {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, + {0x1F595, 0x1F596}, + {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, + {0x1F6D5, 0x1F6D7}, + {0x1F6DD, 0x1F6DF}, + {0x1F6EB, 0x1F6EC}, + {0x1F6F4, 0x1F6FC}, + {0x1F7E0, 0x1F7EB}, + {0x1F7F0, 0x1F7F0}, + {0x1F90C, 0x1F93A}, + {0x1F93C, 0x1F945}, + {0x1F947, 0x1F9FF}, + {0x1FA70, 0x1FA74}, + {0x1FA78, 0x1FA7C}, + {0x1FA80, 0x1FA86}, + {0x1FA90, 0x1FAAC}, + {0x1FAB0, 0x1FABA}, + {0x1FAC0, 0x1FAC5}, + {0x1FAD0, 0x1FAD9}, + {0x1FAE0, 0x1FAE7}, + {0x1FAF0, 0x1FAF6}, + {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, +}; diff --git a/src/include/common/unicode_norm.h b/src/include/common/unicode_norm.h new file mode 100644 index 0000000..deb125d --- /dev/null +++ b/src/include/common/unicode_norm.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * unicode_norm.h + * Routines for normalizing Unicode strings + * + * These definitions are used by both frontend and backend code. + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/common/unicode_norm.h + * + *------------------------------------------------------------------------- + */ +#ifndef UNICODE_NORM_H +#define UNICODE_NORM_H + +#include "mb/pg_wchar.h" + +typedef enum +{ + UNICODE_NFC = 0, + UNICODE_NFD = 1, + UNICODE_NFKC = 2, + UNICODE_NFKD = 3, +} UnicodeNormalizationForm; + +/* see UAX #15 */ +typedef enum +{ + UNICODE_NORM_QC_NO = 0, + UNICODE_NORM_QC_YES = 1, + UNICODE_NORM_QC_MAYBE = -1, +} UnicodeNormalizationQC; + +extern pg_wchar *unicode_normalize(UnicodeNormalizationForm form, const pg_wchar *input); + +extern UnicodeNormalizationQC unicode_is_normalized_quickcheck(UnicodeNormalizationForm form, const pg_wchar *input); + +#endif /* UNICODE_NORM_H */ diff --git a/src/include/common/unicode_norm_hashfunc.h b/src/include/common/unicode_norm_hashfunc.h new file mode 100644 index 0000000..71963ba --- /dev/null +++ b/src/include/common/unicode_norm_hashfunc.h @@ -0,0 +1,2956 @@ +/*------------------------------------------------------------------------- + * + * unicode_norm_hashfunc.h + * Perfect hash functions used for Unicode normalization + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/unicode_norm_hashfunc.h + * + *------------------------------------------------------------------------- + */ + +/* + * File auto-generated by src/common/unicode/generate-unicode_norm_table.pl, + * do not edit. There is deliberately not an #ifndef PG_UNICODE_NORM_HASHFUNC_H + * here. + */ + +#include "common/unicode_norm_table.h" + +/* Typedef for perfect hash functions */ +typedef int (*cp_hash_func) (const void *key); + +/* Information for lookups with perfect hash functions */ +typedef struct +{ + const pg_unicode_decomposition *decomps; + cp_hash_func hash; + int num_decomps; +} pg_unicode_decompinfo; + +typedef struct +{ + const uint16 *inverse_lookup; + cp_hash_func hash; + int num_recomps; +} pg_unicode_recompinfo; + +/* Perfect hash function for decomposition */ +static int +Decomp_hash_func(const void *key) +{ + static const int16 h[13407] = { + 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, + 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, + 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, + 4967, 4968, 4969, 32767, 4970, 4971, 32767, 32767, + 4972, 32767, 32767, 4973, 4974, 32767, 32767, 4975, + 4976, 4977, 4978, 32767, 4979, 4980, 4981, 4982, + 4983, 4984, 4985, 4986, 4987, 4988, 4989, 4990, + 32767, 4991, 32767, 4992, 4993, 4994, 4995, 4996, + 4997, 4998, 32767, 4999, 5000, 5001, 5002, 5003, + 5004, 5005, 5006, 5007, 5008, -6192, 5010, 5011, + 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, + 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, + 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, + 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, + 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, + 5052, 5053, 5054, 5055, 5056, 5057, 32767, 6396, + 6397, 6398, 6399, 6400, 6401, 32767, 6402, 6403, + 6404, 6405, 32767, 32767, 5059, 6407, 5060, 6409, + -9156, 6411, 5507, 6413, 32767, -290, -290, -290, + -290, -290, 9059, 9060, 32767, -291, -291, -291, + -6392, -291, -291, -291, -291, -291, -291, -291, + 951, -291, 952, -291, -291, -291, -291, -6404, + -291, -291, 4828, 4828, -6406, -6406, -291, -291, + -6408, -1694, -292, -292, -292, -292, -6408, -293, + -293, -293, -293, -293, -6409, -294, 32767, -6410, + -6410, -297, -297, -297, -297, -297, -297, -297, + 32767, -298, -6411, 2161, -298, -9253, -6861, 1544, + 2165, 2165, 2165, 7485, 7485, 7485, 7485, 25276, + 7485, 13219, 7485, 1043, 7485, 7485, 7485, 7485, + 7485, 7485, 7485, 5094, 12010, 12010, 13226, 12010, + 13228, 8732, 13230, -298, -6417, 7487, 12010, -298, + -298, -298, -6419, -6419, -1660, 8442, 8442, 8442, + 8442, 8442, -2519, 8442, 18541, -5775, 375, 8887, + 13224, -4566, 13226, 38, 39, -296, -296, 4431, + -296, -296, -6532, -296, -296, 1556, -296, 1557, + -296, -296, -296, -296, -296, -296, -296, -296, + -296, -296, -296, -296, -296, -296, -296, -296, + -296, 449, 450, -296, 106, 107, 679, -296, + 1559, -296, -1981, 112, -296, -296, -296, -296, + -296, -296, -296, 1560, 1561, 1562, 1563, 1564, + -296, -296, 1565, 1566, -296, -296, 1567, 1568, + -296, -296, -296, -296, -296, -296, 1569, 1570, + -296, -296, 1571, 1572, -296, 139, -1933, -295, + -295, 1895, -295, -295, -295, -295, -295, -295, + -295, -295, -295, -295, -486, -1943, -486, -1943, + -295, -295, -295, -295, -295, -295, -295, -295, + -295, -295, 4399, -295, -295, -295, -295, -295, + -295, -295, -295, -295, -295, -295, -295, 179, + -1339, -1339, -3797, -3797, -3797, -1339, -1339, -1339, + 1310, 1311, 1312, 1313, -6671, 1315, -13749,-1339, + -13748,1320, 6679, -1699, 1323, 1324, 1325, -1339, + -1339, -1339, -1339, -1339, 803, 804, 805, 806, + 5334, 3345, -3570, -3569, -1338, -1338, -1338, -1338, + -1338, -1338, -1338, -1338, -1338, -1338, -1338, -1338, + -1338, -1338, -1338, -1338, -1338, 8, -1338, 9, + -1338, 10, -1338, 14228, -1338, -433, -1338, 5365, + 5366, 5367, 5368, 5369, 5370, -3978, -3978, -3978, + 5374, 5375, 5376, 11478, 5378, 5379, 5380, 5381, + 5382, 5383, 5384, 4143, 5386, 4144, 5388, 5389, + 5390, 5391, 11505, 5393, 5394, 276, 277, 11512, + 11513, 5399, 5400, 11518, 5402, 5403, 5404, 5405, + 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, + 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, + 5422, 5423, 5424, 5425, 5426, 11540, 2969, 5429, + 14385, 11994, 3590, 2970, 2971, 2972, -2347, -2346, + -2345, -2344, -20134,-2342, -8075, -2340, 4103, -2338, + -2337, -2336, -2335, -2334, -2333, -2332, 60, -6855, + -6854, -8069, -6852, -8069, -3572, -8069, 5460, 11580, + -2323, -6845, 5464, 5465, 5466, 11588, 11589, 6831, + -3270, -3269, -3268, -3267, -3266, 7696, -3264, -13362, + 10955, 4806, -3705, -8041, 9750, -8041, 5148, 5148, + 5484, 5485, 759, 5487, 5488, 11725, 5490, 5491, + 3640, 5493, 3641, 5495, 5496, 5497, 5498, 5499, + 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, + 5508, 5509, 5510, 5511, 4767, 4767, 5514, 5113, + 5113, 4542, 5518, 3664, 5520, 7206, 5114, 5523, + 5524, 5525, 5526, 5527, 5528, 5529, 3674, 3674, + 3674, 3674, 3674, 5535, 5536, 3676, 3676, 5539, + 5540, 3678, 3678, 5543, 5544, 5545, 5546, 5547, + 5548, 3684, 3684, 5551, 5552, 3686, 3686, 5555, + 5121, 7194, 5557, 5558, 3369, 5560, 5561, 5562, + 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5761, + 7219, 5763, 7221, 5574, 5575, 5576, 5577, 5578, + 5579, 5580, 5581, 5582, 5583, 890, 5585, 5586, + 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, + 5595, 5596, 5597, 5598, 5599, 5600, 5601, 5602, + 5603, 5604, -2311, -2310, -2309, -2308, -2307, -2306, + -2305, -2304, -2303, 5614, 5615, 5616, 5617, 5618, + 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, + 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634, + 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, + 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, + 5651, 5652, -3666, 5654, 5655, 5656, 5657, 5658, + 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666, + 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, + 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, + 5683, 5684, 5685, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 4336, + 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, + 333, 334, 335, -433, -433, -433, -433, -433, + -433, -433, -433, -433, -433, 346, 347, 9415, + 349, 350, 351, 352, 353, 354, 355, 356, + 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, + 373, 374, 375, 376, 377, 378, 379, 6920, + 6921, -2430, -2430, -2430, -8531, -2430, -2430, -2430, + 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 401, 402, 403, + 404, 405, 406, 407, 408, 409, 410, 411, + 412, 413, -348, 5796, 5797, 2779, 5799, 2780, + 2780, 7568, 5803, 5804, 2782, 14440, 7577, 7578, + -2893, 417, 32767, 32767, 32767, 32767, 32767, 418, + 419, 420, 421, 422, 423, 424, 32767, 425, + 32767, 426, 427, 428, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 2084, 2085, + 2657, 0, 0, 0, 0, 2093, 0, 0, + 32767, 32767, 32767, 32767, 32767, 429, 4598, 4599, + 4600, 4601, 4602, 435, 4603, 4604, 4605, 4606, + 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614, + -2552, 4616, 4617, 4618, 4619, 4620, 4621, 4765, + 4766, 3854, 4625, 4626, 4627, 436, 437, 438, + 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, + 4639, 38, 17830, 4642, 4643, 4644, 0, 4645, + 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 448, 449, 450, 32767, 451, + 452, 32767, 32767, 32767, 453, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, -5211, -5211, 32767, -5212, + 32767, 32767, 32767, -5215, 32767, 32767, 32767, 32767, + -5219, -5219, -5219, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 153, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 895, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 100, 100, 32767, 99, + 32767, 32767, 32767, 96, 32767, 32767, 32767, 32767, + 92, 92, 92, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 70, 70, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 59, + 821, -5322, -5322, -2303, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, -4122, -4122, 32767, + 32767, 3651, 3652, 3653, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, -4134, -4134, 3033, -4134, + 32767, 32767, -4136, -4136, 32767, 32767, -4281, -3368, + -4138, -4138, -4138, 54, 32767, 32767, -4140, -4140, + -4140, -4140, -4140, -4140, 32767, 32767, -4142, 460, + -17331,-4142, -4142, -4142, 503, -4141, -4141, -4141, + -4141, -4141, 32767, 32767, -4143, -4143, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 511, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 512, 513, + 514, 515, 516, -4236, -4236, -4236, -4236, -4236, + 522, 523, 524, 525, 526, 527, 528, 529, + 530, 531, 532, 5533, 534, 5534, 536, 5535, + 538, 5536, 540, 5537, -9327, 543, 544, 545, + 546, 547, 548, 549, 550, 551, 552, 553, + 554, 555, 556, 32767, 557, 32767, 558, 559, + 32767, 560, 561, 32767, 562, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 32767, 0, 32767, 32767, 0, 0, 32767, + 0, 0, 32767, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 750, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 751, 32767, 32767, + 752, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 753, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -8394, 567, 568, 569, -8394, -8393, -8392, + -6000, 32767, 32767, 32767, 0, 760, 761, -14129, + 574, 575, 576, -12902,-462, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, -1748, 32767, -1749, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, -255, -255, 581, 582, 583, 584, 585, + 586, 587, 588, 589, 590, 591, 1214, 1215, + 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, + 4947, -171, -170, 1227, 1228, 1229, 1230, 11067, + 1232, 1233, 1234, 1235, 1236, 1237, 1238, -1391, + 1240, 1241, 1242, -1390, 1244, -3217, 604, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 767, 32767, 32767, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, -9177, 32767, 32767, 32767, 911, + 912, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 771, -3830, 32767, 773, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 605, 32767, + 606, 32767, 774, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 607, 32767, 32767, 608, 609, 610, -236, + 612, 613, 5235, 32767, 32767, 615, 616, 617, + 618, 619, 620, 32767, 32767, -4084, -4084, 32767, + -63, -62, 625, -61, 32767, 32767, 32767, -61, + -60, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 4955, 4956, 32767, + -3764, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, -3794, + -3794, -3794, -3794, -3794, 4880, -3794, -3794, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1423, -1750, -3794, -3794, -3794, -3794, -1754, -1754, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32767, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6081, + 6082, 6083, 6084, 6085, 6086, 6087, 6088, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 3706, 4916, 3706, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 4918, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 655, 656, 657, 658, -1487, -1487, + -1487, -1487, -1487, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, -1669, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 665, -573, + 9529, -573, 32767, -574, -574, -5333, -5333, -5333, + -5333, -5333, -5333, -5333, 32767, -5334, -5334, -5334, + 32767, 681, 682, 683, 684, 685, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2467, 2468, 2469, 2470, + 2471, 2472, 2473, 2474, 2475, 2476, 2477, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -1001, + -1001, -1001, -1001, 32767, -1002, -1002, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2512, 2513, 2514, 2515, 2516, 0, + 0, 0, 0, 0, 2522, 2523, 0, 1041, + 1042, 2527, 2528, 2529, 2530, 2531, 2532, 2533, + 2534, 2535, 2536, 2537, 693, 694, 695, -8253, + -4639, -4639, 32767, 32767, 2538, 2539, 0, 2541, + 2542, 2543, 2544, 2545, 0, 2547, 0, 2549, + 2550, 0, 2552, 2553, 0, 2555, 2556, 2557, + 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, + 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, + 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, + 2582, 2583, -1309, 706, 2585, 2586, 2587, 2588, + 2589, 2590, 2591, 2592, -7879, 2594, 2595, 2596, + 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604, + 2605, 2606, 2607, 8568, 2609, 2610, 2611, 5328, + 5329, 5330, 5331, 5332, 2617, 5335, 201, 5337, + 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, + 5346, 2630, 2631, 3718, 3719, 2634, 2635, 2636, + 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, + 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, + 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, + 2661, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2695, 2696, 2697, 2698, 2699, 2700, + 2701, 2702, 2703, 14882, 9148, 2706, 9148, 9148, + 2072, 9149, 9149, 9149, 9149, 6758, 13674, 13674, + 32767, 759, 0, 0, 14891, 189, 189, 189, + 13668, -4759, -4759, 1362, -4759, -4759, 0, 10102, + 0, 10103, 0, 0, 0, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 1458, 1459, + 32767, 32767, 32767, 32767, 32767, 0, 0, 0, + 0, 0, 9309, 9310, 9311, 9312, 9313, 9314, + 0, 0, 0, 9320, 9321, 9322, 9323, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1962, 1962, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7167, 0, 0, + 0, 0, 0, 0, -143, -143, 770, 0, + 0, 0, 4192, 4192, 4192, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4602, -13189, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5320, 5320, 5320, 5320, 23111, 5320, 11054, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32767, 32767, 0, + 0, 0, 0, 0, 0, 6247, 6247, -4714, + 6247, 2055, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32767, 32767, 778, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 779, 780, 781, 32767, 32767, + 782, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -2571, -2136, 32767, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 4811, 4812, 4813, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 2178, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 2189, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 4666, + 4667, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 1743, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 785, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 786, 32767, 32767, 787, 788, + 789, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 790, + 791, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 4668, 2585, 2585, 2014, 4672, + 4673, 4674, 4675, 2583, 4677, 4678, 32767, 32767, + 32767, 32767, 755, 756, 757, 758, 759, 760, + 761, 2992, 762, -1954, -1953, -866, -865, -1950, + -1949, -4921, -858, -857, 7336, -4923, -4923, 792, + 660, 660, 660, 32767, 32767, -4922, -4922, -4922, + -4922, 658, 658, -4874, 32767, 657, 657, -8375, + 2587, -8373, -18471,5846, -303, -8814, -13150,4641, + -13150,39, 39, 375, 376, -4350, 378, 32767, + 32767, 379, 380, -1471, 382, -1470, 384, 385, + 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, -346, -346, -346, + -346, 401, 0, 0, -571, 405, -1449, 407, + 32767, 0, 409, 410, 411, 412, 413, 0, + 414, -1441, -1441, -1441, -1441, -1441, 420, 421, + 32767, 32767, 422, 423, -1439, -1439, 426, 427, + 428, 32767, 32767, 429, -1435, -1435, 432, 433, + -1433, 32767, 32767, 0, 2073, 436, 437, -1752, + 439, 440, 441, 442, 443, 444, 445, 446, + 447, 448, 640, 2098, 642, 32767, 32767, 452, + 453, 454, 455, 456, 457, 458, 459, 460, + -4233, 462, 463, 464, 465, 466, 467, 468, + 469, 470, 471, 472, 473, 0, 1519, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -456, 32767, 32767, 32767, 32767, 32767, 32767, -3164, + 3752, 32767, 32767, 32767, -467, 32767, 32767, 32767, + 32767, 799, 32767, 32767, 32767, 32767, 1521, 1522, + 32767, -4966, -478, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, -2387, -2386, -2385, -2384, -2383, + -2382, -2381, 3002, 4163, 4164, 4165, -5186, -5186, + -5186, -11287,-5186, -5186, -5186, -5186, -5186, -5186, + -5186, -3944, -5186, -3943, -5186, -5186, -5186, -5186, + -11299,-5186, -5186, -67, 32767, -11302,-11302,-5187, + -5187, -11304,-5187, 32767, 32767, -5189, -5189, -5189, + -5189, -5189, -5189, -5189, -5189, -5189, -5189, -5189, + -5189, -5189, -5189, -5189, -5189, 32767, 4684, -5191, + -5191, -5191, -5191, -11304,-2732, -5191, -14146,32767, + 32767, 32767, 32767, 32767, 32767, 4685, 32767, 3013, + 3014, 3015, 32767, 5848, 5849, 5850, 5851, 5852, + 5853, 5854, 32767, 32767, 32767, 32767, 32767, 32767, + 802, 32767, 32767, 32767, 803, 32767, 32767, 32767, + 4686, 32767, 4687, 804, 805, 32767, 806, 807, + 32767, 808, 32767, 32767, 32767, 32767, 32767, 3016, + 32767, 4688, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 4689, + 4690, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 32767, 32767, 4691, + 4692, 4693, 32767, 32767, 32767, 32767, 32767, 2190, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -1638, -1638, 0, 0, 2190, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -191, + -1648, -191, -1648, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4694, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7916, 7916, 7916, 7916, 7916, 7916, + 7916, 7916, 7916, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9319, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 1362, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 6151, 6152, 6153, 6154, 6155, + 6156, 6157, 6158, 6159, 6160, 5382, 5382, -3685, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 5382, 5382, 5382, 5382, 5382, + 5382, 5382, 5382, 5382, 5382, 0, -1160, -1160, + -1160, 8192, 8193, 8194, 14296, 8196, 8197, 8198, + 5381, 5381, 5381, 5381, 5381, 5381, 5381, 5381, + 5381, 5381, 5381, 5381, 5381, 5381, 5381, 5381, + 5381, 5381, 5381, 5381, 5381, 5381, 5381, 5381, + 5381, 5381, 6143, 0, 0, 3019, 0, 3020, + 3021, -1766, 0, 0, 3023, -8634, -1770, -1770, + 8702, 32767, 32767, 3025, 3026, 32767, 3027, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, -1783, -7743, + -1783, -1783, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 5046, 5047, 5048, 5049, 5050, + 5051, 5052, 32767, 32767, 32767, 169, 169, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 6144, 6145, 5767, 6147, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, -2883, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 563, 564, 565, + 8960, 0, 0, 0, 8964, 8964, 8964, 6573, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, 0, 13479, 1040, 0, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -5930, 32767, 32767, 32767, 32767, 829, 830, + -14060,32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 832, 833, + 834, 835, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -622, -622, -622, + -622, -622, -622, -622, -622, 3032, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 32767, 32767, 32767, 32767, -638, 32767, 32767, + 32767, 32767, 1991, -642, 3820, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 838, 32767, 32767, 32767, 32767, + 32767, 2458, 2458, 32767, 0, 4695, 32767, 839, + 840, 4696, 4697, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 841, 32767, 842, 32767, + 843, 32767, 32767, 32767, 32767, 0, 32767, 0, + 32767, 32767, 844, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 845, 32767, 32767, 32767, + 0, 846, 32767, 0, 0, 0, 847, 0, + 0, -4621, 32767, -2323, 0, 0, 0, 0, + 0, 0, 32767, 32767, 4705, 4706, 32767, 686, + 686, 0, 687, 3034, 32767, 32767, 32767, 32767, + -1963, -2342, -2342, 6037, 12728, 12729, -2990, 12731, + 12732, 12733, 12734, 12735, -531, 32767, 32767, -533, + -533, 2711, 2711, 2711, 32767, 2710, 5710, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 6589, + 6590, 6591, 2699, 4714, 6593, 6594, 32767, 32767, + 32767, 6595, 6596, 6597, -3874, 6599, 32767, 32767, + 32767, 2803, 32767, 32767, 32767, 32767, 8384, 32767, + 32767, 32767, 32767, 8337, 32767, 32767, 32767, 32767, + -682, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -2389, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, -2401, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 32767, 0, 32767, 32767, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767, 0, 0, 0, 0, + 32767, 0, 32767, 0, 32767, 32767, 32767, 32767, + 32767, 32767, -957, 32767, 32767, 32767, 32767, 0, + 32767, 0, 880, 0, 32767, 0, 0, 0, + 32767, 0, 0, 32767, 0, 32767, 32767, 0, + 32767, 0, 32767, 0, 32767, 0, 32767, 0, + 32767, 0, 0, 32767, 0, 32767, 32767, 0, + 0, 6115, 0, 6116, 6116, 0, 0, 6116, + 6116, 6116, 6116, 0, 6115, 0, 0, 0, + 6113, 6113, 6113, 6113, 6113, 6113, 6113, 0, + 6113, 0, 8572, 6113, -2842, -450, 0, 0, + 8578, 8578, 13898, 13898, 13898, 0, 0, 13900, + 19634, 13900, 7458, 13900, 13900, 6824, 13901, 13901, + 13901, 13901, 11510, 18426, 18426, 19642, 18426, 0, + 15149, 19647, 6119, 0, 13904, 18427, 0, 0, + 6121, 0, 0, 4759, 14861, 4759, 14862, 4759, + 4759, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4775, 4775, 4775, 4775, 0, 4776, 4776, + 4776, 0, 7826, 7827, 7828, 7829, 7830, 7831, + 4777, 4777, 4777, 4777, 4777, 0, 4778, 4778, + 0, 0, 4780, 4780, 4780, 4780, 4780, 0, + 0, 4782, 4782, 4782, 0, 4783, 0, 4784, + 0, 4785, 0, 4786, 4786, 4786, 4786, 0, + 4787, 4787, 4787, 0, 4788, 4788, 4788, 4788, + 4788, 4788, 4788, 0, 4789, 4789, 4789, 4789, + 4789, 4789, 0, 0, 0, 0, 4793, 4793, + 4793, 4793, 4793, 0, 882, 0, 0, 0, + 0, 4799, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 7927, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 4799, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 4799, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 4799, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 4799, 4799, 4799, 4799, 4799, 4799, 4799, + 4799, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -2458, -2458, -2458, 0, 0, + 0, 2649, 2650, 2651, 2652, -5332, 2654, -12410, + 0, -12409,2659, 8018, -360, 2662, 2663, 2664, + 0, 0, 0, 0, 0, 2142, 2143, 2144, + 2145, 0, 0, 0, 0, 0, 0, 0, + 0, 4307, 4308, 0, 4309, 4310, 0, -173, + 0, 0, -1457, 0, -1457, 0, -1457, 0, + -1458, -8534, -8533, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -3244, + -3244, 0, 0, 0, 0, 0, 3000, 0, + 5135, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2717, 2717, 1631, 1631, 2717, + 2717, 5690, 1628, 1628, -6564, 5696, 5697, 0, + 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, + 5708, 129, 130, 5663, 0, 5664, 5664, 6433, + 0, 0, 0, -5044, 1106, 1107, 1108, 1109, + 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, + 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, + 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, + 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, + 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, + 1150, 1151, -5940, -5319, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 32767, 0, 32767, + 0, 32767, 32767, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3316, 32767, 3317, 32767, + 3318, 32767, 32767, 3319, 3320, 32767, 32767, 32767, + 0, 0, 0, 9778, 3325, 3326, 3327, 3328, + 3329, 3330, 3331, 3332, 3333, 3334, 454, 3336, + 3337, 3338, 3339, 3340, 3341, 3342, 3343, 3344, + 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, + 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, + 3361, 0, 0, 3364, 3365, 3366, 3367, 3368, + 3369, 3370, 3371, 3372, 3373, 3374, 3375, 0, + 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, + 3385, 3386, 0, 3388, 32767, 32767, 3389, 3390, + 3391, 3392, 3393, 0, 3395, 3396, 3397, 0, + 0, 0, 0, 0, 3403, 3404, 3405, 0, + 3407, 0, 3409, 3410, 3411, 3412, 3413, 3414, + 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, + 3423, 3424, 3425, 3426, 3427, 3428, 3429, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -3723, 1396, 1396, 0, 0, 0, 0, + -9836, 0, 0, 0, 0, 0, 0, 0, + 2630, 0, 0, 0, 2633, 0, 4462, 3462, + 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, + 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, + 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, + 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 0, 0, + 0, 0, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 3400, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 471, 471, 885, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 7954, 32767, + 32767, 32767, 32767, 0, 32767, 32767, -620, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, -11684,32767, + 7964, 32767, 32767, 32767, 32767, 32767, 7967, 0, + 32767, -6890, -6889, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, -2878, -2877, -2876, -2875, 8087, -2873, + -12971,0, 32767, 0, 32767, 32767, 32767, 877, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 7021, + 13712, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 878, 32767, 879, 0, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, 0, 0, 0, 32767, 32767, 0, 0, + 32767, 32767, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 0, 32767, 32767, 0, 0, + 32767, 32767, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, -18761,5867, + 5868, 5869, 5870, 5871, 5872, 5873, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 0, 0, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 0, 0, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4392, + 4393, 4394, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8674, 0, 0, 3794, 3794, 3794, + 3794, 3794, 3794, 3794, 3794, 3794, 2371, 2044, + 0, 0, 0, 0, 2040, 2040, 3794, 3794, + 0, 0, -4405, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2454, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7266, 7266, 7266, 7266, 7266, 7266, 7266, 7266, + 7266, 7266, 7266, 7266, 7266, 7266, 7266, 7266, + 7266, 7266, 7266, 32767, 32767, 32767, 7263, 7263, + 7263, 7263, 7263, 7263, 32767, 32767, 7261, 7261, + 7261, 7261, 7261, 7261, 32767, 32767, 2460, 2460, + 2460, 2460, 2460, 2460, 32767, 32767, 0, 0, + 0, 32767, 5102, 5103, 5104, 5105, 5106, 5107, + -2877, 5109, -9955, -6587, -9955, 5113, 10472, 2094, + 5116, 5117, 5118, 5119, 5120, 5121, 5122, 4744, + 5124, 5125, -3253, -9943, -9943, 5777, -9943, -9943, + -9943, -9943, -9943, 3324, 3325, 3326, 3327, 3328, + 85, 86, 87, 88, 89, -2910, 91, -5043, + 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, -2614, -2613, -1526, -1525, -2610, -2609, + -5581, -1518, -1517, 6676, -5583, -5583, 132, 0, + 0, 0, -5580, -5580, -5580, -5580, -5580, -5580, + 0, 0, -5532, 5183, 0, 0, 6677, 32767, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4922, + 4923, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32767, + 0, 0, 32767, 32767, 0, 32767, 32767, 0, + 0, 32767, 32767, 0, 0, 0, 0, 32767, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 32767, 0, + 0, 0, 0, 0, 0, 0, 32767, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11201, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 886, 887, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 888, 32767, 32767, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -4020, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 778, + 0, 0, -9067, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -6540, -6540, 2812, 32767, 2813, 8915, + 2815, 2816, 2817, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 762, 32767, 32767, + 32767, 32767, -2365, 32767, 32767, 32767, 32767, 32767, + -14024,32767, 32767, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 0, 0, 0, 0, 0, 0, + 0, 32767, 0, 32767, 0, 0, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 889, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 890, 32767, 32767, 32767, + 0, -4168, -4168, -4168, -4168, -4168, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 0, 0, -4192, -4192, 32767, -4193, -4193, + -4193, -4193, -4193, -4193, 409, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 32767, 0, 0, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -1663, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 891, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 892, 893, 894, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 32767, 0, + 0, 4788, 32767, 32767, 0, 11658, 32767, 8415, + 8416, 32767, 32767, 0, 0, 32767, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 5874, 5875, 5876, 5877, 32767, 5878, 5879, 5880, + 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, + 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, + 5897, 5898, 5899, 5900, 5901, 5902, 5903, 5904, + 32767, 5905, 5906, 32767, 5907, 32767, 32767, 5908, + 32767, 5909, 5910, 5911, 5912, 5913, 5914, 5915, + 5916, 5917, 5918, 32767, 5919, 5920, 5921, 5922, + 32767, 5923, 32767, 5924, 32767, 32767, 32767, 32767, + 32767, 32767, 6882, 32767, 32767, 32767, 32767, 5926, + 32767, 5927, 32767, 5928, 32767, 5929, 5930, 5931, + 32767, 5932, 5933, 32767, 5934, 32767, 32767, 5935, + 32767, 5936, 32767, 5937, 32767, 5938, 32767, 5939, + 32767, 5940, 5941, 32767, 5942, 32767, 32767, 5943, + 5944, -170, 5946, 32767, -169, 5948, 5949, -166, + -165, -164, -163, 32767, -161, 5955, 5956, 5957, + 32767, -155, -154, -153, -152, 32767, -151, 32767, + -150, 5964, -2607, -147, 8809, 6418, 5969, 5970, + -2607, -2606, 32767, -7925, -7924, 5975, 5976, -7923, + -13656,-7921, -1478, -7919, -7918, -841, -7917, -7916, + -7915, -7914, -5522, -12437,32767, 32767, 32767, 32767, + 32767, -13657,-128, 5992, 32767, -12434,5994, 5995, + -125, 5997, 0, 1239, -8862, 1241, -8861, 1243, + 1244, 6004, 6005, 6006, 6007, 6008, 6009, 6010, + 6011, 6012, 6013, 6014, 32767, 0, 0, 0, + 0, 0, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 897, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 0, 0, 0, 0, 0, + 0, 0, 32767, 32767, 0, -1786, -1786, -1786, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 898, + 899, 900, 901, 902, 903, 904, 905, 32767, + 32767, 906, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 907, -8041, -8041, + 7679, -3281, 912, 913, 914, 915, 916, 0, + 0, 0, 0, 32767, -1845, -1845, -1845, -1845, + 0, 0, 0, 8949, 8950, -6769, 4192, 0, + 0, 0, 0, 0, 917, 918, 919, 920, + 32767, 2766, 2767, 2768, 2769, 925, 926, 927, + -8021, -8021, 7699, -3261, 932, 933, 934, 935, + 936, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, -1879, -1879, + -1879, -1879, -1879, -1879, -1879, -1879, 2014, 0, + -1878, -1878, -1878, -1878, -1878, -1878, -1878, -1878, + 8594, -1878, -1878, -1878, -1878, -1878, 32767, -1879, + -1879, -1879, -1879, -1879, -1879, -1879, -1879, -7839, + -1879, -1879, -1879, -4595, -4595, -4595, -4595, -4595, + -1879, -4596, 539, -4596, -4596, -4596, -4596, -4596, + -4596, -4596, -4596, -4596, 32767, 397, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 943, + 32767, 32767, 32767, 32767, 32767, 32767, 944, 32767, + 945, 32767, 32767, 946, 947, 32767, 948, 949, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 950, 951, + 952, 953, 954, 955, 956, 957, 958, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 4591, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 959, 960, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 961, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 51, 51, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 964, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 4767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 6015, 6016, 6017, 6018, 6019, + 6020, 6021, 6022, 6023, 7447, 7775, 32767, 32767, + 32767, 32767, 32767, 7780, 6027, 6028, 6029, 6030, + 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, + 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, + 6047, 6048, 6049, 6050, 6051, 6052, 6053, 6054, + 6055, 6056, 32767, 6057, 6058, 6059, 6060, 6061, + 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, + 6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077, + 6078, 6079, 6080, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 965, 1410, 1411, 1412, + 1413, 1414, 1415, 1416, 1417, 1418, 12380, 1420, + -8678, 15639, 9490, 979, -3357, 14434, -3357, 2377, + -3357, 2379, 1174, 2381, 1174, 2383, 1174, 2385, + 1174, 2387, 1174, 1174, 2390, 1174, 2392, -2104, + 2394, 1174, -2102, 1174, 1174, 1174, 1174, -2400, + -2400, -2400, -2400, 2405, 1174, 2407, 2408, 1174, + 2410, 2411, 1174, 2413, 2414, -1896, 1174, 1174, + 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, + 1174, 1174, 1174, 1174, 1174, 1174, 1174, 1174, + 1174, 1174, -3323, 2437, 1174, 1174, 1174, 1174, + 2442, 2443, 2444, 2445, 1174, 2447, 2448, 1174, + 1174, 992, -3314, -3314, -2076, -3314, -3314, 997, + 1171, 999, 1000, 2458, 1002, 2460, 1004, 2462, + 9540, 2464, 9541, 9541, 1009, 1010, 1011, 1012, + 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, + 1021, 1022, 1023, 0, 1024, 1025, 1026, 1027, + 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, + 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, + 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, + 0, 0, 0, 0, -8971, -1739, -1738, -1737, + -8971, -8971, -8971, -8971, -8971, 1052, -8971, -8971, + 32767, -8972, -8972, -8972, -8972, -5604, -8972, -8972, + -8972, -8972, -8972, -8972, -8972, -1697, -8972, -8972, + 32767, -8973, -8973, -8973, -2283, -8973, -8973, 6747, + -8973, -8973, -8973, -8973, -8973, 4294, 4295, 4296, + 4297, 4298, 1055, 1056, 1057, 1058, 1059, -1940, + 1061, -4073, 1063, 1064, 1065, 1066, 1067, 1068, + 1069, 1070, 1071, 1072, -1644, -1643, -556, -555, + -1640, -1639, -4611, -548, -547, 7646, -4613, -4613, + 1085, -4614, -4614, -4614, -4614, -4614, -4614, -4614, + -4614, -4614, 966, 966, -4566, 1098, -4565, -4564, + -5332, 1102, 1103, 1104, 6149, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7092, 6472, 6473, 6474, 1155, + 1156, 1157, 1158, -16632,1160, -4573, 1162, 7605, + 1164, 1165, 1166, 1167, 1168, 1169, 1170, 3562, + -3353, -3352, -4567, -3350, -4567, -70, -4567, -3346, + 1180, 1181, -3341, -3340, -3339, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 11206, 246, + -9852, 14465, 8316, -195, -4531, 13260, -4531, 1203, + -4531, 1205, 0, 1207, 0, 1209, 0, 1211, + 0, 1213, 0, 0, 1216, 0, 1218, -3278, + 1220, 0, -3276, 0, 0, 0, 0, -3574, + -3574, -3574, -3574, 1231, 0, 1233, 1234, 0, + 1236, 1237, 0, 1239, 1240, -3070, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -4497, 1263, 0, 0, 0, 0, + 1268, 1269, 1270, 1271, 0, 1273, 1274, 0, + 0, -182, -4488, 0, 1280, 1281, -4485, -174, + 0, -172, -171, 1287, -169, 1289, -167, 1291, + 8369, 1293, 8370, 8370, 1296, 1297, 1298, 1299, + 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, + 1308, 1309, 0, 0, 0, 0, 1310, 1311, + 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, + 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, + 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, + 1336, 0, 1338, 1339, 1340, 1341, 1342, 1343, + 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, + 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, + 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, + 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, + 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, + 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, + 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 1400, + 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, + 444, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -10961,0, 10099, 32767, 32767, 443, + 4780, -13010,4782, -951, 4784, 11227, 32767, -953, + 255, -953, 257, -953, 259, -953, 261, 262, + -953, 264, -953, 3544, -953, 268, 3545, 270, + 271, 272, 273, 3848, 3849, 3850, 3851, -953, + 279, -953, -953, 282, -953, -953, 285, -953, + -953, 3358, 289, 290, 291, 32767, 32767, 292, + 293, 294, 295, 296, 297, 32767, 32767, 298, + 299, 300, 301, 302, 303, 304, 4802, 3582, + 306, 32767, 307, 32767, -960, 32767, -961, -961, + 311, -961, -961, 314, 315, 498, 4805, 4806, + 3569, 4808, 4809, 499, 326, 499, 499, -958, + 499, -958, 499, -958, -8035, -958, -8034, -8033, + 500, 500, 500, 500, 500, 32767, 32767, 498, + 498, 498, 498, 498, 498, 498, 498, 1522, + 499, 499, 499, 499, 499, 499, 499, 499, + 499, 499, 499, 499, 499, 499, 499, 499, + 499, 499, 499, 499, 499, 499, 499, 499, + 499, 499, 499, 499, 1551, 1552, 1553, 1554, + 10526, 3295, 3295, 3295, 10530, 10531, 10532, 10533, + 10534, 512, 10536, 10537, 10538, 10539, 10540, 10541, + 10542, 7175, 10544, 10545, 10546, 10547, 10548, 10549, + 10550, 3276, 10552, 10553, 10554, 10555, 10556, 10557, + 3868, 10559, 10560, -5159, 10562, 10563, 10564, 10565, + 10566, -2700, -2700, 3260, 10570, -2702, 542, 542, + 542, 542, 542, 3258, 541, 5676, 541, 541, + 541, 541, 541, 541, 541, 541, 541, 541, + 3258, 3258, 2172, 2172, 3258, 3258, 6231, 6232, + 6233, -6025, 6235, 6236, 6237, 6238, 6239, 6240, + 6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, + 1633, 1634, 1635, 1636, 1637, 1638, 1639, -872, + -872, -872, -872, 6260, 6261, 6262, 6263, 6264, + 6265, -878, 6267, 6268, 6269, 6270, 6271, -883, + 6273, 6274, 6275, 6276, 6277, 6278, 6279, 6280, + 6281, 6282, 6283, 6284, 9899, 6286, 6287, 6288, + 6289, 6290, 6291, 6292, 6293, 6294, 6295, -895, + 6297, 6298, 6299, 1650, -898, 6302, 1652, -899, + 6305, 6306, 6307, 6308, -903, 6310, -904, 6312, + 6313, 6314, 6315, 6316, 6317, 6318, 6319, -912, + -912, -912, 6323, 6324, 6325, 6326, 6327, -3695, + 6329, 6330, 6331, 6332, 6333, 6334, 6335, 2968, + 6337, 6338, 6339, 6340, 6341, 6342, 6343, -931, + 6345, 6346, 6347, 6348, 6349, 6350, -339, 6352, + 6353, -9366, 6355, 6356, 6357, 6358, 6359, -6907, + -6907, -947, 6363, -6909, -3665, -3665, -3665, -3665, + -3665, -949, -3666, 1469, -3666, -3666, -3666, -3666, + -3666, -3666, -3666, -3666, -3666, -3666, -949, -949, + -2035, -2035, -949, -949, -949, -949, -949, 6392, + -950, -950, -950, -950, -950, -950, -950, -950, + -950, -950, -950, -950, -950, 6406, 6407, 6408, + 6409, -4824, -4823, 6412, 6413, 6414, 6415, 6416, + 1703, 302, 6418, 303, 304, 6421, 6422, 307, + 308, 309, 310, 6427, 313, 6429, 6430, 6431, + 319, 320, 321, 322, 323, 324, 325, 6439, + 327, 6441, -2130, 330, 9286, 6895, 6446, 6447, + -2130, -2129, -7448, -7447, -7446, 6453, 6454, -7445, + -13178,-7443, -1000, -7441, -7440, -363, -7439, -7438, + -7437, -7436, -5044, -11959,-11958,-13173,-11956,6471, + -8677, -13174,355, 6475, -7428, -11950,6478, 6479, + 359, 6481, 6482, 1724, -8377, 1726, -8376, 1728, + 1729, 6489, 6490, 6491, 6492, 6493, 6494, 6495, + 6496, 6497, 6498, 6499, 6500, 6501, 6502, 6503, + 6504, 1730, 1731, 1732, 1733, 6509, 1734, 1735, + 1736, 6513, -1312, -1312, -1312, -1312, -1312, -1312, + 1743, 1744, 1745, 1746, 1747, 6525, 1748, 1749, + 6528, 6529, 1750, 1751, 1752, 1753, 1754, 6535, + 6536, 1755, 1756, 1757, 6540, 1758, 6542, 1759, + 6544, 1760, 6546, 1761, 1762, 1763, 1764, 6551, + 1765, 1766, 1767, 6555, 1768, 1769, 1770, 1771, + 1772, 1773, 1774, 6563, 1775, 1776, 1777, 1778, + 1779, 1780, 6570, 6571, 6572, 6573, 1781, 1782, + 1783, 1784, 1785, 6579, 5698, 6581, 6582, 6583, + 6584, 1786, 1787, 1788, 1789, 1790, 1791, 1792, + 1793, -1334, 1795, 1796, 1797, 1798, 1799, 1800, + 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, + 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, + 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, + 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, + 1833, 6633, 6634, 6635, 6636, 6637, 6638, 6639, + 6640, 6641, 6642, 9101, 9102, 9103, 6646, 6647, + 6648, 4000, 4000, 4000, 4000, 11985, 4000, 19065, + 6656, 19066, 3999, -1359, 7020, 3999, 3999, 3999, + 6664, 6665, 6666, 6667, 6668, 4527, 4527, 4527, + 4527, 0, 1990, 8906, 8906, 6676, 6677, 6678, + 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, + 6687, 6688, 6689, 6690, 6691, 6692, 5347, 6694, + 5348, 6696, 5349, 6698, -8867, 6700, 5796, 6702, + 0, 0, 0, 0, 0, 0, 9349, 9350, + 9351, 0, 0, 0, -6101, 0, 0, 0, + 0, 0, 0, 0, 1242, 0, 1243, 0, + 0, 0, 0, -6113, 0, 0, 5119, 5119, + -6115, -6115, 0, 0, -6117, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -6113, 2459, + 0, -8955, -6563, 1842, 2463, 2463, 2463, 7783, + 7783, 7783, 7783, 25574, 7783, 13517, 7783, 1341, + 7783, 7783, 7783, 7783, 7783, 7783, 7783, 5392, + 12308, 12308, 13524, 12308, 13526, 9030, 13528, 0, + -6119, 7785, 12308, 0, 0, 0, -6121, 1847, + 32767, 8738, 8738, 8738, 8738, 8738, -2223, 8738, + 18837, -5479, 671, 9183, 13520, -4270, 13522, 334, + 335, 0, 0, 4727, 0, 0, -6236, 0, + 0, 1852, 0, 1853, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 745, 746, 0, + 402, 403, 975, 0, 1855, 0, -1685, 408, + 0, 0, 0, 0, 0, 0, 0, 1856, + 1857, 1858, 1859, 1860, 0, 0, 1861, 1862, + 0, 0, 1863, 1864, 0, 0, 0, 0, + 0, 0, 1865, 1866, 0, 0, 1867, 1868, + 0, 32767, 1869, 1870, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 1871, 1872, + 1873, 1874, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 1875, 1876, 1877, 1878, 32767, 32767, + 32767, 32767, 32767, 32767, 1879, 1880, 1881, 1882, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 1883, 1884, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 0, 0, 4753, 4754, 4755, 4756, 4757, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -5000, 0, -4999, 0, -4998, + 0, -4997, 0, -4996, 9869, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767, 0, 32767, 0, 0, + 32767, 0, 0, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 251, 251, 251, 251, + 251, 251, 2763, 2764, 2765, 2766, -4365, -4365, + -4365, -4365, -4365, -4365, 2779, -4365, -4365, -4365, + -4365, -4365, 2790, -4365, -4365, -4365, -4365, -4365, + -4365, -4365, -4365, -4365, -4365, -4365, -4365, -7979, + -4365, -4365, -4365, -4365, -4365, -4365, -4365, -4365, + -4365, -4365, 2826, -4365, -4365, -4365, 285, 2834, + -4365, 286, 2838, -4365, -4365, -4365, -4365, 2847, + -4365, 2850, -4365, -4365, -4365, -4365, -4365, -4365, + -4365, -4365, 2867, 2868, 2869, -4365, -4365, -4365, + -4365, -4365, 5658, -4365, -4365, -4365, -4365, -4365, + -4365, -4365, -997, -4365, -4365, -4365, -4365, -4365, + -4365, -4365, 2910, -4365, -4365, -4365, -4365, -4365, + -4365, 2325, -4365, -4365, 11355, -4365, -4365, -4365, + -4365, -4365, 8902, 8903, 2944, -4365, 8908, 5665, + 5666, 5667, 5668, 5669, 2954, 5672, 538, 5674, + 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, + 5683, 2967, 2968, 4055, 4056, 2971, 2972, 0, + 0, 0, 12259, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4616, 4616, 4616, 4616, 4616, 4616, 4616, + 7128, 7129, 7130, 7131, 0, 0, 0, 0, + 0, 0, 7144, 0, 0, 0, 0, 0, + 7155, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -3614, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7191, 0, 0, 0, 4650, 7199, 0, 4651, + 7203, 0, 0, 0, 0, 7212, 0, 7215, + 0, 0, 0, 0, 0, 0, 0, 0, + 7232, 7233, 7234, 0, 0, 0, 0, 0, + 10023, 0, 0, 0, 0, 0, 0, 0, + 3368, 0, 0, 0, 0, 0, 0, 0, + 7275, 0, 0, 0, 0, 0, 0, 6690, + 0, 0, 15720, 0, 0, 0, 0, 0, + 13267, 13268, 7309, 0, 13273, 10030, 10031, 10032, + 10033, 10034, 7319, 10037, 4903, 10039, 10040, 10041, + 10042, 10043, 10044, 10045, 10046, 10047, 10048, 7332, + 7333, 8420, 8421, 7336, 7337, 7338, 7339, 7340, + 0, 7343, 7344, 7345, 7346, 7347, 7348, 7349, + 7350, 7351, 7352, 7353, 7354, 7355, 0, 0, + 0, 0, 11234, 11234, 0, 0, 0, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 775, 32767, + 32767, 776, 32767, 32767, 32767, 32767, 32767, 777, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 32767, 32767, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 0, 0, 32767, + 32767, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 32767, 32767, 32767, 0, -444, -444, 32767, + -445, -445, -445, -445, -445, -445, -11406,-445, + 9654, -14662,-8512, 0, 4337, 32767, 4338, -1395, + 4340, -1395, -189, -1395, -187, 32767, 32767, 32767, + 32767, -1399, 32767, 32767, 32767, 32767, 32767, 32767, + -1405, 32767, 32767, 32767, -184, -183, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 3035, 3036, + 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, + 3045, 3046, 3047, 0, 0, 0, 0, 0, + 0, 0, 3055, 3056, 3057, 3058, 3059, 3060, + 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, + 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, + 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084, + 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, + 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100, + 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, + 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, + 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, + 3125, 3126, 3127, 0, 3129, 3130, 3131, 3132, + 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, + 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, + 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, + 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, + 3165, 3166, 3167, 3168, 3169, 3170, 0, 0, + 0, 0, 0, 0, 7985, 0, 15065, 11698, + 15067, 0, -5358, 3021, 0, 0, 0, 0, + 0, 0, 0, 379, 0, 0, 8379, 15070, + 15071, -648, 15073, 15074, 15075, 15076, 15077, 1811, + 1811, 1811, 1811, 1811, 5055, 5055, 5055, 5055, + 5055, 8055, 5055, 10190, 5055, 5055, 5055, 5055, + 5055, 5055, 5055, 5055, 5055, 5055, 7772, 7772, + 6686, 6686, 7772, 7772, 10745, 6683, 6683, -1509, + 10751, 10752, 5038, 5171, 5172, 5173, 10754, 10755, + 10756, 10757, 10758, 10759, 5180, 5181, 10714, 0, + 5184, 5185, -1491, 3256, 14217, 24316, 0, 6150, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 2713, 2714, 2715, 2716, 2717, + 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, + 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, + 2734, 2735, 2736, 2737, 2738, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3048, 3049, 3050, 3051, 3052, 3053, + 3054, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3171, 3172, 3173, + 3174, 3175, 3176, -4808, 3178, -11886,-8518, -11886, + 3182, 8541, 163, 3185, 3186, 3187, 3188, 3189, + 3190, 3191, 2813, 3193, 3194, -5184, -11874,-11874, + 3846, -11874,-11874,-11874,-11874,-11874,1393, 1394, + 1395, 1396, 1397, -1846, -1845, -1844, -1843, -1842, + -4841, -1840, -6974, -1838, -1837, -1836, -1835, -1834, + -1833, -1832, -1831, -1830, -1829, -4545, -4544, -3457, + -3456, -4541, -4540, -7512, -3449, -3448, 4745, -7514, + -7514, -1799, -1931, -1931, -1931, -7511, -7511, -7511, + -7511, -7511, -7511, -1931, -1931, -7463, 3252, -1931, + -1931, 4746, 0, -10960,-21058,3259, -2890, 3261, + 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, + 3270, 3271, 3272, 3273, 3274, 3275, 3276, 3277, + 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, + 3286, 3287, 3288, 3289, 3290, 32767, 3291, 3292, + 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, + 3301, 3302, 3303, 3304, 32767, 32767, 3305, 32767, + 3306, 32767, 32767, 3307, 3308, 3309, 3310, 3311, + 3312, 3313, 3314, 3315, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32767, 32767, + 3321, 3322, 3323, -6454, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2881, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3362, 3363, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3376, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3387, 0, 0, 0, 0, 0, + 0, 0, 0, 3394, 0, 0, 0, 3398, + 3399, 3400, 3401, 3402, 0, 0, 0, 3406, + 0, 3408, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3430, + 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, + 3439, 7163, 2045, 2046, 3443, 3444, 3445, 3446, + 13283, 3448, 3449, 3450, 3451, 3452, 3453, 3454, + 825, 3456, 3457, 3458, 826, 3460, -1001, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3499, 0, 0, 0, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 3502, 3503, 3504, 3505, 3506, 32767, + 32767, 32767, 32767, 32767, 3507, 3508, 985, 2026, + 2027, 3512, 3513, 3514, 3515, 3516, 3517, 3518, + 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, + 3527, 3528, 3529, 3530, 3531, 3532, 32767, 3533, + 3534, 3535, 3536, 3537, 32767, 3538, 32767, 3539, + 3540, 32767, 3541, 3542, 32767, 3543, 3544, 3545, + 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, + 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, + 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, + 3570, 3571, -321, 3573, 3574, 3575, 3576, 3577, + 3578, 3579, 3580, 3581, -6890, 3583, 3584, 3585, + 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, + 3594, 3595, 3596, 9557, 3598, 3599, 3600, 6317, + 6318, 6319, 6320, 6321, 3606, 6324, 1190, 6326, + 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, + 6335, 3619, 3620, 4707, 4708, 3623, 3624, 3625, + 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, + 3634, 3635, 3636, 3637, 3638, 3639, 3640, 3641, + 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, + 3650, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 3651, 3652, 3653, 3654, 3655, 3656, + 3657, 3658, 3659, 15838, 10104, 3662, 10104, 10104, + 3028, 10105, 10105, 10105, 3669, 3670, 3671, 3672, + 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, + 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, + 3689, 3690, 3691, 3692, 3693, 3694, 3695, 32767, + 3696, 3697, 3698, 3699, 3700, 3701, 3702, 3703, + 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, + 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, + 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3727, + 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, + 3736, 3737, 3738, 3739, 3740, 3741, -3350, -2729, + -2729, -2729, 2591, 2591, 2591, 2591, 20382, 2591, + 8325, 2591, -3851, 2591, 2591, 2591, 2591, 2591, + 2591, 2591, 200, 7116, 7116, 8332, 7116, 8334, + 3838, 8336, 7116, 2591, 2591, 7114, 7114, 7114, + 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, + 3540, -7421, 3540, 13639, -10677,-4527, 3985, 8322, + -9468, 8324, 2591, 8326, 2591, 3797, 2591, 3799, + 2591, 3801, 2591, 3803, 2591, 3805, 3806, 2591, + 3808, 2591, 7088, 2591, 3812, 7089, 3814, 3815, + 3816, 3817, 7392, 7393, 7394, 7395, 2591, 3823, + 2591, 2591, 3826, 2591, 2591, 3829, 2591, 2591, + 6902, 3833, 3834, 3835, 3836, 3837, 3838, 3839, + 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, + 3848, 3849, 3850, 3851, 3852, 8350, 2591, 3855, + 3856, 3857, 3858, 2591, 2591, 2591, 2591, 3863, + 2591, 2591, 3866, 3867, 4050, 8357, 3870, 2591, + 2591, 8358, 4048, 3875, 4048, 4048, 2591, 4048, + 2591, 4048, 2591, -4486, 2591, -4485, -4484, 2591, + 2591, 2591, 2591, 2591, 2591, 2591, 2591, 2591, + 2591, 2591, 2591, 2591, 2591, 3901, 3902, 3903, + 3904, 2595, 2595, 2595, 2595, 2595, 2595, 2595, + 2595, 2595, 2595, 2595, 2595, 2595, 2595, 2595, + 2595, 2595, 2595, 2595, 2595, 2595, 2595, 2595, + 2595, 2595, 2595, 2595, 3932, 2595, 2595, 2595, + 2595, 2595, 2595, 2595, 2595, 2595, 2595, 2595, + 2595, 2595, 2595, 2595, 2595, 2595, 2595, 2595, + 32767, 3952, 3953, 3954, 3955, 3956, -5352, -5352, + -5352, -5352, -5352, -5352, 3963, 3964, 3965, -5354, + -5354, -5354, -5354, 3970, 3971, 3972, 3973, 3974, + 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, + 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, + 2029, 2030, 3993, 3994, 3995, 3996, 3997, 3998, + 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, + 4007, 4008, 4009, 4010, 4011, 4012, 4013, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 4014, 4015, 4016, 4017, 4018, 4019, 4020, + 4021, 4022, -579, 17213, 4025, 4026, 4027, 4028, + 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, + 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, + 4045, 4046, 4047, 4048, -1271, -1270, -1269, -1268, + -19058,-1266, -6999, 4056, 4057, 4058, 4059, 4060, + 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, + 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, + 4077, 32767, 32767, 4078, 4079, 4080, 4081, 4082, + 4083, -2163, -2162, 8800, -2160, 2033, 4089, 4090, + 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, + 4099, 4100, 4101, 4102, 4103, 4104, 4105, 4106, + 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, + 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, + 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, + 4131, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 0, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 4132, 4133, 4134, 4135, 4136, 4137, 4138, + 4139, 4140, 4141, 4142, 4143, 4144, 32767, 32767, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 4145, 4146, 4147, 4148, 4149, 4150, + 4151, 4152, 4153, 4154, 2034, 32767, 32767, 32767, + 32767, 32767, 4155, 4156, 4157, 4158, 4159, 4160, + 4161, 4162, 4163, 4164, 1284, 4166, 4167, 4168, + 4169, 4170, 4171, 4172, 4173, 4174, 4175, 4176, + 4177, 4178, 4179, 4180, 4181, 4182, 4183, 4184, + 4185, 4186, 4187, 4188, 4189, 4190, 4191, 32767, + 32767, 4192, 4193, 4194, 4195, 4196, 4197, 4198, + 4199, 4200, 4201, 4202, 4203, 32767, 4204, 4205, + 4206, 4207, 4208, 4209, 4210, 4211, 4212, 4213, + 827, 4215, 4216, 4217, 4218, 4219, 4220, 4221, + 4222, 32767, 4223, 4224, 4225, 828, 32767, 32767, + 32767, 32767, 4227, 4228, 4229, 32767, 4230, 32767, + 4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, + 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, + 4247, 4248, 4249, 4250, 4251, 822, 822, 822, + 822, 822, 822, 822, 822, 822, 822, -2901, + 2218, 2218, 822, 822, 822, 822, -9014, 822, + 822, 822, 822, 822, 822, 822, 3452, 822, + 822, 822, 3455, 822, 5284, 4284, 4285, 4286, + 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, + 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, + 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, + 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, + 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, + 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, + 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, + 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, + 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, + 4359, 861, 4361, 4362, 4363, 4364, 4365, 32767, + 32767, 32767, 32767, 32767, 4366, 4367, 4368, 4369, + 4370, 4371, 4372, 4373, 4374, 4375, 4376, 4377, + 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, + 4386, 4387, 4388, 4389, 4390, 4391, 0, 0, + 0, 4395, 4396, 4397, 4398, 4399, 4400, 4401, + 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, + 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, + 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425, + 4426, -4247, 4428, 4429, 636, 637, 638, 639, + 640, 641, 642, 643, 644, 2068, 2396, 4441, + 4442, 4443, 4444, 2405, 2406, 653, 654, 4449, + 4450, 8856, 4452, 4453, 4454, 4455, 4456, 4457, + 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, + 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, + 4474, 4475, 4476, 4477, 4478, 4479, 4480, 4481, + 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, + 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, + 4498, 4499, 4500, 4501, 4502, 4503, 4504, 4505, + 4506, 4507, 4508, 4509, 4510, 4511, 4512, 4513, + 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, + 4522, 2069, 4524, 4525, 4526, 4527, 4528, 4529, + 4530, 4531, 4532, 4533, 4534, 4535, 4536, -2729, + -2728, -2727, -2726, -2725, -2724, -2723, -2722, -2721, + -2720, -2719, -2718, -2717, -2716, -2715, -2714, -2713, + -2712, -2711, -2710, -2709, -2708, -2707, -2706, -2705, + -2704, -2703, -2702, -2701, -2700, -2699, -2698, -2697, + -2696, -2695, -2694, 2106, 2107, 2108, 2109, 2110, + 2111, 2112, 2113, 2114, 2115, 4574, 4575, 4576, + 2119, 2120, 2121, -527, -527, -527, -527, 7458, + -527, 14538, 2129, 14539, -528, -5886, 2493, -528, + -528, -528, 2137, 2138, 2139, 2140, 2141, 0, + 0, 0, 0, 2146, 2147, 2148, 2149, 2150, + 2151, 2152, 2153, -2153, -2153, 2156, -2152, -2152, + 2159, 2333, 2161, 2162, 3620, 2164, 3622, 2166, + 3624, 2168, 3627, 10704, 10704, 2172, 2173, 2174, + 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, + 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, + 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, + 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, + 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, + 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, + 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, + 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, + 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2246, + 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, + 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, + 2263, 5508, 5509, 2266, 2267, 2268, 2269, 2270, + -729, 2272, -2862, 2274, 2275, 2276, 2277, 2278, + 2279, 2280, 2281, 2282, 2283, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 2284, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 2285, 2286, -15504,2288, -3445, 2290, + 32767, 32767, 32767, 32767, 32767, 32767, 2291, 32767, + 4683, -2232, -2231, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1346, 0, 1347, 0, + 1348, 0, 15566, 0, 905, 0, 14359, 32767, + 2301, 32767, 2302, 32767, 2303, 32767, 2304, 32767, + 2305, 32767, 2306, 32767, 32767, 2307, 32767, 2308, + 32767, 2309, 32767, 32767, 32767, 32767, 32767, 32767, + -2491, -2491, 32767, -2492, 2313, 32767, 2314, 2315, + 32767, 2316, 2317, 32767, 2318, 2319, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2320, 32767, 32767, 32767, + 32767, 2321, 2322, 2323, 2324, 32767, 2325, 2326, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2327, 32767, 2328, 32767, + 2329, 32767, 2330, 32767, 9406, 32767, 2332, 32767, + 2333, 32767, 2334, 32767, 2335, 32767, 2336, 32767, + 2337, 32767, 2338, 32767, 32767, 2339, 32767, 2340, + 32767, 2341, 32767, 32767, 32767, 32767, 32767, 32767, + 2342, 2343, 32767, 2344, 2345, 32767, 2346, 2347, + 32767, 2348, 2349, 32767, 2350, 2351, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2352, 32767, 32767, 2353, + 2354, 2355, 2356, 32767, 32767, 32767, 2357, 2358, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 4768, 4769, 4770, 4771, 4772, 4773, 4774, 4775, + 4776, 15738, 4778, -5320, 0, 0, 0, 0, + 17791, 0, 5734, 0, -6442, 0, 0, 0, + 0, 0, 0, 0, -2391, 4525, 4525, 5741, + 4525, 5743, 1247, 5745, 4525, 0, 0, 4523, + 4523, 4523, 949, 949, 949, 949, 949, 949, + 949, 949, 949, -10012,949, 11048, -13268,-7118, + 1394, 5731, -12059,5733, 0, 5735, 0, 1206, + 0, 1208, 0, 1210, 0, 1212, 0, 1214, + 1215, 0, 1217, 0, 4497, 0, 1221, 4498, + 1223, 1224, 1225, 1226, 4801, 4802, 4803, 4804, + 0, 1232, 0, 0, 1235, 0, 0, 1238, + 0, 0, 4311, 1242, 1243, 1244, 1245, 1246, + 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, + 1255, 1256, 1257, 1258, 1259, 1260, 1261, 5759, + 0, 1264, 1265, 1266, 1267, 0, 0, 0, + 0, 1272, 0, 0, 1275, 1276, 1459, 5766, + 1279, 0, 0, 5767, 1457, 1284, 1457, 1457, + 0, 1457, 0, 1457, 0, -7077, 0, -7076, + -7075, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32767, + 32767, 0, 32767, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1337, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2478, 2479, 2480, + 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, + 2489, 2490, 2491, 2492, 2493, 3495, 3496, 3497, + 3498, 0, 3500, 3501, 2500, 2501, 2502, 2503, + 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, + 0, 0, 0, 0, 0, 2517, 2518, 2519, + 2520, 2521, 0, 0, 2524, 1484, 1484, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2540, 0, 0, 0, + 0, 0, 2546, 0, 2548, 0, 0, 2551, + 0, 0, 2554, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3893, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10472, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -5960, 0, 0, 0, -2716, -2716, -2716, + -2716, -2716, 0, -2717, 2418, -2717, -2717, -2717, + -2717, -2717, -2717, -2717, -2717, -2717, -2717, 0, + 0, -1086, -1086, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2662, + 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, + 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, + 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, + 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12178,-6443, 0, -6441, -6440, 637, -6439, + -6438, -6437, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2739, 2740, 2741, + 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, + 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, + 2758, 2759, -288, -288, -288, -288, -288, -288, + -288, 2767, 2768, 2769, 2770, 2771, 2772, 2773, + 2774, 2775, 2776, 2777, 2778, 2779, 2780, 2781, + 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, + 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, + 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, + 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, + 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, + 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829, + 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, + 2838, 2839, -288, 2841, 2842, 2843, 2844, 2845, + 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, + 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, + 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, + 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, + 2878, 2879, 2880, 2881, 2882, -288, -288, -288, + -288, -288, -288, 7697, -288, 14777, 11410, 14779, + -288, -5646, 2733, -288, -288, -288, -288, -288, + -288, -288, 91, -288, -288, 8091, 14782, 14783, + -936, 14785, 14786, 14787, 14788, 14789, 1523, 1523, + 1523, 1523, 1523, 4767, 4767, 4767, 4767, 4767, + 7767, 4767, 9902, 4767, 4767, 4767, 4767, 4767, + 4767, 4767, 4767, 4767, 4767, 7484, 7484, 6398, + 6398, 7484, 7484, 10457, 6395, 6395, -1797, 10463, + 10464, 4750, 4883, 4884, 4885, 10466, 10467, 10468, + 10469, 10470, 10471, 4892, 4893, 10426, -288, 4896, + 4897, -1779, 2968, 4899, 4900, 4901, 4902, 4903, + 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, + 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, + 4920, 4921, 0, 0, 4924, 4925, 4926, 4927, + 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, + 4936, 4937, 4938, 4939, 4940, 4941, 4942 + }; + + const unsigned char *k = (const unsigned char *) key; + size_t keylen = 4; + uint32 a = 0; + uint32 b = 1; + + while (keylen--) + { + unsigned char c = *k++; + + a = a * 257 + c; + b = b * 8191 + c; + } + return h[a % 13407] + h[b % 13407]; +} + +/* Hash lookup information for decomposition */ +static const pg_unicode_decompinfo UnicodeDecompInfo = +{ + UnicodeDecompMain, + Decomp_hash_func, + 6703 +}; + +/* Inverse lookup array -- contains indexes into UnicodeDecompMain[] */ +static const uint16 RecompInverseLookup[941] = +{ + /* U+003C+0338 -> U+226E */ 1857, + /* U+003D+0338 -> U+2260 */ 1854, + /* U+003E+0338 -> U+226F */ 1858, + /* U+0041+0300 -> U+00C0 */ 14, + /* U+0041+0301 -> U+00C1 */ 15, + /* U+0041+0302 -> U+00C2 */ 16, + /* U+0041+0303 -> U+00C3 */ 17, + /* U+0041+0304 -> U+0100 */ 67, + /* U+0041+0306 -> U+0102 */ 69, + /* U+0041+0307 -> U+0226 */ 270, + /* U+0041+0308 -> U+00C4 */ 18, + /* U+0041+0309 -> U+1EA2 */ 1312, + /* U+0041+030A -> U+00C5 */ 19, + /* U+0041+030C -> U+01CD */ 194, + /* U+0041+030F -> U+0200 */ 240, + /* U+0041+0311 -> U+0202 */ 242, + /* U+0041+0323 -> U+1EA0 */ 1310, + /* U+0041+0325 -> U+1E00 */ 1154, + /* U+0041+0328 -> U+0104 */ 71, + /* U+0042+0307 -> U+1E02 */ 1156, + /* U+0042+0323 -> U+1E04 */ 1158, + /* U+0042+0331 -> U+1E06 */ 1160, + /* U+0043+0301 -> U+0106 */ 73, + /* U+0043+0302 -> U+0108 */ 75, + /* U+0043+0307 -> U+010A */ 77, + /* U+0043+030C -> U+010C */ 79, + /* U+0043+0327 -> U+00C7 */ 20, + /* U+0044+0307 -> U+1E0A */ 1164, + /* U+0044+030C -> U+010E */ 81, + /* U+0044+0323 -> U+1E0C */ 1166, + /* U+0044+0327 -> U+1E10 */ 1170, + /* U+0044+032D -> U+1E12 */ 1172, + /* U+0044+0331 -> U+1E0E */ 1168, + /* U+0045+0300 -> U+00C8 */ 21, + /* U+0045+0301 -> U+00C9 */ 22, + /* U+0045+0302 -> U+00CA */ 23, + /* U+0045+0303 -> U+1EBC */ 1338, + /* U+0045+0304 -> U+0112 */ 83, + /* U+0045+0306 -> U+0114 */ 85, + /* U+0045+0307 -> U+0116 */ 87, + /* U+0045+0308 -> U+00CB */ 24, + /* U+0045+0309 -> U+1EBA */ 1336, + /* U+0045+030C -> U+011A */ 91, + /* U+0045+030F -> U+0204 */ 244, + /* U+0045+0311 -> U+0206 */ 246, + /* U+0045+0323 -> U+1EB8 */ 1334, + /* U+0045+0327 -> U+0228 */ 272, + /* U+0045+0328 -> U+0118 */ 89, + /* U+0045+032D -> U+1E18 */ 1178, + /* U+0045+0330 -> U+1E1A */ 1180, + /* U+0046+0307 -> U+1E1E */ 1184, + /* U+0047+0301 -> U+01F4 */ 230, + /* U+0047+0302 -> U+011C */ 93, + /* U+0047+0304 -> U+1E20 */ 1186, + /* U+0047+0306 -> U+011E */ 95, + /* U+0047+0307 -> U+0120 */ 97, + /* U+0047+030C -> U+01E6 */ 216, + /* U+0047+0327 -> U+0122 */ 99, + /* U+0048+0302 -> U+0124 */ 101, + /* U+0048+0307 -> U+1E22 */ 1188, + /* U+0048+0308 -> U+1E26 */ 1192, + /* U+0048+030C -> U+021E */ 268, + /* U+0048+0323 -> U+1E24 */ 1190, + /* U+0048+0327 -> U+1E28 */ 1194, + /* U+0048+032E -> U+1E2A */ 1196, + /* U+0049+0300 -> U+00CC */ 25, + /* U+0049+0301 -> U+00CD */ 26, + /* U+0049+0302 -> U+00CE */ 27, + /* U+0049+0303 -> U+0128 */ 103, + /* U+0049+0304 -> U+012A */ 105, + /* U+0049+0306 -> U+012C */ 107, + /* U+0049+0307 -> U+0130 */ 111, + /* U+0049+0308 -> U+00CF */ 28, + /* U+0049+0309 -> U+1EC8 */ 1350, + /* U+0049+030C -> U+01CF */ 196, + /* U+0049+030F -> U+0208 */ 248, + /* U+0049+0311 -> U+020A */ 250, + /* U+0049+0323 -> U+1ECA */ 1352, + /* U+0049+0328 -> U+012E */ 109, + /* U+0049+0330 -> U+1E2C */ 1198, + /* U+004A+0302 -> U+0134 */ 114, + /* U+004B+0301 -> U+1E30 */ 1202, + /* U+004B+030C -> U+01E8 */ 218, + /* U+004B+0323 -> U+1E32 */ 1204, + /* U+004B+0327 -> U+0136 */ 116, + /* U+004B+0331 -> U+1E34 */ 1206, + /* U+004C+0301 -> U+0139 */ 118, + /* U+004C+030C -> U+013D */ 122, + /* U+004C+0323 -> U+1E36 */ 1208, + /* U+004C+0327 -> U+013B */ 120, + /* U+004C+032D -> U+1E3C */ 1214, + /* U+004C+0331 -> U+1E3A */ 1212, + /* U+004D+0301 -> U+1E3E */ 1216, + /* U+004D+0307 -> U+1E40 */ 1218, + /* U+004D+0323 -> U+1E42 */ 1220, + /* U+004E+0300 -> U+01F8 */ 232, + /* U+004E+0301 -> U+0143 */ 126, + /* U+004E+0303 -> U+00D1 */ 29, + /* U+004E+0307 -> U+1E44 */ 1222, + /* U+004E+030C -> U+0147 */ 130, + /* U+004E+0323 -> U+1E46 */ 1224, + /* U+004E+0327 -> U+0145 */ 128, + /* U+004E+032D -> U+1E4A */ 1228, + /* U+004E+0331 -> U+1E48 */ 1226, + /* U+004F+0300 -> U+00D2 */ 30, + /* U+004F+0301 -> U+00D3 */ 31, + /* U+004F+0302 -> U+00D4 */ 32, + /* U+004F+0303 -> U+00D5 */ 33, + /* U+004F+0304 -> U+014C */ 133, + /* U+004F+0306 -> U+014E */ 135, + /* U+004F+0307 -> U+022E */ 278, + /* U+004F+0308 -> U+00D6 */ 34, + /* U+004F+0309 -> U+1ECE */ 1356, + /* U+004F+030B -> U+0150 */ 137, + /* U+004F+030C -> U+01D1 */ 198, + /* U+004F+030F -> U+020C */ 252, + /* U+004F+0311 -> U+020E */ 254, + /* U+004F+031B -> U+01A0 */ 181, + /* U+004F+0323 -> U+1ECC */ 1354, + /* U+004F+0328 -> U+01EA */ 220, + /* U+0050+0301 -> U+1E54 */ 1238, + /* U+0050+0307 -> U+1E56 */ 1240, + /* U+0052+0301 -> U+0154 */ 139, + /* U+0052+0307 -> U+1E58 */ 1242, + /* U+0052+030C -> U+0158 */ 143, + /* U+0052+030F -> U+0210 */ 256, + /* U+0052+0311 -> U+0212 */ 258, + /* U+0052+0323 -> U+1E5A */ 1244, + /* U+0052+0327 -> U+0156 */ 141, + /* U+0052+0331 -> U+1E5E */ 1248, + /* U+0053+0301 -> U+015A */ 145, + /* U+0053+0302 -> U+015C */ 147, + /* U+0053+0307 -> U+1E60 */ 1250, + /* U+0053+030C -> U+0160 */ 151, + /* U+0053+0323 -> U+1E62 */ 1252, + /* U+0053+0326 -> U+0218 */ 264, + /* U+0053+0327 -> U+015E */ 149, + /* U+0054+0307 -> U+1E6A */ 1260, + /* U+0054+030C -> U+0164 */ 155, + /* U+0054+0323 -> U+1E6C */ 1262, + /* U+0054+0326 -> U+021A */ 266, + /* U+0054+0327 -> U+0162 */ 153, + /* U+0054+032D -> U+1E70 */ 1266, + /* U+0054+0331 -> U+1E6E */ 1264, + /* U+0055+0300 -> U+00D9 */ 35, + /* U+0055+0301 -> U+00DA */ 36, + /* U+0055+0302 -> U+00DB */ 37, + /* U+0055+0303 -> U+0168 */ 157, + /* U+0055+0304 -> U+016A */ 159, + /* U+0055+0306 -> U+016C */ 161, + /* U+0055+0308 -> U+00DC */ 38, + /* U+0055+0309 -> U+1EE6 */ 1380, + /* U+0055+030A -> U+016E */ 163, + /* U+0055+030B -> U+0170 */ 165, + /* U+0055+030C -> U+01D3 */ 200, + /* U+0055+030F -> U+0214 */ 260, + /* U+0055+0311 -> U+0216 */ 262, + /* U+0055+031B -> U+01AF */ 183, + /* U+0055+0323 -> U+1EE4 */ 1378, + /* U+0055+0324 -> U+1E72 */ 1268, + /* U+0055+0328 -> U+0172 */ 167, + /* U+0055+032D -> U+1E76 */ 1272, + /* U+0055+0330 -> U+1E74 */ 1270, + /* U+0056+0303 -> U+1E7C */ 1278, + /* U+0056+0323 -> U+1E7E */ 1280, + /* U+0057+0300 -> U+1E80 */ 1282, + /* U+0057+0301 -> U+1E82 */ 1284, + /* U+0057+0302 -> U+0174 */ 169, + /* U+0057+0307 -> U+1E86 */ 1288, + /* U+0057+0308 -> U+1E84 */ 1286, + /* U+0057+0323 -> U+1E88 */ 1290, + /* U+0058+0307 -> U+1E8A */ 1292, + /* U+0058+0308 -> U+1E8C */ 1294, + /* U+0059+0300 -> U+1EF2 */ 1392, + /* U+0059+0301 -> U+00DD */ 39, + /* U+0059+0302 -> U+0176 */ 171, + /* U+0059+0303 -> U+1EF8 */ 1398, + /* U+0059+0304 -> U+0232 */ 282, + /* U+0059+0307 -> U+1E8E */ 1296, + /* U+0059+0308 -> U+0178 */ 173, + /* U+0059+0309 -> U+1EF6 */ 1396, + /* U+0059+0323 -> U+1EF4 */ 1394, + /* U+005A+0301 -> U+0179 */ 174, + /* U+005A+0302 -> U+1E90 */ 1298, + /* U+005A+0307 -> U+017B */ 176, + /* U+005A+030C -> U+017D */ 178, + /* U+005A+0323 -> U+1E92 */ 1300, + /* U+005A+0331 -> U+1E94 */ 1302, + /* U+0061+0300 -> U+00E0 */ 40, + /* U+0061+0301 -> U+00E1 */ 41, + /* U+0061+0302 -> U+00E2 */ 42, + /* U+0061+0303 -> U+00E3 */ 43, + /* U+0061+0304 -> U+0101 */ 68, + /* U+0061+0306 -> U+0103 */ 70, + /* U+0061+0307 -> U+0227 */ 271, + /* U+0061+0308 -> U+00E4 */ 44, + /* U+0061+0309 -> U+1EA3 */ 1313, + /* U+0061+030A -> U+00E5 */ 45, + /* U+0061+030C -> U+01CE */ 195, + /* U+0061+030F -> U+0201 */ 241, + /* U+0061+0311 -> U+0203 */ 243, + /* U+0061+0323 -> U+1EA1 */ 1311, + /* U+0061+0325 -> U+1E01 */ 1155, + /* U+0061+0328 -> U+0105 */ 72, + /* U+0062+0307 -> U+1E03 */ 1157, + /* U+0062+0323 -> U+1E05 */ 1159, + /* U+0062+0331 -> U+1E07 */ 1161, + /* U+0063+0301 -> U+0107 */ 74, + /* U+0063+0302 -> U+0109 */ 76, + /* U+0063+0307 -> U+010B */ 78, + /* U+0063+030C -> U+010D */ 80, + /* U+0063+0327 -> U+00E7 */ 46, + /* U+0064+0307 -> U+1E0B */ 1165, + /* U+0064+030C -> U+010F */ 82, + /* U+0064+0323 -> U+1E0D */ 1167, + /* U+0064+0327 -> U+1E11 */ 1171, + /* U+0064+032D -> U+1E13 */ 1173, + /* U+0064+0331 -> U+1E0F */ 1169, + /* U+0065+0300 -> U+00E8 */ 47, + /* U+0065+0301 -> U+00E9 */ 48, + /* U+0065+0302 -> U+00EA */ 49, + /* U+0065+0303 -> U+1EBD */ 1339, + /* U+0065+0304 -> U+0113 */ 84, + /* U+0065+0306 -> U+0115 */ 86, + /* U+0065+0307 -> U+0117 */ 88, + /* U+0065+0308 -> U+00EB */ 50, + /* U+0065+0309 -> U+1EBB */ 1337, + /* U+0065+030C -> U+011B */ 92, + /* U+0065+030F -> U+0205 */ 245, + /* U+0065+0311 -> U+0207 */ 247, + /* U+0065+0323 -> U+1EB9 */ 1335, + /* U+0065+0327 -> U+0229 */ 273, + /* U+0065+0328 -> U+0119 */ 90, + /* U+0065+032D -> U+1E19 */ 1179, + /* U+0065+0330 -> U+1E1B */ 1181, + /* U+0066+0307 -> U+1E1F */ 1185, + /* U+0067+0301 -> U+01F5 */ 231, + /* U+0067+0302 -> U+011D */ 94, + /* U+0067+0304 -> U+1E21 */ 1187, + /* U+0067+0306 -> U+011F */ 96, + /* U+0067+0307 -> U+0121 */ 98, + /* U+0067+030C -> U+01E7 */ 217, + /* U+0067+0327 -> U+0123 */ 100, + /* U+0068+0302 -> U+0125 */ 102, + /* U+0068+0307 -> U+1E23 */ 1189, + /* U+0068+0308 -> U+1E27 */ 1193, + /* U+0068+030C -> U+021F */ 269, + /* U+0068+0323 -> U+1E25 */ 1191, + /* U+0068+0327 -> U+1E29 */ 1195, + /* U+0068+032E -> U+1E2B */ 1197, + /* U+0068+0331 -> U+1E96 */ 1304, + /* U+0069+0300 -> U+00EC */ 51, + /* U+0069+0301 -> U+00ED */ 52, + /* U+0069+0302 -> U+00EE */ 53, + /* U+0069+0303 -> U+0129 */ 104, + /* U+0069+0304 -> U+012B */ 106, + /* U+0069+0306 -> U+012D */ 108, + /* U+0069+0308 -> U+00EF */ 54, + /* U+0069+0309 -> U+1EC9 */ 1351, + /* U+0069+030C -> U+01D0 */ 197, + /* U+0069+030F -> U+0209 */ 249, + /* U+0069+0311 -> U+020B */ 251, + /* U+0069+0323 -> U+1ECB */ 1353, + /* U+0069+0328 -> U+012F */ 110, + /* U+0069+0330 -> U+1E2D */ 1199, + /* U+006A+0302 -> U+0135 */ 115, + /* U+006A+030C -> U+01F0 */ 226, + /* U+006B+0301 -> U+1E31 */ 1203, + /* U+006B+030C -> U+01E9 */ 219, + /* U+006B+0323 -> U+1E33 */ 1205, + /* U+006B+0327 -> U+0137 */ 117, + /* U+006B+0331 -> U+1E35 */ 1207, + /* U+006C+0301 -> U+013A */ 119, + /* U+006C+030C -> U+013E */ 123, + /* U+006C+0323 -> U+1E37 */ 1209, + /* U+006C+0327 -> U+013C */ 121, + /* U+006C+032D -> U+1E3D */ 1215, + /* U+006C+0331 -> U+1E3B */ 1213, + /* U+006D+0301 -> U+1E3F */ 1217, + /* U+006D+0307 -> U+1E41 */ 1219, + /* U+006D+0323 -> U+1E43 */ 1221, + /* U+006E+0300 -> U+01F9 */ 233, + /* U+006E+0301 -> U+0144 */ 127, + /* U+006E+0303 -> U+00F1 */ 55, + /* U+006E+0307 -> U+1E45 */ 1223, + /* U+006E+030C -> U+0148 */ 131, + /* U+006E+0323 -> U+1E47 */ 1225, + /* U+006E+0327 -> U+0146 */ 129, + /* U+006E+032D -> U+1E4B */ 1229, + /* U+006E+0331 -> U+1E49 */ 1227, + /* U+006F+0300 -> U+00F2 */ 56, + /* U+006F+0301 -> U+00F3 */ 57, + /* U+006F+0302 -> U+00F4 */ 58, + /* U+006F+0303 -> U+00F5 */ 59, + /* U+006F+0304 -> U+014D */ 134, + /* U+006F+0306 -> U+014F */ 136, + /* U+006F+0307 -> U+022F */ 279, + /* U+006F+0308 -> U+00F6 */ 60, + /* U+006F+0309 -> U+1ECF */ 1357, + /* U+006F+030B -> U+0151 */ 138, + /* U+006F+030C -> U+01D2 */ 199, + /* U+006F+030F -> U+020D */ 253, + /* U+006F+0311 -> U+020F */ 255, + /* U+006F+031B -> U+01A1 */ 182, + /* U+006F+0323 -> U+1ECD */ 1355, + /* U+006F+0328 -> U+01EB */ 221, + /* U+0070+0301 -> U+1E55 */ 1239, + /* U+0070+0307 -> U+1E57 */ 1241, + /* U+0072+0301 -> U+0155 */ 140, + /* U+0072+0307 -> U+1E59 */ 1243, + /* U+0072+030C -> U+0159 */ 144, + /* U+0072+030F -> U+0211 */ 257, + /* U+0072+0311 -> U+0213 */ 259, + /* U+0072+0323 -> U+1E5B */ 1245, + /* U+0072+0327 -> U+0157 */ 142, + /* U+0072+0331 -> U+1E5F */ 1249, + /* U+0073+0301 -> U+015B */ 146, + /* U+0073+0302 -> U+015D */ 148, + /* U+0073+0307 -> U+1E61 */ 1251, + /* U+0073+030C -> U+0161 */ 152, + /* U+0073+0323 -> U+1E63 */ 1253, + /* U+0073+0326 -> U+0219 */ 265, + /* U+0073+0327 -> U+015F */ 150, + /* U+0074+0307 -> U+1E6B */ 1261, + /* U+0074+0308 -> U+1E97 */ 1305, + /* U+0074+030C -> U+0165 */ 156, + /* U+0074+0323 -> U+1E6D */ 1263, + /* U+0074+0326 -> U+021B */ 267, + /* U+0074+0327 -> U+0163 */ 154, + /* U+0074+032D -> U+1E71 */ 1267, + /* U+0074+0331 -> U+1E6F */ 1265, + /* U+0075+0300 -> U+00F9 */ 61, + /* U+0075+0301 -> U+00FA */ 62, + /* U+0075+0302 -> U+00FB */ 63, + /* U+0075+0303 -> U+0169 */ 158, + /* U+0075+0304 -> U+016B */ 160, + /* U+0075+0306 -> U+016D */ 162, + /* U+0075+0308 -> U+00FC */ 64, + /* U+0075+0309 -> U+1EE7 */ 1381, + /* U+0075+030A -> U+016F */ 164, + /* U+0075+030B -> U+0171 */ 166, + /* U+0075+030C -> U+01D4 */ 201, + /* U+0075+030F -> U+0215 */ 261, + /* U+0075+0311 -> U+0217 */ 263, + /* U+0075+031B -> U+01B0 */ 184, + /* U+0075+0323 -> U+1EE5 */ 1379, + /* U+0075+0324 -> U+1E73 */ 1269, + /* U+0075+0328 -> U+0173 */ 168, + /* U+0075+032D -> U+1E77 */ 1273, + /* U+0075+0330 -> U+1E75 */ 1271, + /* U+0076+0303 -> U+1E7D */ 1279, + /* U+0076+0323 -> U+1E7F */ 1281, + /* U+0077+0300 -> U+1E81 */ 1283, + /* U+0077+0301 -> U+1E83 */ 1285, + /* U+0077+0302 -> U+0175 */ 170, + /* U+0077+0307 -> U+1E87 */ 1289, + /* U+0077+0308 -> U+1E85 */ 1287, + /* U+0077+030A -> U+1E98 */ 1306, + /* U+0077+0323 -> U+1E89 */ 1291, + /* U+0078+0307 -> U+1E8B */ 1293, + /* U+0078+0308 -> U+1E8D */ 1295, + /* U+0079+0300 -> U+1EF3 */ 1393, + /* U+0079+0301 -> U+00FD */ 65, + /* U+0079+0302 -> U+0177 */ 172, + /* U+0079+0303 -> U+1EF9 */ 1399, + /* U+0079+0304 -> U+0233 */ 283, + /* U+0079+0307 -> U+1E8F */ 1297, + /* U+0079+0308 -> U+00FF */ 66, + /* U+0079+0309 -> U+1EF7 */ 1397, + /* U+0079+030A -> U+1E99 */ 1307, + /* U+0079+0323 -> U+1EF5 */ 1395, + /* U+007A+0301 -> U+017A */ 175, + /* U+007A+0302 -> U+1E91 */ 1299, + /* U+007A+0307 -> U+017C */ 177, + /* U+007A+030C -> U+017E */ 179, + /* U+007A+0323 -> U+1E93 */ 1301, + /* U+007A+0331 -> U+1E95 */ 1303, + /* U+00A8+0300 -> U+1FED */ 1618, + /* U+00A8+0301 -> U+0385 */ 419, + /* U+00A8+0342 -> U+1FC1 */ 1578, + /* U+00C2+0300 -> U+1EA6 */ 1316, + /* U+00C2+0301 -> U+1EA4 */ 1314, + /* U+00C2+0303 -> U+1EAA */ 1320, + /* U+00C2+0309 -> U+1EA8 */ 1318, + /* U+00C4+0304 -> U+01DE */ 210, + /* U+00C5+0301 -> U+01FA */ 234, + /* U+00C6+0301 -> U+01FC */ 236, + /* U+00C6+0304 -> U+01E2 */ 214, + /* U+00C7+0301 -> U+1E08 */ 1162, + /* U+00CA+0300 -> U+1EC0 */ 1342, + /* U+00CA+0301 -> U+1EBE */ 1340, + /* U+00CA+0303 -> U+1EC4 */ 1346, + /* U+00CA+0309 -> U+1EC2 */ 1344, + /* U+00CF+0301 -> U+1E2E */ 1200, + /* U+00D4+0300 -> U+1ED2 */ 1360, + /* U+00D4+0301 -> U+1ED0 */ 1358, + /* U+00D4+0303 -> U+1ED6 */ 1364, + /* U+00D4+0309 -> U+1ED4 */ 1362, + /* U+00D5+0301 -> U+1E4C */ 1230, + /* U+00D5+0304 -> U+022C */ 276, + /* U+00D5+0308 -> U+1E4E */ 1232, + /* U+00D6+0304 -> U+022A */ 274, + /* U+00D8+0301 -> U+01FE */ 238, + /* U+00DC+0300 -> U+01DB */ 208, + /* U+00DC+0301 -> U+01D7 */ 204, + /* U+00DC+0304 -> U+01D5 */ 202, + /* U+00DC+030C -> U+01D9 */ 206, + /* U+00E2+0300 -> U+1EA7 */ 1317, + /* U+00E2+0301 -> U+1EA5 */ 1315, + /* U+00E2+0303 -> U+1EAB */ 1321, + /* U+00E2+0309 -> U+1EA9 */ 1319, + /* U+00E4+0304 -> U+01DF */ 211, + /* U+00E5+0301 -> U+01FB */ 235, + /* U+00E6+0301 -> U+01FD */ 237, + /* U+00E6+0304 -> U+01E3 */ 215, + /* U+00E7+0301 -> U+1E09 */ 1163, + /* U+00EA+0300 -> U+1EC1 */ 1343, + /* U+00EA+0301 -> U+1EBF */ 1341, + /* U+00EA+0303 -> U+1EC5 */ 1347, + /* U+00EA+0309 -> U+1EC3 */ 1345, + /* U+00EF+0301 -> U+1E2F */ 1201, + /* U+00F4+0300 -> U+1ED3 */ 1361, + /* U+00F4+0301 -> U+1ED1 */ 1359, + /* U+00F4+0303 -> U+1ED7 */ 1365, + /* U+00F4+0309 -> U+1ED5 */ 1363, + /* U+00F5+0301 -> U+1E4D */ 1231, + /* U+00F5+0304 -> U+022D */ 277, + /* U+00F5+0308 -> U+1E4F */ 1233, + /* U+00F6+0304 -> U+022B */ 275, + /* U+00F8+0301 -> U+01FF */ 239, + /* U+00FC+0300 -> U+01DC */ 209, + /* U+00FC+0301 -> U+01D8 */ 205, + /* U+00FC+0304 -> U+01D6 */ 203, + /* U+00FC+030C -> U+01DA */ 207, + /* U+0102+0300 -> U+1EB0 */ 1326, + /* U+0102+0301 -> U+1EAE */ 1324, + /* U+0102+0303 -> U+1EB4 */ 1330, + /* U+0102+0309 -> U+1EB2 */ 1328, + /* U+0103+0300 -> U+1EB1 */ 1327, + /* U+0103+0301 -> U+1EAF */ 1325, + /* U+0103+0303 -> U+1EB5 */ 1331, + /* U+0103+0309 -> U+1EB3 */ 1329, + /* U+0112+0300 -> U+1E14 */ 1174, + /* U+0112+0301 -> U+1E16 */ 1176, + /* U+0113+0300 -> U+1E15 */ 1175, + /* U+0113+0301 -> U+1E17 */ 1177, + /* U+014C+0300 -> U+1E50 */ 1234, + /* U+014C+0301 -> U+1E52 */ 1236, + /* U+014D+0300 -> U+1E51 */ 1235, + /* U+014D+0301 -> U+1E53 */ 1237, + /* U+015A+0307 -> U+1E64 */ 1254, + /* U+015B+0307 -> U+1E65 */ 1255, + /* U+0160+0307 -> U+1E66 */ 1256, + /* U+0161+0307 -> U+1E67 */ 1257, + /* U+0168+0301 -> U+1E78 */ 1274, + /* U+0169+0301 -> U+1E79 */ 1275, + /* U+016A+0308 -> U+1E7A */ 1276, + /* U+016B+0308 -> U+1E7B */ 1277, + /* U+017F+0307 -> U+1E9B */ 1309, + /* U+01A0+0300 -> U+1EDC */ 1370, + /* U+01A0+0301 -> U+1EDA */ 1368, + /* U+01A0+0303 -> U+1EE0 */ 1374, + /* U+01A0+0309 -> U+1EDE */ 1372, + /* U+01A0+0323 -> U+1EE2 */ 1376, + /* U+01A1+0300 -> U+1EDD */ 1371, + /* U+01A1+0301 -> U+1EDB */ 1369, + /* U+01A1+0303 -> U+1EE1 */ 1375, + /* U+01A1+0309 -> U+1EDF */ 1373, + /* U+01A1+0323 -> U+1EE3 */ 1377, + /* U+01AF+0300 -> U+1EEA */ 1384, + /* U+01AF+0301 -> U+1EE8 */ 1382, + /* U+01AF+0303 -> U+1EEE */ 1388, + /* U+01AF+0309 -> U+1EEC */ 1386, + /* U+01AF+0323 -> U+1EF0 */ 1390, + /* U+01B0+0300 -> U+1EEB */ 1385, + /* U+01B0+0301 -> U+1EE9 */ 1383, + /* U+01B0+0303 -> U+1EEF */ 1389, + /* U+01B0+0309 -> U+1EED */ 1387, + /* U+01B0+0323 -> U+1EF1 */ 1391, + /* U+01B7+030C -> U+01EE */ 224, + /* U+01EA+0304 -> U+01EC */ 222, + /* U+01EB+0304 -> U+01ED */ 223, + /* U+0226+0304 -> U+01E0 */ 212, + /* U+0227+0304 -> U+01E1 */ 213, + /* U+0228+0306 -> U+1E1C */ 1182, + /* U+0229+0306 -> U+1E1D */ 1183, + /* U+022E+0304 -> U+0230 */ 280, + /* U+022F+0304 -> U+0231 */ 281, + /* U+0292+030C -> U+01EF */ 225, + /* U+0391+0300 -> U+1FBA */ 1571, + /* U+0391+0301 -> U+0386 */ 420, + /* U+0391+0304 -> U+1FB9 */ 1570, + /* U+0391+0306 -> U+1FB8 */ 1569, + /* U+0391+0313 -> U+1F08 */ 1408, + /* U+0391+0314 -> U+1F09 */ 1409, + /* U+0391+0345 -> U+1FBC */ 1573, + /* U+0395+0300 -> U+1FC8 */ 1584, + /* U+0395+0301 -> U+0388 */ 422, + /* U+0395+0313 -> U+1F18 */ 1422, + /* U+0395+0314 -> U+1F19 */ 1423, + /* U+0397+0300 -> U+1FCA */ 1586, + /* U+0397+0301 -> U+0389 */ 423, + /* U+0397+0313 -> U+1F28 */ 1436, + /* U+0397+0314 -> U+1F29 */ 1437, + /* U+0397+0345 -> U+1FCC */ 1588, + /* U+0399+0300 -> U+1FDA */ 1600, + /* U+0399+0301 -> U+038A */ 424, + /* U+0399+0304 -> U+1FD9 */ 1599, + /* U+0399+0306 -> U+1FD8 */ 1598, + /* U+0399+0308 -> U+03AA */ 429, + /* U+0399+0313 -> U+1F38 */ 1452, + /* U+0399+0314 -> U+1F39 */ 1453, + /* U+039F+0300 -> U+1FF8 */ 1626, + /* U+039F+0301 -> U+038C */ 425, + /* U+039F+0313 -> U+1F48 */ 1466, + /* U+039F+0314 -> U+1F49 */ 1467, + /* U+03A1+0314 -> U+1FEC */ 1617, + /* U+03A5+0300 -> U+1FEA */ 1615, + /* U+03A5+0301 -> U+038E */ 426, + /* U+03A5+0304 -> U+1FE9 */ 1614, + /* U+03A5+0306 -> U+1FE8 */ 1613, + /* U+03A5+0308 -> U+03AB */ 430, + /* U+03A5+0314 -> U+1F59 */ 1480, + /* U+03A9+0300 -> U+1FFA */ 1628, + /* U+03A9+0301 -> U+038F */ 427, + /* U+03A9+0313 -> U+1F68 */ 1492, + /* U+03A9+0314 -> U+1F69 */ 1493, + /* U+03A9+0345 -> U+1FFC */ 1630, + /* U+03AC+0345 -> U+1FB4 */ 1566, + /* U+03AE+0345 -> U+1FC4 */ 1581, + /* U+03B1+0300 -> U+1F70 */ 1500, + /* U+03B1+0301 -> U+03AC */ 431, + /* U+03B1+0304 -> U+1FB1 */ 1563, + /* U+03B1+0306 -> U+1FB0 */ 1562, + /* U+03B1+0313 -> U+1F00 */ 1400, + /* U+03B1+0314 -> U+1F01 */ 1401, + /* U+03B1+0342 -> U+1FB6 */ 1567, + /* U+03B1+0345 -> U+1FB3 */ 1565, + /* U+03B5+0300 -> U+1F72 */ 1502, + /* U+03B5+0301 -> U+03AD */ 432, + /* U+03B5+0313 -> U+1F10 */ 1416, + /* U+03B5+0314 -> U+1F11 */ 1417, + /* U+03B7+0300 -> U+1F74 */ 1504, + /* U+03B7+0301 -> U+03AE */ 433, + /* U+03B7+0313 -> U+1F20 */ 1428, + /* U+03B7+0314 -> U+1F21 */ 1429, + /* U+03B7+0342 -> U+1FC6 */ 1582, + /* U+03B7+0345 -> U+1FC3 */ 1580, + /* U+03B9+0300 -> U+1F76 */ 1506, + /* U+03B9+0301 -> U+03AF */ 434, + /* U+03B9+0304 -> U+1FD1 */ 1593, + /* U+03B9+0306 -> U+1FD0 */ 1592, + /* U+03B9+0308 -> U+03CA */ 436, + /* U+03B9+0313 -> U+1F30 */ 1444, + /* U+03B9+0314 -> U+1F31 */ 1445, + /* U+03B9+0342 -> U+1FD6 */ 1596, + /* U+03BF+0300 -> U+1F78 */ 1508, + /* U+03BF+0301 -> U+03CC */ 438, + /* U+03BF+0313 -> U+1F40 */ 1460, + /* U+03BF+0314 -> U+1F41 */ 1461, + /* U+03C1+0313 -> U+1FE4 */ 1609, + /* U+03C1+0314 -> U+1FE5 */ 1610, + /* U+03C5+0300 -> U+1F7A */ 1510, + /* U+03C5+0301 -> U+03CD */ 439, + /* U+03C5+0304 -> U+1FE1 */ 1606, + /* U+03C5+0306 -> U+1FE0 */ 1605, + /* U+03C5+0308 -> U+03CB */ 437, + /* U+03C5+0313 -> U+1F50 */ 1472, + /* U+03C5+0314 -> U+1F51 */ 1473, + /* U+03C5+0342 -> U+1FE6 */ 1611, + /* U+03C9+0300 -> U+1F7C */ 1512, + /* U+03C9+0301 -> U+03CE */ 440, + /* U+03C9+0313 -> U+1F60 */ 1484, + /* U+03C9+0314 -> U+1F61 */ 1485, + /* U+03C9+0342 -> U+1FF6 */ 1624, + /* U+03C9+0345 -> U+1FF3 */ 1622, + /* U+03CA+0300 -> U+1FD2 */ 1594, + /* U+03CA+0301 -> U+0390 */ 428, + /* U+03CA+0342 -> U+1FD7 */ 1597, + /* U+03CB+0300 -> U+1FE2 */ 1607, + /* U+03CB+0301 -> U+03B0 */ 435, + /* U+03CB+0342 -> U+1FE7 */ 1612, + /* U+03CE+0345 -> U+1FF4 */ 1623, + /* U+03D2+0301 -> U+03D3 */ 444, + /* U+03D2+0308 -> U+03D4 */ 445, + /* U+0406+0308 -> U+0407 */ 457, + /* U+0410+0306 -> U+04D0 */ 479, + /* U+0410+0308 -> U+04D2 */ 481, + /* U+0413+0301 -> U+0403 */ 456, + /* U+0415+0300 -> U+0400 */ 454, + /* U+0415+0306 -> U+04D6 */ 483, + /* U+0415+0308 -> U+0401 */ 455, + /* U+0416+0306 -> U+04C1 */ 477, + /* U+0416+0308 -> U+04DC */ 487, + /* U+0417+0308 -> U+04DE */ 489, + /* U+0418+0300 -> U+040D */ 459, + /* U+0418+0304 -> U+04E2 */ 491, + /* U+0418+0306 -> U+0419 */ 461, + /* U+0418+0308 -> U+04E4 */ 493, + /* U+041A+0301 -> U+040C */ 458, + /* U+041E+0308 -> U+04E6 */ 495, + /* U+0423+0304 -> U+04EE */ 501, + /* U+0423+0306 -> U+040E */ 460, + /* U+0423+0308 -> U+04F0 */ 503, + /* U+0423+030B -> U+04F2 */ 505, + /* U+0427+0308 -> U+04F4 */ 507, + /* U+042B+0308 -> U+04F8 */ 509, + /* U+042D+0308 -> U+04EC */ 499, + /* U+0430+0306 -> U+04D1 */ 480, + /* U+0430+0308 -> U+04D3 */ 482, + /* U+0433+0301 -> U+0453 */ 465, + /* U+0435+0300 -> U+0450 */ 463, + /* U+0435+0306 -> U+04D7 */ 484, + /* U+0435+0308 -> U+0451 */ 464, + /* U+0436+0306 -> U+04C2 */ 478, + /* U+0436+0308 -> U+04DD */ 488, + /* U+0437+0308 -> U+04DF */ 490, + /* U+0438+0300 -> U+045D */ 468, + /* U+0438+0304 -> U+04E3 */ 492, + /* U+0438+0306 -> U+0439 */ 462, + /* U+0438+0308 -> U+04E5 */ 494, + /* U+043A+0301 -> U+045C */ 467, + /* U+043E+0308 -> U+04E7 */ 496, + /* U+0443+0304 -> U+04EF */ 502, + /* U+0443+0306 -> U+045E */ 469, + /* U+0443+0308 -> U+04F1 */ 504, + /* U+0443+030B -> U+04F3 */ 506, + /* U+0447+0308 -> U+04F5 */ 508, + /* U+044B+0308 -> U+04F9 */ 510, + /* U+044D+0308 -> U+04ED */ 500, + /* U+0456+0308 -> U+0457 */ 466, + /* U+0474+030F -> U+0476 */ 470, + /* U+0475+030F -> U+0477 */ 471, + /* U+04D8+0308 -> U+04DA */ 485, + /* U+04D9+0308 -> U+04DB */ 486, + /* U+04E8+0308 -> U+04EA */ 497, + /* U+04E9+0308 -> U+04EB */ 498, + /* U+0627+0653 -> U+0622 */ 574, + /* U+0627+0654 -> U+0623 */ 575, + /* U+0627+0655 -> U+0625 */ 577, + /* U+0648+0654 -> U+0624 */ 576, + /* U+064A+0654 -> U+0626 */ 578, + /* U+06C1+0654 -> U+06C2 */ 606, + /* U+06D2+0654 -> U+06D3 */ 607, + /* U+06D5+0654 -> U+06C0 */ 605, + /* U+0928+093C -> U+0929 */ 750, + /* U+0930+093C -> U+0931 */ 751, + /* U+0933+093C -> U+0934 */ 752, + /* U+09C7+09BE -> U+09CB */ 768, + /* U+09C7+09D7 -> U+09CC */ 769, + /* U+0B47+0B3E -> U+0B4B */ 787, + /* U+0B47+0B56 -> U+0B48 */ 786, + /* U+0B47+0B57 -> U+0B4C */ 788, + /* U+0B92+0BD7 -> U+0B94 */ 792, + /* U+0BC6+0BBE -> U+0BCA */ 793, + /* U+0BC6+0BD7 -> U+0BCC */ 795, + /* U+0BC7+0BBE -> U+0BCB */ 794, + /* U+0C46+0C56 -> U+0C48 */ 798, + /* U+0CBF+0CD5 -> U+0CC0 */ 803, + /* U+0CC6+0CC2 -> U+0CCA */ 806, + /* U+0CC6+0CD5 -> U+0CC7 */ 804, + /* U+0CC6+0CD6 -> U+0CC8 */ 805, + /* U+0CCA+0CD5 -> U+0CCB */ 807, + /* U+0D46+0D3E -> U+0D4A */ 811, + /* U+0D46+0D57 -> U+0D4C */ 813, + /* U+0D47+0D3E -> U+0D4B */ 812, + /* U+0DD9+0DCA -> U+0DDA */ 816, + /* U+0DD9+0DCF -> U+0DDC */ 817, + /* U+0DD9+0DDF -> U+0DDE */ 819, + /* U+0DDC+0DCA -> U+0DDD */ 818, + /* U+1025+102E -> U+1026 */ 877, + /* U+1B05+1B35 -> U+1B06 */ 937, + /* U+1B07+1B35 -> U+1B08 */ 938, + /* U+1B09+1B35 -> U+1B0A */ 939, + /* U+1B0B+1B35 -> U+1B0C */ 940, + /* U+1B0D+1B35 -> U+1B0E */ 941, + /* U+1B11+1B35 -> U+1B12 */ 942, + /* U+1B3A+1B35 -> U+1B3B */ 944, + /* U+1B3C+1B35 -> U+1B3D */ 945, + /* U+1B3E+1B35 -> U+1B40 */ 946, + /* U+1B3F+1B35 -> U+1B41 */ 947, + /* U+1B42+1B35 -> U+1B43 */ 948, + /* U+1E36+0304 -> U+1E38 */ 1210, + /* U+1E37+0304 -> U+1E39 */ 1211, + /* U+1E5A+0304 -> U+1E5C */ 1246, + /* U+1E5B+0304 -> U+1E5D */ 1247, + /* U+1E62+0307 -> U+1E68 */ 1258, + /* U+1E63+0307 -> U+1E69 */ 1259, + /* U+1EA0+0302 -> U+1EAC */ 1322, + /* U+1EA0+0306 -> U+1EB6 */ 1332, + /* U+1EA1+0302 -> U+1EAD */ 1323, + /* U+1EA1+0306 -> U+1EB7 */ 1333, + /* U+1EB8+0302 -> U+1EC6 */ 1348, + /* U+1EB9+0302 -> U+1EC7 */ 1349, + /* U+1ECC+0302 -> U+1ED8 */ 1366, + /* U+1ECD+0302 -> U+1ED9 */ 1367, + /* U+1F00+0300 -> U+1F02 */ 1402, + /* U+1F00+0301 -> U+1F04 */ 1404, + /* U+1F00+0342 -> U+1F06 */ 1406, + /* U+1F00+0345 -> U+1F80 */ 1514, + /* U+1F01+0300 -> U+1F03 */ 1403, + /* U+1F01+0301 -> U+1F05 */ 1405, + /* U+1F01+0342 -> U+1F07 */ 1407, + /* U+1F01+0345 -> U+1F81 */ 1515, + /* U+1F02+0345 -> U+1F82 */ 1516, + /* U+1F03+0345 -> U+1F83 */ 1517, + /* U+1F04+0345 -> U+1F84 */ 1518, + /* U+1F05+0345 -> U+1F85 */ 1519, + /* U+1F06+0345 -> U+1F86 */ 1520, + /* U+1F07+0345 -> U+1F87 */ 1521, + /* U+1F08+0300 -> U+1F0A */ 1410, + /* U+1F08+0301 -> U+1F0C */ 1412, + /* U+1F08+0342 -> U+1F0E */ 1414, + /* U+1F08+0345 -> U+1F88 */ 1522, + /* U+1F09+0300 -> U+1F0B */ 1411, + /* U+1F09+0301 -> U+1F0D */ 1413, + /* U+1F09+0342 -> U+1F0F */ 1415, + /* U+1F09+0345 -> U+1F89 */ 1523, + /* U+1F0A+0345 -> U+1F8A */ 1524, + /* U+1F0B+0345 -> U+1F8B */ 1525, + /* U+1F0C+0345 -> U+1F8C */ 1526, + /* U+1F0D+0345 -> U+1F8D */ 1527, + /* U+1F0E+0345 -> U+1F8E */ 1528, + /* U+1F0F+0345 -> U+1F8F */ 1529, + /* U+1F10+0300 -> U+1F12 */ 1418, + /* U+1F10+0301 -> U+1F14 */ 1420, + /* U+1F11+0300 -> U+1F13 */ 1419, + /* U+1F11+0301 -> U+1F15 */ 1421, + /* U+1F18+0300 -> U+1F1A */ 1424, + /* U+1F18+0301 -> U+1F1C */ 1426, + /* U+1F19+0300 -> U+1F1B */ 1425, + /* U+1F19+0301 -> U+1F1D */ 1427, + /* U+1F20+0300 -> U+1F22 */ 1430, + /* U+1F20+0301 -> U+1F24 */ 1432, + /* U+1F20+0342 -> U+1F26 */ 1434, + /* U+1F20+0345 -> U+1F90 */ 1530, + /* U+1F21+0300 -> U+1F23 */ 1431, + /* U+1F21+0301 -> U+1F25 */ 1433, + /* U+1F21+0342 -> U+1F27 */ 1435, + /* U+1F21+0345 -> U+1F91 */ 1531, + /* U+1F22+0345 -> U+1F92 */ 1532, + /* U+1F23+0345 -> U+1F93 */ 1533, + /* U+1F24+0345 -> U+1F94 */ 1534, + /* U+1F25+0345 -> U+1F95 */ 1535, + /* U+1F26+0345 -> U+1F96 */ 1536, + /* U+1F27+0345 -> U+1F97 */ 1537, + /* U+1F28+0300 -> U+1F2A */ 1438, + /* U+1F28+0301 -> U+1F2C */ 1440, + /* U+1F28+0342 -> U+1F2E */ 1442, + /* U+1F28+0345 -> U+1F98 */ 1538, + /* U+1F29+0300 -> U+1F2B */ 1439, + /* U+1F29+0301 -> U+1F2D */ 1441, + /* U+1F29+0342 -> U+1F2F */ 1443, + /* U+1F29+0345 -> U+1F99 */ 1539, + /* U+1F2A+0345 -> U+1F9A */ 1540, + /* U+1F2B+0345 -> U+1F9B */ 1541, + /* U+1F2C+0345 -> U+1F9C */ 1542, + /* U+1F2D+0345 -> U+1F9D */ 1543, + /* U+1F2E+0345 -> U+1F9E */ 1544, + /* U+1F2F+0345 -> U+1F9F */ 1545, + /* U+1F30+0300 -> U+1F32 */ 1446, + /* U+1F30+0301 -> U+1F34 */ 1448, + /* U+1F30+0342 -> U+1F36 */ 1450, + /* U+1F31+0300 -> U+1F33 */ 1447, + /* U+1F31+0301 -> U+1F35 */ 1449, + /* U+1F31+0342 -> U+1F37 */ 1451, + /* U+1F38+0300 -> U+1F3A */ 1454, + /* U+1F38+0301 -> U+1F3C */ 1456, + /* U+1F38+0342 -> U+1F3E */ 1458, + /* U+1F39+0300 -> U+1F3B */ 1455, + /* U+1F39+0301 -> U+1F3D */ 1457, + /* U+1F39+0342 -> U+1F3F */ 1459, + /* U+1F40+0300 -> U+1F42 */ 1462, + /* U+1F40+0301 -> U+1F44 */ 1464, + /* U+1F41+0300 -> U+1F43 */ 1463, + /* U+1F41+0301 -> U+1F45 */ 1465, + /* U+1F48+0300 -> U+1F4A */ 1468, + /* U+1F48+0301 -> U+1F4C */ 1470, + /* U+1F49+0300 -> U+1F4B */ 1469, + /* U+1F49+0301 -> U+1F4D */ 1471, + /* U+1F50+0300 -> U+1F52 */ 1474, + /* U+1F50+0301 -> U+1F54 */ 1476, + /* U+1F50+0342 -> U+1F56 */ 1478, + /* U+1F51+0300 -> U+1F53 */ 1475, + /* U+1F51+0301 -> U+1F55 */ 1477, + /* U+1F51+0342 -> U+1F57 */ 1479, + /* U+1F59+0300 -> U+1F5B */ 1481, + /* U+1F59+0301 -> U+1F5D */ 1482, + /* U+1F59+0342 -> U+1F5F */ 1483, + /* U+1F60+0300 -> U+1F62 */ 1486, + /* U+1F60+0301 -> U+1F64 */ 1488, + /* U+1F60+0342 -> U+1F66 */ 1490, + /* U+1F60+0345 -> U+1FA0 */ 1546, + /* U+1F61+0300 -> U+1F63 */ 1487, + /* U+1F61+0301 -> U+1F65 */ 1489, + /* U+1F61+0342 -> U+1F67 */ 1491, + /* U+1F61+0345 -> U+1FA1 */ 1547, + /* U+1F62+0345 -> U+1FA2 */ 1548, + /* U+1F63+0345 -> U+1FA3 */ 1549, + /* U+1F64+0345 -> U+1FA4 */ 1550, + /* U+1F65+0345 -> U+1FA5 */ 1551, + /* U+1F66+0345 -> U+1FA6 */ 1552, + /* U+1F67+0345 -> U+1FA7 */ 1553, + /* U+1F68+0300 -> U+1F6A */ 1494, + /* U+1F68+0301 -> U+1F6C */ 1496, + /* U+1F68+0342 -> U+1F6E */ 1498, + /* U+1F68+0345 -> U+1FA8 */ 1554, + /* U+1F69+0300 -> U+1F6B */ 1495, + /* U+1F69+0301 -> U+1F6D */ 1497, + /* U+1F69+0342 -> U+1F6F */ 1499, + /* U+1F69+0345 -> U+1FA9 */ 1555, + /* U+1F6A+0345 -> U+1FAA */ 1556, + /* U+1F6B+0345 -> U+1FAB */ 1557, + /* U+1F6C+0345 -> U+1FAC */ 1558, + /* U+1F6D+0345 -> U+1FAD */ 1559, + /* U+1F6E+0345 -> U+1FAE */ 1560, + /* U+1F6F+0345 -> U+1FAF */ 1561, + /* U+1F70+0345 -> U+1FB2 */ 1564, + /* U+1F74+0345 -> U+1FC2 */ 1579, + /* U+1F7C+0345 -> U+1FF2 */ 1621, + /* U+1FB6+0345 -> U+1FB7 */ 1568, + /* U+1FBF+0300 -> U+1FCD */ 1589, + /* U+1FBF+0301 -> U+1FCE */ 1590, + /* U+1FBF+0342 -> U+1FCF */ 1591, + /* U+1FC6+0345 -> U+1FC7 */ 1583, + /* U+1FF6+0345 -> U+1FF7 */ 1625, + /* U+1FFE+0300 -> U+1FDD */ 1602, + /* U+1FFE+0301 -> U+1FDE */ 1603, + /* U+1FFE+0342 -> U+1FDF */ 1604, + /* U+2190+0338 -> U+219A */ 1835, + /* U+2192+0338 -> U+219B */ 1836, + /* U+2194+0338 -> U+21AE */ 1837, + /* U+21D0+0338 -> U+21CD */ 1838, + /* U+21D2+0338 -> U+21CF */ 1840, + /* U+21D4+0338 -> U+21CE */ 1839, + /* U+2203+0338 -> U+2204 */ 1841, + /* U+2208+0338 -> U+2209 */ 1842, + /* U+220B+0338 -> U+220C */ 1843, + /* U+2223+0338 -> U+2224 */ 1844, + /* U+2225+0338 -> U+2226 */ 1845, + /* U+223C+0338 -> U+2241 */ 1850, + /* U+2243+0338 -> U+2244 */ 1851, + /* U+2245+0338 -> U+2247 */ 1852, + /* U+2248+0338 -> U+2249 */ 1853, + /* U+224D+0338 -> U+226D */ 1856, + /* U+2261+0338 -> U+2262 */ 1855, + /* U+2264+0338 -> U+2270 */ 1859, + /* U+2265+0338 -> U+2271 */ 1860, + /* U+2272+0338 -> U+2274 */ 1861, + /* U+2273+0338 -> U+2275 */ 1862, + /* U+2276+0338 -> U+2278 */ 1863, + /* U+2277+0338 -> U+2279 */ 1864, + /* U+227A+0338 -> U+2280 */ 1865, + /* U+227B+0338 -> U+2281 */ 1866, + /* U+227C+0338 -> U+22E0 */ 1875, + /* U+227D+0338 -> U+22E1 */ 1876, + /* U+2282+0338 -> U+2284 */ 1867, + /* U+2283+0338 -> U+2285 */ 1868, + /* U+2286+0338 -> U+2288 */ 1869, + /* U+2287+0338 -> U+2289 */ 1870, + /* U+2291+0338 -> U+22E2 */ 1877, + /* U+2292+0338 -> U+22E3 */ 1878, + /* U+22A2+0338 -> U+22AC */ 1871, + /* U+22A8+0338 -> U+22AD */ 1872, + /* U+22A9+0338 -> U+22AE */ 1873, + /* U+22AB+0338 -> U+22AF */ 1874, + /* U+22B2+0338 -> U+22EA */ 1879, + /* U+22B3+0338 -> U+22EB */ 1880, + /* U+22B4+0338 -> U+22EC */ 1881, + /* U+22B5+0338 -> U+22ED */ 1882, + /* U+3046+3099 -> U+3094 */ 2320, + /* U+304B+3099 -> U+304C */ 2295, + /* U+304D+3099 -> U+304E */ 2296, + /* U+304F+3099 -> U+3050 */ 2297, + /* U+3051+3099 -> U+3052 */ 2298, + /* U+3053+3099 -> U+3054 */ 2299, + /* U+3055+3099 -> U+3056 */ 2300, + /* U+3057+3099 -> U+3058 */ 2301, + /* U+3059+3099 -> U+305A */ 2302, + /* U+305B+3099 -> U+305C */ 2303, + /* U+305D+3099 -> U+305E */ 2304, + /* U+305F+3099 -> U+3060 */ 2305, + /* U+3061+3099 -> U+3062 */ 2306, + /* U+3064+3099 -> U+3065 */ 2307, + /* U+3066+3099 -> U+3067 */ 2308, + /* U+3068+3099 -> U+3069 */ 2309, + /* U+306F+3099 -> U+3070 */ 2310, + /* U+306F+309A -> U+3071 */ 2311, + /* U+3072+3099 -> U+3073 */ 2312, + /* U+3072+309A -> U+3074 */ 2313, + /* U+3075+3099 -> U+3076 */ 2314, + /* U+3075+309A -> U+3077 */ 2315, + /* U+3078+3099 -> U+3079 */ 2316, + /* U+3078+309A -> U+307A */ 2317, + /* U+307B+3099 -> U+307C */ 2318, + /* U+307B+309A -> U+307D */ 2319, + /* U+309D+3099 -> U+309E */ 2325, + /* U+30A6+3099 -> U+30F4 */ 2352, + /* U+30AB+3099 -> U+30AC */ 2327, + /* U+30AD+3099 -> U+30AE */ 2328, + /* U+30AF+3099 -> U+30B0 */ 2329, + /* U+30B1+3099 -> U+30B2 */ 2330, + /* U+30B3+3099 -> U+30B4 */ 2331, + /* U+30B5+3099 -> U+30B6 */ 2332, + /* U+30B7+3099 -> U+30B8 */ 2333, + /* U+30B9+3099 -> U+30BA */ 2334, + /* U+30BB+3099 -> U+30BC */ 2335, + /* U+30BD+3099 -> U+30BE */ 2336, + /* U+30BF+3099 -> U+30C0 */ 2337, + /* U+30C1+3099 -> U+30C2 */ 2338, + /* U+30C4+3099 -> U+30C5 */ 2339, + /* U+30C6+3099 -> U+30C7 */ 2340, + /* U+30C8+3099 -> U+30C9 */ 2341, + /* U+30CF+3099 -> U+30D0 */ 2342, + /* U+30CF+309A -> U+30D1 */ 2343, + /* U+30D2+3099 -> U+30D3 */ 2344, + /* U+30D2+309A -> U+30D4 */ 2345, + /* U+30D5+3099 -> U+30D6 */ 2346, + /* U+30D5+309A -> U+30D7 */ 2347, + /* U+30D8+3099 -> U+30D9 */ 2348, + /* U+30D8+309A -> U+30DA */ 2349, + /* U+30DB+3099 -> U+30DC */ 2350, + /* U+30DB+309A -> U+30DD */ 2351, + /* U+30EF+3099 -> U+30F7 */ 2353, + /* U+30F0+3099 -> U+30F8 */ 2354, + /* U+30F1+3099 -> U+30F9 */ 2355, + /* U+30F2+3099 -> U+30FA */ 2356, + /* U+30FD+3099 -> U+30FE */ 2357, + /* U+11099+110BA -> U+1109A */ 4686, + /* U+1109B+110BA -> U+1109C */ 4687, + /* U+110A5+110BA -> U+110AB */ 4688, + /* U+11131+11127 -> U+1112E */ 4694, + /* U+11132+11127 -> U+1112F */ 4695, + /* U+11347+1133E -> U+1134B */ 4707, + /* U+11347+11357 -> U+1134C */ 4708, + /* U+114B9+114B0 -> U+114BC */ 4726, + /* U+114B9+114BA -> U+114BB */ 4725, + /* U+114B9+114BD -> U+114BE */ 4727, + /* U+115B8+115AF -> U+115BA */ 4730, + /* U+115B9+115AF -> U+115BB */ 4731, + /* U+11935+11930 -> U+11938 */ 4740 +}; + +/* Perfect hash function for recomposition */ +static int +Recomp_hash_func(const void *key) +{ + static const int16 h[1883] = { + 772, 773, 621, 32767, 32767, 387, 653, 196, + 32767, 32767, 855, 463, -19, 651, 32767, 32767, + 32767, 364, 32767, 32767, -108, 32767, 32767, 32767, + 32767, 0, -568, 32767, 32767, 32767, 0, 0, + 0, -103, 364, 0, 210, 732, 0, 0, + -506, 0, 0, 0, 32767, 32767, 0, 32767, + 407, -140, 32767, 409, 32767, 772, 0, 86, + 842, 934, 32767, 32767, -499, -355, 32767, 32767, + 532, 138, 174, -243, 860, 1870, 742, 32767, + 32767, 339, 32767, 1290, 0, 32767, 32767, 0, + -449, -1386, 1633, 560, 561, 32767, 1219, 1004, + 139, -804, 32767, -179, 141, 579, 1586, 32767, + 32767, 32767, 142, 199, 32767, 32767, 143, 0, + 32767, 32767, 314, 896, 32767, 32767, 428, 129, + 286, -58, 0, 68, 32767, 0, 244, -566, + 32767, 32767, 32767, 246, 32767, 32767, 0, 32767, + 32767, 271, -108, 928, 32767, 715, 32767, 32767, + -211, -497, 32767, 0, 1055, 1339, 32767, 0, + 32767, 32767, -968, -144, 32767, 32767, 248, 32767, + -161, 32767, 32767, 282, 32767, -372, 0, 2, + -137, 1116, 32767, 687, 32767, 459, 913, 0, + 461, 879, -816, 443, 32767, 32767, 462, 1089, + 32767, 1054, 0, 314, 447, -26, 480, 32767, + 64, 0, 0, 112, 32767, 66, 0, 646, + 603, 22, -292, 0, 710, 475, 32767, 24, + -781, 32767, 32767, 32767, 281, 307, 32767, 1289, + 32767, 0, 1064, -149, 454, 118, 32767, 32767, + 0, 32767, -126, 0, 32767, 32767, 858, 32767, + 32767, 32767, 1029, 886, 665, 209, 0, 26, + 359, 0, 0, -108, -508, -603, 894, 906, + 32767, 32767, 14, 0, 0, 534, 984, 876, + 32767, -93, 110, -367, 167, 843, 32767, 32767, + -947, -290, 169, 0, 0, 32767, -42, 564, + 0, -927, 32767, 817, 32767, 32767, 32767, 110, + 0, 32767, 32767, -38, 32767, 32767, -101, 694, + -142, 190, 191, 1288, 32767, -687, 194, -579, + 534, -452, 0, -72, 536, 765, 823, 266, + -259, 684, 767, 32767, 654, 32767, 32767, 64, + 920, 32767, 32767, 32767, 0, 1653, 0, 0, + 32767, 32767, -452, -222, 855, 0, 32767, -1153, + 127, 490, 449, 863, 32767, -144, 32767, -379, + 545, 32767, 32767, 32767, 530, 32767, 32767, 1331, + 611, -612, 332, 545, -73, 0, 604, 201, + 32767, -279, 338, 836, 340, 408, 32767, -60, + -358, 32767, 343, 69, 707, 0, -129, 582, + 32767, 0, 32767, 96, 392, 490, 639, 157, + -4, 406, 32767, 32767, -571, 1077, 546, 32767, + 551, 0, 0, 0, 32767, 32767, 348, 32767, + 498, -181, 0, -433, 1057, 260, 0, 32767, + 32767, 397, 32767, 816, -130, 32767, 624, 0, + 0, 32767, 32767, 32767, 485, 0, 32767, 32767, + 32767, 32767, 32767, 0, 32767, 32767, 32767, 1222, + -230, 32767, 797, -538, 32767, 974, 32767, 32767, + 831, 70, -658, 145, 0, 147, 0, 32767, + 1295, 32767, 0, 0, 895, 0, 0, -385, + 491, -287, 32767, -587, 32767, 32767, 32767, 813, + -471, -13, 32767, 32767, 32767, 0, 203, 411, + 470, 0, -546, -179, 146, 0, 0, 32767, + -468, 32767, 0, 0, 32767, 32767, 32767, 211, + 32767, 32767, 0, 32767, 0, 52, 32767, 0, + 32767, 0, 692, 990, 32767, 32767, 32767, 56, + -507, 784, 951, 0, 32767, 0, 697, 32767, + 187, 0, 32767, 32767, 430, 1209, 682, 32767, + 130, 0, -25, 0, -1006, 0, 32767, 214, + 433, 22, 0, -1119, 32767, 285, 32767, 32767, + 32767, 216, 32767, 32767, 32767, 217, 527, 32767, + 32767, 32767, 829, 485, 419, 717, 620, 731, + 32767, 470, 0, -145, -620, 1162, -644, 848, + 287, -632, 32767, 32767, 32767, 32767, 381, 32767, + 510, 511, -554, -2, 32767, 0, 0, 698, + 32767, 32767, 436, 1154, 32767, 463, 32767, 32767, + 627, 517, 32767, 32767, 854, 579, 723, 396, + 110, -42, 354, 32767, 664, 32767, 32767, 0, + 0, 32767, 65, -163, 67, 140, 69, 341, + 70, 71, 402, 73, 623, 544, 624, 417, + -1375, 648, 32767, -26, 904, 0, 548, 0, + 0, 32767, 32767, 855, 32767, 488, -524, 599, + 130, 131, 32767, 32767, 542, -1110, -324, -462, + 32767, -405, -440, 0, 0, 629, 850, 0, + 741, 257, 258, 32767, 32767, 0, 32767, 923, + 0, 32767, 0, 32767, 1559, 32767, 32767, 32767, + 671, 32767, 134, 32767, 32767, -336, -104, 576, + 577, 829, 32767, 32767, 762, 902, 32767, 0, + 32767, 0, 1506, 887, 32767, 636, 601, 2465, + 426, 0, 236, 317, 427, 968, 32767, -975, + -559, -343, 341, 32767, 937, 241, 0, 32767, + 32767, 547, 32767, 32767, 32767, 32767, 32767, 789, + 0, 32767, 32767, 32767, 0, 0, 0, 32767, + -192, 859, 1185, 1153, 69, 32767, 32767, 32767, + -539, 32767, 32767, 0, 32767, 32767, 32767, 32767, + 640, 578, 32767, 32767, -766, 32767, 32767, 32767, + 32767, 1050, -572, 32767, 32767, 32767, 32767, 1268, + 32767, 32767, 32767, 754, 32767, 32767, 1640, 179, + 804, 32767, 32767, 32767, 32767, 0, 684, 943, + 1006, 32767, 32767, 652, 0, 32767, 1041, 32767, + 718, 791, 32767, 274, 697, 32767, 32767, 0, + 32767, 32767, 32767, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 735, + 0, 32767, 32767, 32767, 275, 358, 688, 32767, + 32767, 32767, 548, -87, 770, 32767, -42, 0, + 551, 32767, 691, 222, 32767, 32767, 32767, 32767, + 0, 1273, 403, -121, 806, 553, 554, 163, + 32767, 32767, 892, 825, 32767, 32767, -490, 32767, + 32767, 32767, 32767, 32767, -109, 744, 910, 32767, + 91, 32767, 32767, 0, 0, 32767, 32767, 32767, + 1521, 50, 701, 32767, 32767, 32767, 32767, 164, + 658, 32767, 288, 0, 32767, 0, 51, 0, + 32767, 32767, 32767, 32767, 555, 1547, 32767, 32767, + 595, 585, 429, 32767, -80, 32767, 1258, 0, + 540, 486, -434, 865, 0, 192, 0, 884, + 0, 0, 0, 175, 555, 0, 32767, 32767, + 0, 32767, -566, 866, 591, 32767, 32767, 32767, + 32767, 32767, 496, 495, -215, 32767, 849, -772, + 32767, 32767, 502, 178, 483, 32767, 912, 793, + 794, 0, 32767, 32767, 32767, -556, 499, 838, + 32767, 32767, -506, 331, 0, 0, -1096, 512, + 880, 0, 774, -338, 649, 32767, 270, 32767, + 32767, -624, 328, 459, 32767, 32767, 32767, 32767, + 329, -201, -835, 813, -879, 560, 0, -212, + -114, 35, -494, 37, 523, 653, 751, -653, + -743, 32767, 1356, 818, 32767, 32767, 856, 0, + 44, 902, 0, 0, 0, 0, 32767, -26, + 526, 795, 456, 32767, 104, -209, -341, 133, + -372, 0, 45, 110, 111, 0, 511, 47, + 114, 32767, 32767, 93, 48, 116, -1031, -279, + 32767, 192, 0, 32767, 453, 415, 0, -190, + 32767, 471, 240, 175, 29, 665, 684, 0, + -11, -95, -344, 32767, 245, 148, 0, 530, + 0, 1185, -615, -712, 693, 784, 32767, 0, + -776, 32767, 32767, -813, 0, 0, 0, 207, + 208, 32767, 674, 32767, 742, -289, 249, 32767, + 520, 929, -50, 781, 0, -778, 32767, 0, + 302, 32767, 720, -465, 0, 32767, 32767, 32767, + 0, 0, 32767, 833, 328, 806, 32767, -403, + 0, 32767, -77, 32767, 0, 441, 930, 32767, + 643, 0, 32767, 1938, 0, 1334, 381, 32767, + 216, 32767, 32767, 0, 32767, 484, 383, 0, + 242, 395, 0, 32767, 32767, 32767, -781, 355, + 356, 32767, 292, 706, 32767, 32767, 32767, 32767, + 32767, -410, 32767, 32767, 782, 32767, 189, 32767, + 32767, 943, 0, -212, 407, 335, 0, 135, + 32767, 616, 0, -497, 0, -67, 853, 32767, + 700, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 459, -48, 32767, 58, 0, + -856, 1017, 32767, 59, 916, -731, 32767, 940, + -855, 347, 650, 0, 678, 32767, 0, 32767, + 32767, 530, 32767, 0, -80, 32767, -730, 32767, + 1214, 799, 58, 651, 841, 0, 0, -589, + -1530, -478, 651, 652, 93, 576, -1215, 32767, + 125, 32767, 1279, 32767, 32767, 0, 32767, 0, + -367, 416, -1236, 32767, 418, 32767, 815, 558, + 559, 781, 419, 32767, 739, 32767, 0, 32767, + 128, 570, 1349, -298, -66, 0, 147, -488, + 32767, 590, 189, 274, 524, 32767, 1082, -209, + 32767, 423, 32767, 32767, 975, 573, 32767, 424, + 32767, 32767, 1241, 32767, 32767, 32767, 32767, 32767, + 612, 391, 32767, 0, -803, 1004, -561, 32767, + 32767, 735, 870, 32767, 0, 32767, 32767, -123, + 99, 210, 600, 1294, 109, 1053, 32767, 307, + 834, 32767, 0, 1651, 32767, 644, 32767, 32767, + 0, 32767, -801, 385, 379, 32767, -368, 32767, + 32767, 830, 0, 32767, 32767, 739, 371, 372, + -275, 32767, 32767, 331, -780, 32767, 0, 1229, + -1462, 913, 266, 827, 125, 32767, 32767, 32767, + 393, 32767, 631, -33, -883, -661, -204, 6, + -19, 257, 8, 9, 118, 519, 615, -541, + -893, 0, 32767, 0, 1156, 15, 900, 32767, + 32767, 32767, 32767, 32767, 32767, 1022, 376, 0, + 32767, 32767, -972, 676, 840, -661, 631, 58, + 0, 17, 32767, 0, -799, 82, 0, 32767, + 32767, 680, 32767, 905, 0, 0, 32767, 32767, + 0, 0, 32767, 0, 828, 386, 802, 0, + 146, 0, 148, 32767, -1146, 0, 150, 151, + -743, 153, 154, 32767, 32767, 442, 32767, 743, + 0, 0, 746, 0, 32767, 32767, 32767, 98, + 32767, 157, 0, 696, 0, 32767, 32767, -294, + 32767, 158, 159, 32767, 0, 32767, 160, 32767, + 933, 32767, 32767, -50, 759, 824, 162, 672, + 32767, 356, 0, 356, 32767, 32767, 0, 0, + 656, 692, 253, 254, -374, 102, 256, 32767, + 0, 0, 32767, 32767, 259, 32767, 63, 260, + 510, 261, 32767, 0, 32767, 1061, 32767, 521, + 32767, 32767, 32767, 32767, 32767, 32767, 316, 317, + 846, 0, 32767, -500, 318, 0, 32767, 32767, + 263, 0, 790, 872, 32767, 32767, 32767, 2171, + 264, 32767, 32767, 32767, 32767, 486, 334, 465, + 32767, 466, 32767, 444, 606, 32767, 0, 445, + 320, -317, 0, 520, 322, 718, 32767, 32767, + 32767, 0, 1013, 32767, 32767, 32767, 32767, 32767, + 32767, 611, 32767, 0, 0, 32767, 32767, -120, + 156, 613, 0, 0, 32767, -68, 32767, 622, + 32767, 32767, 32767, 32767, 32767, 455, 32767, 32767, + 32767, 403, 533, 0, -161, 405, 95, 96, + 32767, 97, 32767, 0, 29, 0, 32767, 32767, + 30, 32767, 99, 32767, 32767, 0, 161, 32767, + 97, 0, 32, 32767, 32767, 0, 0, 315, + 32767, 32767, 414, 966, 0, 585, 32767, 32767, + -616, -256, 171, 172, 666, 101, 562, 563, + 32767, 95, 0, 0, 1492, 390, -251, 103, + 32767, 0, 32767, 188, 1487, 32767, 0, 0, + 586, 668, -126, 0, 0, 32767, 32767, 204, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 656, 32767, 32767, + 599, 0, 222, 32767, 0, 1368, -412, 435, + 32767, 936, 32767, -17, 32767, 832, 32767, 437, + 0, -518, 787, 32767, 864, -449, 0, 636, + 713, 206, 592, 572, 0, 483, -139, 32767, + 32767, 180, 818, 32767, 32767, 1304, 0, 32767, + 274, 0, 0, 0, 0, 705, 32767, 32767, + 32767, 0, -272, 0, 502, 503, 319, 0, + 32767, 0, 13, 32767, 32767, 0, 32767, 270, + 737, 0, 32767, 32767, 32767, 901, 32767, 616, + 180, 32767, 721, 353, 32767, 0, 32767, 32767, + -199, 0, 280, 788, 32767, 940, 32767, 51, + 0, 400, 53, 0, 54, -637, 0, -453, + 0, 0, 0, 380, 0, 32767, 504, 0, + 2049, 0, -964, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 798, 32767, 32767, 32767, 0, + 538, 488, 0, 32767, -528, 57, 819, 32767, + 32767, 1244, 0, 488, 739, 908, 32767, 32767, + 0, 32767, 32767, 0, 55, 533, 0, 32767, + 814, 0, 32767, 458, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 776, 777, 920, 0, + 0, 755, 32767, 0, 32767, 32767, 0, 32767, + 55, -954, 0, 372, 166, 218, 165, 857, + 221, 675, 0, 223, 224, -155, 226, 32767, + 1851, 227, 32767, 32767, 1192, 0, 229, 0, + -72, 0, 865, 0, 0, -330, 0, 683, + 32767, -550, -196, 725, -573, 293, 102, 32767, + -589, 296, 297, 298, 231, -256, 300, 32767, + 32767, 301, 233, 868, 32767, 234, 0, 811, + 1187, 32767, 32767, 0, 32767, 518, 0, 361, + 362, 466, 0, 365, 32767, -179, 366, 367, + 874, 369, 305, 0, 32767, 0, 32767, 0, + 32767, 2000, 1215, 451, 652, 0, 0, 799, + 32767, 32767, 32767 + }; + + const unsigned char *k = (const unsigned char *) key; + size_t keylen = 8; + uint32 a = 0; + uint32 b = 0; + + while (keylen--) + { + unsigned char c = *k++; + + a = a * 257 + c; + b = b * 17 + c; + } + return h[a % 1883] + h[b % 1883]; +} + +/* Hash lookup information for recomposition */ +static const pg_unicode_recompinfo UnicodeRecompInfo = +{ + RecompInverseLookup, + Recomp_hash_func, + 941 +}; diff --git a/src/include/common/unicode_norm_table.h b/src/include/common/unicode_norm_table.h new file mode 100644 index 0000000..c0cf336 --- /dev/null +++ b/src/include/common/unicode_norm_table.h @@ -0,0 +1,9042 @@ +/*------------------------------------------------------------------------- + * + * unicode_norm_table.h + * Composition table used for Unicode normalization + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/unicode_norm_table.h + * + *------------------------------------------------------------------------- + */ + +/* + * File auto-generated by src/common/unicode/generate-unicode_norm_table.pl, + * do not edit. There is deliberately not an #ifndef PG_UNICODE_NORM_TABLE_H + * here. + */ +typedef struct +{ + uint32 codepoint; /* Unicode codepoint */ + uint8 comb_class; /* combining class of character */ + uint8 dec_size_flags; /* size and flags of decomposition code list */ + uint16 dec_index; /* index into UnicodeDecomp_codepoints, or the + * decomposition itself if DECOMP_INLINE */ +} pg_unicode_decomposition; + +#define DECOMP_NO_COMPOSE 0x80 /* don't use for re-composition */ +#define DECOMP_INLINE 0x40 /* decomposition is stored inline in + * dec_index */ +#define DECOMP_COMPAT 0x20 /* compatibility mapping */ + +#define DECOMPOSITION_SIZE(x) ((x)->dec_size_flags & 0x1F) +#define DECOMPOSITION_NO_COMPOSE(x) (((x)->dec_size_flags & (DECOMP_NO_COMPOSE | DECOMP_COMPAT)) != 0) +#define DECOMPOSITION_IS_INLINE(x) (((x)->dec_size_flags & DECOMP_INLINE) != 0) +#define DECOMPOSITION_IS_COMPAT(x) (((x)->dec_size_flags & DECOMP_COMPAT) != 0) + +/* Table of Unicode codepoints and their decompositions */ +static const pg_unicode_decomposition UnicodeDecompMain[6703] = +{ + {0x00A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x00A8, 0, 2 | DECOMP_COMPAT, 0}, + {0x00AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x00AF, 0, 2 | DECOMP_COMPAT, 2}, + {0x00B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x00B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x00B4, 0, 2 | DECOMP_COMPAT, 4}, + {0x00B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x00B8, 0, 2 | DECOMP_COMPAT, 6}, + {0x00B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x00BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x00BC, 0, 3 | DECOMP_COMPAT, 8}, + {0x00BD, 0, 3 | DECOMP_COMPAT, 11}, + {0x00BE, 0, 3 | DECOMP_COMPAT, 14}, + {0x00C0, 0, 2, 17}, + {0x00C1, 0, 2, 19}, + {0x00C2, 0, 2, 21}, + {0x00C3, 0, 2, 23}, + {0x00C4, 0, 2, 25}, + {0x00C5, 0, 2, 27}, + {0x00C7, 0, 2, 29}, + {0x00C8, 0, 2, 31}, + {0x00C9, 0, 2, 33}, + {0x00CA, 0, 2, 35}, + {0x00CB, 0, 2, 37}, + {0x00CC, 0, 2, 39}, + {0x00CD, 0, 2, 41}, + {0x00CE, 0, 2, 43}, + {0x00CF, 0, 2, 45}, + {0x00D1, 0, 2, 47}, + {0x00D2, 0, 2, 49}, + {0x00D3, 0, 2, 51}, + {0x00D4, 0, 2, 53}, + {0x00D5, 0, 2, 55}, + {0x00D6, 0, 2, 57}, + {0x00D9, 0, 2, 59}, + {0x00DA, 0, 2, 61}, + {0x00DB, 0, 2, 63}, + {0x00DC, 0, 2, 65}, + {0x00DD, 0, 2, 67}, + {0x00E0, 0, 2, 69}, + {0x00E1, 0, 2, 71}, + {0x00E2, 0, 2, 73}, + {0x00E3, 0, 2, 75}, + {0x00E4, 0, 2, 77}, + {0x00E5, 0, 2, 79}, + {0x00E7, 0, 2, 81}, + {0x00E8, 0, 2, 83}, + {0x00E9, 0, 2, 85}, + {0x00EA, 0, 2, 87}, + {0x00EB, 0, 2, 89}, + {0x00EC, 0, 2, 91}, + {0x00ED, 0, 2, 93}, + {0x00EE, 0, 2, 95}, + {0x00EF, 0, 2, 97}, + {0x00F1, 0, 2, 99}, + {0x00F2, 0, 2, 101}, + {0x00F3, 0, 2, 103}, + {0x00F4, 0, 2, 105}, + {0x00F5, 0, 2, 107}, + {0x00F6, 0, 2, 109}, + {0x00F9, 0, 2, 111}, + {0x00FA, 0, 2, 113}, + {0x00FB, 0, 2, 115}, + {0x00FC, 0, 2, 117}, + {0x00FD, 0, 2, 119}, + {0x00FF, 0, 2, 121}, + {0x0100, 0, 2, 123}, + {0x0101, 0, 2, 125}, + {0x0102, 0, 2, 127}, + {0x0103, 0, 2, 129}, + {0x0104, 0, 2, 131}, + {0x0105, 0, 2, 133}, + {0x0106, 0, 2, 135}, + {0x0107, 0, 2, 137}, + {0x0108, 0, 2, 139}, + {0x0109, 0, 2, 141}, + {0x010A, 0, 2, 143}, + {0x010B, 0, 2, 145}, + {0x010C, 0, 2, 147}, + {0x010D, 0, 2, 149}, + {0x010E, 0, 2, 151}, + {0x010F, 0, 2, 153}, + {0x0112, 0, 2, 155}, + {0x0113, 0, 2, 157}, + {0x0114, 0, 2, 159}, + {0x0115, 0, 2, 161}, + {0x0116, 0, 2, 163}, + {0x0117, 0, 2, 165}, + {0x0118, 0, 2, 167}, + {0x0119, 0, 2, 169}, + {0x011A, 0, 2, 171}, + {0x011B, 0, 2, 173}, + {0x011C, 0, 2, 175}, + {0x011D, 0, 2, 177}, + {0x011E, 0, 2, 179}, + {0x011F, 0, 2, 181}, + {0x0120, 0, 2, 183}, + {0x0121, 0, 2, 185}, + {0x0122, 0, 2, 187}, + {0x0123, 0, 2, 189}, + {0x0124, 0, 2, 191}, + {0x0125, 0, 2, 193}, + {0x0128, 0, 2, 195}, + {0x0129, 0, 2, 197}, + {0x012A, 0, 2, 199}, + {0x012B, 0, 2, 201}, + {0x012C, 0, 2, 203}, + {0x012D, 0, 2, 205}, + {0x012E, 0, 2, 207}, + {0x012F, 0, 2, 209}, + {0x0130, 0, 2, 211}, + {0x0132, 0, 2 | DECOMP_COMPAT, 213}, + {0x0133, 0, 2 | DECOMP_COMPAT, 215}, + {0x0134, 0, 2, 217}, + {0x0135, 0, 2, 219}, + {0x0136, 0, 2, 221}, + {0x0137, 0, 2, 223}, + {0x0139, 0, 2, 225}, + {0x013A, 0, 2, 227}, + {0x013B, 0, 2, 229}, + {0x013C, 0, 2, 231}, + {0x013D, 0, 2, 233}, + {0x013E, 0, 2, 235}, + {0x013F, 0, 2 | DECOMP_COMPAT, 237}, + {0x0140, 0, 2 | DECOMP_COMPAT, 239}, + {0x0143, 0, 2, 241}, + {0x0144, 0, 2, 243}, + {0x0145, 0, 2, 245}, + {0x0146, 0, 2, 247}, + {0x0147, 0, 2, 249}, + {0x0148, 0, 2, 251}, + {0x0149, 0, 2 | DECOMP_COMPAT, 253}, + {0x014C, 0, 2, 255}, + {0x014D, 0, 2, 257}, + {0x014E, 0, 2, 259}, + {0x014F, 0, 2, 261}, + {0x0150, 0, 2, 263}, + {0x0151, 0, 2, 265}, + {0x0154, 0, 2, 267}, + {0x0155, 0, 2, 269}, + {0x0156, 0, 2, 271}, + {0x0157, 0, 2, 273}, + {0x0158, 0, 2, 275}, + {0x0159, 0, 2, 277}, + {0x015A, 0, 2, 279}, + {0x015B, 0, 2, 281}, + {0x015C, 0, 2, 283}, + {0x015D, 0, 2, 285}, + {0x015E, 0, 2, 287}, + {0x015F, 0, 2, 289}, + {0x0160, 0, 2, 291}, + {0x0161, 0, 2, 293}, + {0x0162, 0, 2, 295}, + {0x0163, 0, 2, 297}, + {0x0164, 0, 2, 299}, + {0x0165, 0, 2, 301}, + {0x0168, 0, 2, 303}, + {0x0169, 0, 2, 305}, + {0x016A, 0, 2, 307}, + {0x016B, 0, 2, 309}, + {0x016C, 0, 2, 311}, + {0x016D, 0, 2, 313}, + {0x016E, 0, 2, 315}, + {0x016F, 0, 2, 317}, + {0x0170, 0, 2, 319}, + {0x0171, 0, 2, 321}, + {0x0172, 0, 2, 323}, + {0x0173, 0, 2, 325}, + {0x0174, 0, 2, 327}, + {0x0175, 0, 2, 329}, + {0x0176, 0, 2, 331}, + {0x0177, 0, 2, 333}, + {0x0178, 0, 2, 335}, + {0x0179, 0, 2, 337}, + {0x017A, 0, 2, 339}, + {0x017B, 0, 2, 341}, + {0x017C, 0, 2, 343}, + {0x017D, 0, 2, 345}, + {0x017E, 0, 2, 347}, + {0x017F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x01A0, 0, 2, 349}, + {0x01A1, 0, 2, 351}, + {0x01AF, 0, 2, 353}, + {0x01B0, 0, 2, 355}, + {0x01C4, 0, 2 | DECOMP_COMPAT, 357}, + {0x01C5, 0, 2 | DECOMP_COMPAT, 359}, + {0x01C6, 0, 2 | DECOMP_COMPAT, 361}, + {0x01C7, 0, 2 | DECOMP_COMPAT, 363}, + {0x01C8, 0, 2 | DECOMP_COMPAT, 365}, + {0x01C9, 0, 2 | DECOMP_COMPAT, 367}, + {0x01CA, 0, 2 | DECOMP_COMPAT, 369}, + {0x01CB, 0, 2 | DECOMP_COMPAT, 371}, + {0x01CC, 0, 2 | DECOMP_COMPAT, 373}, + {0x01CD, 0, 2, 375}, + {0x01CE, 0, 2, 377}, + {0x01CF, 0, 2, 379}, + {0x01D0, 0, 2, 381}, + {0x01D1, 0, 2, 383}, + {0x01D2, 0, 2, 385}, + {0x01D3, 0, 2, 387}, + {0x01D4, 0, 2, 389}, + {0x01D5, 0, 2, 391}, + {0x01D6, 0, 2, 393}, + {0x01D7, 0, 2, 395}, + {0x01D8, 0, 2, 397}, + {0x01D9, 0, 2, 399}, + {0x01DA, 0, 2, 401}, + {0x01DB, 0, 2, 403}, + {0x01DC, 0, 2, 405}, + {0x01DE, 0, 2, 407}, + {0x01DF, 0, 2, 409}, + {0x01E0, 0, 2, 411}, + {0x01E1, 0, 2, 413}, + {0x01E2, 0, 2, 415}, + {0x01E3, 0, 2, 417}, + {0x01E6, 0, 2, 419}, + {0x01E7, 0, 2, 421}, + {0x01E8, 0, 2, 423}, + {0x01E9, 0, 2, 425}, + {0x01EA, 0, 2, 427}, + {0x01EB, 0, 2, 429}, + {0x01EC, 0, 2, 431}, + {0x01ED, 0, 2, 433}, + {0x01EE, 0, 2, 435}, + {0x01EF, 0, 2, 437}, + {0x01F0, 0, 2, 439}, + {0x01F1, 0, 2 | DECOMP_COMPAT, 441}, + {0x01F2, 0, 2 | DECOMP_COMPAT, 443}, + {0x01F3, 0, 2 | DECOMP_COMPAT, 445}, + {0x01F4, 0, 2, 447}, + {0x01F5, 0, 2, 449}, + {0x01F8, 0, 2, 451}, + {0x01F9, 0, 2, 453}, + {0x01FA, 0, 2, 455}, + {0x01FB, 0, 2, 457}, + {0x01FC, 0, 2, 459}, + {0x01FD, 0, 2, 461}, + {0x01FE, 0, 2, 463}, + {0x01FF, 0, 2, 465}, + {0x0200, 0, 2, 467}, + {0x0201, 0, 2, 469}, + {0x0202, 0, 2, 471}, + {0x0203, 0, 2, 473}, + {0x0204, 0, 2, 475}, + {0x0205, 0, 2, 477}, + {0x0206, 0, 2, 479}, + {0x0207, 0, 2, 481}, + {0x0208, 0, 2, 483}, + {0x0209, 0, 2, 485}, + {0x020A, 0, 2, 487}, + {0x020B, 0, 2, 489}, + {0x020C, 0, 2, 491}, + {0x020D, 0, 2, 493}, + {0x020E, 0, 2, 495}, + {0x020F, 0, 2, 497}, + {0x0210, 0, 2, 499}, + {0x0211, 0, 2, 501}, + {0x0212, 0, 2, 503}, + {0x0213, 0, 2, 505}, + {0x0214, 0, 2, 507}, + {0x0215, 0, 2, 509}, + {0x0216, 0, 2, 511}, + {0x0217, 0, 2, 513}, + {0x0218, 0, 2, 515}, + {0x0219, 0, 2, 517}, + {0x021A, 0, 2, 519}, + {0x021B, 0, 2, 521}, + {0x021E, 0, 2, 523}, + {0x021F, 0, 2, 525}, + {0x0226, 0, 2, 527}, + {0x0227, 0, 2, 529}, + {0x0228, 0, 2, 531}, + {0x0229, 0, 2, 533}, + {0x022A, 0, 2, 535}, + {0x022B, 0, 2, 537}, + {0x022C, 0, 2, 539}, + {0x022D, 0, 2, 541}, + {0x022E, 0, 2, 543}, + {0x022F, 0, 2, 545}, + {0x0230, 0, 2, 547}, + {0x0231, 0, 2, 549}, + {0x0232, 0, 2, 551}, + {0x0233, 0, 2, 553}, + {0x02B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x02B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0266}, + {0x02B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x02B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x02B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0279}, + {0x02B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027B}, + {0x02B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0281}, + {0x02B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x02B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x02D8, 0, 2 | DECOMP_COMPAT, 555}, + {0x02D9, 0, 2 | DECOMP_COMPAT, 557}, + {0x02DA, 0, 2 | DECOMP_COMPAT, 559}, + {0x02DB, 0, 2 | DECOMP_COMPAT, 561}, + {0x02DC, 0, 2 | DECOMP_COMPAT, 563}, + {0x02DD, 0, 2 | DECOMP_COMPAT, 565}, + {0x02E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0263}, + {0x02E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x02E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x02E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x02E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0295}, + {0x0300, 230, 0, 0}, + {0x0301, 230, 0, 0}, + {0x0302, 230, 0, 0}, + {0x0303, 230, 0, 0}, + {0x0304, 230, 0, 0}, + {0x0305, 230, 0, 0}, + {0x0306, 230, 0, 0}, + {0x0307, 230, 0, 0}, + {0x0308, 230, 0, 0}, + {0x0309, 230, 0, 0}, + {0x030A, 230, 0, 0}, + {0x030B, 230, 0, 0}, + {0x030C, 230, 0, 0}, + {0x030D, 230, 0, 0}, + {0x030E, 230, 0, 0}, + {0x030F, 230, 0, 0}, + {0x0310, 230, 0, 0}, + {0x0311, 230, 0, 0}, + {0x0312, 230, 0, 0}, + {0x0313, 230, 0, 0}, + {0x0314, 230, 0, 0}, + {0x0315, 232, 0, 0}, + {0x0316, 220, 0, 0}, + {0x0317, 220, 0, 0}, + {0x0318, 220, 0, 0}, + {0x0319, 220, 0, 0}, + {0x031A, 232, 0, 0}, + {0x031B, 216, 0, 0}, + {0x031C, 220, 0, 0}, + {0x031D, 220, 0, 0}, + {0x031E, 220, 0, 0}, + {0x031F, 220, 0, 0}, + {0x0320, 220, 0, 0}, + {0x0321, 202, 0, 0}, + {0x0322, 202, 0, 0}, + {0x0323, 220, 0, 0}, + {0x0324, 220, 0, 0}, + {0x0325, 220, 0, 0}, + {0x0326, 220, 0, 0}, + {0x0327, 202, 0, 0}, + {0x0328, 202, 0, 0}, + {0x0329, 220, 0, 0}, + {0x032A, 220, 0, 0}, + {0x032B, 220, 0, 0}, + {0x032C, 220, 0, 0}, + {0x032D, 220, 0, 0}, + {0x032E, 220, 0, 0}, + {0x032F, 220, 0, 0}, + {0x0330, 220, 0, 0}, + {0x0331, 220, 0, 0}, + {0x0332, 220, 0, 0}, + {0x0333, 220, 0, 0}, + {0x0334, 1, 0, 0}, + {0x0335, 1, 0, 0}, + {0x0336, 1, 0, 0}, + {0x0337, 1, 0, 0}, + {0x0338, 1, 0, 0}, + {0x0339, 220, 0, 0}, + {0x033A, 220, 0, 0}, + {0x033B, 220, 0, 0}, + {0x033C, 220, 0, 0}, + {0x033D, 230, 0, 0}, + {0x033E, 230, 0, 0}, + {0x033F, 230, 0, 0}, + {0x0340, 230, 1 | DECOMP_INLINE, 0x0300}, + {0x0341, 230, 1 | DECOMP_INLINE, 0x0301}, + {0x0342, 230, 0, 0}, + {0x0343, 230, 1 | DECOMP_INLINE, 0x0313}, + {0x0344, 230, 2 | DECOMP_NO_COMPOSE, 567}, /* non-starter decomposition */ + {0x0345, 240, 0, 0}, + {0x0346, 230, 0, 0}, + {0x0347, 220, 0, 0}, + {0x0348, 220, 0, 0}, + {0x0349, 220, 0, 0}, + {0x034A, 230, 0, 0}, + {0x034B, 230, 0, 0}, + {0x034C, 230, 0, 0}, + {0x034D, 220, 0, 0}, + {0x034E, 220, 0, 0}, + {0x0350, 230, 0, 0}, + {0x0351, 230, 0, 0}, + {0x0352, 230, 0, 0}, + {0x0353, 220, 0, 0}, + {0x0354, 220, 0, 0}, + {0x0355, 220, 0, 0}, + {0x0356, 220, 0, 0}, + {0x0357, 230, 0, 0}, + {0x0358, 232, 0, 0}, + {0x0359, 220, 0, 0}, + {0x035A, 220, 0, 0}, + {0x035B, 230, 0, 0}, + {0x035C, 233, 0, 0}, + {0x035D, 234, 0, 0}, + {0x035E, 234, 0, 0}, + {0x035F, 233, 0, 0}, + {0x0360, 234, 0, 0}, + {0x0361, 234, 0, 0}, + {0x0362, 233, 0, 0}, + {0x0363, 230, 0, 0}, + {0x0364, 230, 0, 0}, + {0x0365, 230, 0, 0}, + {0x0366, 230, 0, 0}, + {0x0367, 230, 0, 0}, + {0x0368, 230, 0, 0}, + {0x0369, 230, 0, 0}, + {0x036A, 230, 0, 0}, + {0x036B, 230, 0, 0}, + {0x036C, 230, 0, 0}, + {0x036D, 230, 0, 0}, + {0x036E, 230, 0, 0}, + {0x036F, 230, 0, 0}, + {0x0374, 0, 1 | DECOMP_INLINE, 0x02B9}, + {0x037A, 0, 2 | DECOMP_COMPAT, 569}, + {0x037E, 0, 1 | DECOMP_INLINE, 0x003B}, + {0x0384, 0, 2 | DECOMP_COMPAT, 571}, + {0x0385, 0, 2, 573}, + {0x0386, 0, 2, 575}, + {0x0387, 0, 1 | DECOMP_INLINE, 0x00B7}, + {0x0388, 0, 2, 577}, + {0x0389, 0, 2, 579}, + {0x038A, 0, 2, 581}, + {0x038C, 0, 2, 583}, + {0x038E, 0, 2, 585}, + {0x038F, 0, 2, 587}, + {0x0390, 0, 2, 589}, + {0x03AA, 0, 2, 591}, + {0x03AB, 0, 2, 593}, + {0x03AC, 0, 2, 595}, + {0x03AD, 0, 2, 597}, + {0x03AE, 0, 2, 599}, + {0x03AF, 0, 2, 601}, + {0x03B0, 0, 2, 603}, + {0x03CA, 0, 2, 605}, + {0x03CB, 0, 2, 607}, + {0x03CC, 0, 2, 609}, + {0x03CD, 0, 2, 611}, + {0x03CE, 0, 2, 613}, + {0x03D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x03D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x03D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x03D3, 0, 2, 615}, + {0x03D4, 0, 2, 617}, + {0x03D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x03D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x03F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x03F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x03F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x03F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x03F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x03F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x0400, 0, 2, 619}, + {0x0401, 0, 2, 621}, + {0x0403, 0, 2, 623}, + {0x0407, 0, 2, 625}, + {0x040C, 0, 2, 627}, + {0x040D, 0, 2, 629}, + {0x040E, 0, 2, 631}, + {0x0419, 0, 2, 633}, + {0x0439, 0, 2, 635}, + {0x0450, 0, 2, 637}, + {0x0451, 0, 2, 639}, + {0x0453, 0, 2, 641}, + {0x0457, 0, 2, 643}, + {0x045C, 0, 2, 645}, + {0x045D, 0, 2, 647}, + {0x045E, 0, 2, 649}, + {0x0476, 0, 2, 651}, + {0x0477, 0, 2, 653}, + {0x0483, 230, 0, 0}, + {0x0484, 230, 0, 0}, + {0x0485, 230, 0, 0}, + {0x0486, 230, 0, 0}, + {0x0487, 230, 0, 0}, + {0x04C1, 0, 2, 655}, + {0x04C2, 0, 2, 657}, + {0x04D0, 0, 2, 659}, + {0x04D1, 0, 2, 661}, + {0x04D2, 0, 2, 663}, + {0x04D3, 0, 2, 665}, + {0x04D6, 0, 2, 667}, + {0x04D7, 0, 2, 669}, + {0x04DA, 0, 2, 671}, + {0x04DB, 0, 2, 673}, + {0x04DC, 0, 2, 675}, + {0x04DD, 0, 2, 677}, + {0x04DE, 0, 2, 679}, + {0x04DF, 0, 2, 681}, + {0x04E2, 0, 2, 683}, + {0x04E3, 0, 2, 685}, + {0x04E4, 0, 2, 687}, + {0x04E5, 0, 2, 689}, + {0x04E6, 0, 2, 691}, + {0x04E7, 0, 2, 693}, + {0x04EA, 0, 2, 695}, + {0x04EB, 0, 2, 697}, + {0x04EC, 0, 2, 699}, + {0x04ED, 0, 2, 701}, + {0x04EE, 0, 2, 703}, + {0x04EF, 0, 2, 705}, + {0x04F0, 0, 2, 707}, + {0x04F1, 0, 2, 709}, + {0x04F2, 0, 2, 711}, + {0x04F3, 0, 2, 713}, + {0x04F4, 0, 2, 715}, + {0x04F5, 0, 2, 717}, + {0x04F8, 0, 2, 719}, + {0x04F9, 0, 2, 721}, + {0x0587, 0, 2 | DECOMP_COMPAT, 723}, + {0x0591, 220, 0, 0}, + {0x0592, 230, 0, 0}, + {0x0593, 230, 0, 0}, + {0x0594, 230, 0, 0}, + {0x0595, 230, 0, 0}, + {0x0596, 220, 0, 0}, + {0x0597, 230, 0, 0}, + {0x0598, 230, 0, 0}, + {0x0599, 230, 0, 0}, + {0x059A, 222, 0, 0}, + {0x059B, 220, 0, 0}, + {0x059C, 230, 0, 0}, + {0x059D, 230, 0, 0}, + {0x059E, 230, 0, 0}, + {0x059F, 230, 0, 0}, + {0x05A0, 230, 0, 0}, + {0x05A1, 230, 0, 0}, + {0x05A2, 220, 0, 0}, + {0x05A3, 220, 0, 0}, + {0x05A4, 220, 0, 0}, + {0x05A5, 220, 0, 0}, + {0x05A6, 220, 0, 0}, + {0x05A7, 220, 0, 0}, + {0x05A8, 230, 0, 0}, + {0x05A9, 230, 0, 0}, + {0x05AA, 220, 0, 0}, + {0x05AB, 230, 0, 0}, + {0x05AC, 230, 0, 0}, + {0x05AD, 222, 0, 0}, + {0x05AE, 228, 0, 0}, + {0x05AF, 230, 0, 0}, + {0x05B0, 10, 0, 0}, + {0x05B1, 11, 0, 0}, + {0x05B2, 12, 0, 0}, + {0x05B3, 13, 0, 0}, + {0x05B4, 14, 0, 0}, + {0x05B5, 15, 0, 0}, + {0x05B6, 16, 0, 0}, + {0x05B7, 17, 0, 0}, + {0x05B8, 18, 0, 0}, + {0x05B9, 19, 0, 0}, + {0x05BA, 19, 0, 0}, + {0x05BB, 20, 0, 0}, + {0x05BC, 21, 0, 0}, + {0x05BD, 22, 0, 0}, + {0x05BF, 23, 0, 0}, + {0x05C1, 24, 0, 0}, + {0x05C2, 25, 0, 0}, + {0x05C4, 230, 0, 0}, + {0x05C5, 220, 0, 0}, + {0x05C7, 18, 0, 0}, + {0x0610, 230, 0, 0}, + {0x0611, 230, 0, 0}, + {0x0612, 230, 0, 0}, + {0x0613, 230, 0, 0}, + {0x0614, 230, 0, 0}, + {0x0615, 230, 0, 0}, + {0x0616, 230, 0, 0}, + {0x0617, 230, 0, 0}, + {0x0618, 30, 0, 0}, + {0x0619, 31, 0, 0}, + {0x061A, 32, 0, 0}, + {0x0622, 0, 2, 725}, + {0x0623, 0, 2, 727}, + {0x0624, 0, 2, 729}, + {0x0625, 0, 2, 731}, + {0x0626, 0, 2, 733}, + {0x064B, 27, 0, 0}, + {0x064C, 28, 0, 0}, + {0x064D, 29, 0, 0}, + {0x064E, 30, 0, 0}, + {0x064F, 31, 0, 0}, + {0x0650, 32, 0, 0}, + {0x0651, 33, 0, 0}, + {0x0652, 34, 0, 0}, + {0x0653, 230, 0, 0}, + {0x0654, 230, 0, 0}, + {0x0655, 220, 0, 0}, + {0x0656, 220, 0, 0}, + {0x0657, 230, 0, 0}, + {0x0658, 230, 0, 0}, + {0x0659, 230, 0, 0}, + {0x065A, 230, 0, 0}, + {0x065B, 230, 0, 0}, + {0x065C, 220, 0, 0}, + {0x065D, 230, 0, 0}, + {0x065E, 230, 0, 0}, + {0x065F, 220, 0, 0}, + {0x0670, 35, 0, 0}, + {0x0675, 0, 2 | DECOMP_COMPAT, 735}, + {0x0676, 0, 2 | DECOMP_COMPAT, 737}, + {0x0677, 0, 2 | DECOMP_COMPAT, 739}, + {0x0678, 0, 2 | DECOMP_COMPAT, 741}, + {0x06C0, 0, 2, 743}, + {0x06C2, 0, 2, 745}, + {0x06D3, 0, 2, 747}, + {0x06D6, 230, 0, 0}, + {0x06D7, 230, 0, 0}, + {0x06D8, 230, 0, 0}, + {0x06D9, 230, 0, 0}, + {0x06DA, 230, 0, 0}, + {0x06DB, 230, 0, 0}, + {0x06DC, 230, 0, 0}, + {0x06DF, 230, 0, 0}, + {0x06E0, 230, 0, 0}, + {0x06E1, 230, 0, 0}, + {0x06E2, 230, 0, 0}, + {0x06E3, 220, 0, 0}, + {0x06E4, 230, 0, 0}, + {0x06E7, 230, 0, 0}, + {0x06E8, 230, 0, 0}, + {0x06EA, 220, 0, 0}, + {0x06EB, 230, 0, 0}, + {0x06EC, 230, 0, 0}, + {0x06ED, 220, 0, 0}, + {0x0711, 36, 0, 0}, + {0x0730, 230, 0, 0}, + {0x0731, 220, 0, 0}, + {0x0732, 230, 0, 0}, + {0x0733, 230, 0, 0}, + {0x0734, 220, 0, 0}, + {0x0735, 230, 0, 0}, + {0x0736, 230, 0, 0}, + {0x0737, 220, 0, 0}, + {0x0738, 220, 0, 0}, + {0x0739, 220, 0, 0}, + {0x073A, 230, 0, 0}, + {0x073B, 220, 0, 0}, + {0x073C, 220, 0, 0}, + {0x073D, 230, 0, 0}, + {0x073E, 220, 0, 0}, + {0x073F, 230, 0, 0}, + {0x0740, 230, 0, 0}, + {0x0741, 230, 0, 0}, + {0x0742, 220, 0, 0}, + {0x0743, 230, 0, 0}, + {0x0744, 220, 0, 0}, + {0x0745, 230, 0, 0}, + {0x0746, 220, 0, 0}, + {0x0747, 230, 0, 0}, + {0x0748, 220, 0, 0}, + {0x0749, 230, 0, 0}, + {0x074A, 230, 0, 0}, + {0x07EB, 230, 0, 0}, + {0x07EC, 230, 0, 0}, + {0x07ED, 230, 0, 0}, + {0x07EE, 230, 0, 0}, + {0x07EF, 230, 0, 0}, + {0x07F0, 230, 0, 0}, + {0x07F1, 230, 0, 0}, + {0x07F2, 220, 0, 0}, + {0x07F3, 230, 0, 0}, + {0x07FD, 220, 0, 0}, + {0x0816, 230, 0, 0}, + {0x0817, 230, 0, 0}, + {0x0818, 230, 0, 0}, + {0x0819, 230, 0, 0}, + {0x081B, 230, 0, 0}, + {0x081C, 230, 0, 0}, + {0x081D, 230, 0, 0}, + {0x081E, 230, 0, 0}, + {0x081F, 230, 0, 0}, + {0x0820, 230, 0, 0}, + {0x0821, 230, 0, 0}, + {0x0822, 230, 0, 0}, + {0x0823, 230, 0, 0}, + {0x0825, 230, 0, 0}, + {0x0826, 230, 0, 0}, + {0x0827, 230, 0, 0}, + {0x0829, 230, 0, 0}, + {0x082A, 230, 0, 0}, + {0x082B, 230, 0, 0}, + {0x082C, 230, 0, 0}, + {0x082D, 230, 0, 0}, + {0x0859, 220, 0, 0}, + {0x085A, 220, 0, 0}, + {0x085B, 220, 0, 0}, + {0x0898, 230, 0, 0}, + {0x0899, 220, 0, 0}, + {0x089A, 220, 0, 0}, + {0x089B, 220, 0, 0}, + {0x089C, 230, 0, 0}, + {0x089D, 230, 0, 0}, + {0x089E, 230, 0, 0}, + {0x089F, 230, 0, 0}, + {0x08CA, 230, 0, 0}, + {0x08CB, 230, 0, 0}, + {0x08CC, 230, 0, 0}, + {0x08CD, 230, 0, 0}, + {0x08CE, 230, 0, 0}, + {0x08CF, 220, 0, 0}, + {0x08D0, 220, 0, 0}, + {0x08D1, 220, 0, 0}, + {0x08D2, 220, 0, 0}, + {0x08D3, 220, 0, 0}, + {0x08D4, 230, 0, 0}, + {0x08D5, 230, 0, 0}, + {0x08D6, 230, 0, 0}, + {0x08D7, 230, 0, 0}, + {0x08D8, 230, 0, 0}, + {0x08D9, 230, 0, 0}, + {0x08DA, 230, 0, 0}, + {0x08DB, 230, 0, 0}, + {0x08DC, 230, 0, 0}, + {0x08DD, 230, 0, 0}, + {0x08DE, 230, 0, 0}, + {0x08DF, 230, 0, 0}, + {0x08E0, 230, 0, 0}, + {0x08E1, 230, 0, 0}, + {0x08E3, 220, 0, 0}, + {0x08E4, 230, 0, 0}, + {0x08E5, 230, 0, 0}, + {0x08E6, 220, 0, 0}, + {0x08E7, 230, 0, 0}, + {0x08E8, 230, 0, 0}, + {0x08E9, 220, 0, 0}, + {0x08EA, 230, 0, 0}, + {0x08EB, 230, 0, 0}, + {0x08EC, 230, 0, 0}, + {0x08ED, 220, 0, 0}, + {0x08EE, 220, 0, 0}, + {0x08EF, 220, 0, 0}, + {0x08F0, 27, 0, 0}, + {0x08F1, 28, 0, 0}, + {0x08F2, 29, 0, 0}, + {0x08F3, 230, 0, 0}, + {0x08F4, 230, 0, 0}, + {0x08F5, 230, 0, 0}, + {0x08F6, 220, 0, 0}, + {0x08F7, 230, 0, 0}, + {0x08F8, 230, 0, 0}, + {0x08F9, 220, 0, 0}, + {0x08FA, 220, 0, 0}, + {0x08FB, 230, 0, 0}, + {0x08FC, 230, 0, 0}, + {0x08FD, 230, 0, 0}, + {0x08FE, 230, 0, 0}, + {0x08FF, 230, 0, 0}, + {0x0929, 0, 2, 749}, + {0x0931, 0, 2, 751}, + {0x0934, 0, 2, 753}, + {0x093C, 7, 0, 0}, + {0x094D, 9, 0, 0}, + {0x0951, 230, 0, 0}, + {0x0952, 220, 0, 0}, + {0x0953, 230, 0, 0}, + {0x0954, 230, 0, 0}, + {0x0958, 0, 2 | DECOMP_NO_COMPOSE, 755}, /* in exclusion list */ + {0x0959, 0, 2 | DECOMP_NO_COMPOSE, 757}, /* in exclusion list */ + {0x095A, 0, 2 | DECOMP_NO_COMPOSE, 759}, /* in exclusion list */ + {0x095B, 0, 2 | DECOMP_NO_COMPOSE, 761}, /* in exclusion list */ + {0x095C, 0, 2 | DECOMP_NO_COMPOSE, 763}, /* in exclusion list */ + {0x095D, 0, 2 | DECOMP_NO_COMPOSE, 765}, /* in exclusion list */ + {0x095E, 0, 2 | DECOMP_NO_COMPOSE, 767}, /* in exclusion list */ + {0x095F, 0, 2 | DECOMP_NO_COMPOSE, 769}, /* in exclusion list */ + {0x09BC, 7, 0, 0}, + {0x09CB, 0, 2, 771}, + {0x09CC, 0, 2, 773}, + {0x09CD, 9, 0, 0}, + {0x09DC, 0, 2 | DECOMP_NO_COMPOSE, 775}, /* in exclusion list */ + {0x09DD, 0, 2 | DECOMP_NO_COMPOSE, 777}, /* in exclusion list */ + {0x09DF, 0, 2 | DECOMP_NO_COMPOSE, 779}, /* in exclusion list */ + {0x09FE, 230, 0, 0}, + {0x0A33, 0, 2 | DECOMP_NO_COMPOSE, 781}, /* in exclusion list */ + {0x0A36, 0, 2 | DECOMP_NO_COMPOSE, 783}, /* in exclusion list */ + {0x0A3C, 7, 0, 0}, + {0x0A4D, 9, 0, 0}, + {0x0A59, 0, 2 | DECOMP_NO_COMPOSE, 785}, /* in exclusion list */ + {0x0A5A, 0, 2 | DECOMP_NO_COMPOSE, 787}, /* in exclusion list */ + {0x0A5B, 0, 2 | DECOMP_NO_COMPOSE, 789}, /* in exclusion list */ + {0x0A5E, 0, 2 | DECOMP_NO_COMPOSE, 791}, /* in exclusion list */ + {0x0ABC, 7, 0, 0}, + {0x0ACD, 9, 0, 0}, + {0x0B3C, 7, 0, 0}, + {0x0B48, 0, 2, 793}, + {0x0B4B, 0, 2, 795}, + {0x0B4C, 0, 2, 797}, + {0x0B4D, 9, 0, 0}, + {0x0B5C, 0, 2 | DECOMP_NO_COMPOSE, 799}, /* in exclusion list */ + {0x0B5D, 0, 2 | DECOMP_NO_COMPOSE, 801}, /* in exclusion list */ + {0x0B94, 0, 2, 803}, + {0x0BCA, 0, 2, 805}, + {0x0BCB, 0, 2, 807}, + {0x0BCC, 0, 2, 809}, + {0x0BCD, 9, 0, 0}, + {0x0C3C, 7, 0, 0}, + {0x0C48, 0, 2, 811}, + {0x0C4D, 9, 0, 0}, + {0x0C55, 84, 0, 0}, + {0x0C56, 91, 0, 0}, + {0x0CBC, 7, 0, 0}, + {0x0CC0, 0, 2, 813}, + {0x0CC7, 0, 2, 815}, + {0x0CC8, 0, 2, 817}, + {0x0CCA, 0, 2, 819}, + {0x0CCB, 0, 2, 821}, + {0x0CCD, 9, 0, 0}, + {0x0D3B, 9, 0, 0}, + {0x0D3C, 9, 0, 0}, + {0x0D4A, 0, 2, 823}, + {0x0D4B, 0, 2, 825}, + {0x0D4C, 0, 2, 827}, + {0x0D4D, 9, 0, 0}, + {0x0DCA, 9, 0, 0}, + {0x0DDA, 0, 2, 829}, + {0x0DDC, 0, 2, 831}, + {0x0DDD, 0, 2, 833}, + {0x0DDE, 0, 2, 835}, + {0x0E33, 0, 2 | DECOMP_COMPAT, 837}, + {0x0E38, 103, 0, 0}, + {0x0E39, 103, 0, 0}, + {0x0E3A, 9, 0, 0}, + {0x0E48, 107, 0, 0}, + {0x0E49, 107, 0, 0}, + {0x0E4A, 107, 0, 0}, + {0x0E4B, 107, 0, 0}, + {0x0EB3, 0, 2 | DECOMP_COMPAT, 839}, + {0x0EB8, 118, 0, 0}, + {0x0EB9, 118, 0, 0}, + {0x0EBA, 9, 0, 0}, + {0x0EC8, 122, 0, 0}, + {0x0EC9, 122, 0, 0}, + {0x0ECA, 122, 0, 0}, + {0x0ECB, 122, 0, 0}, + {0x0EDC, 0, 2 | DECOMP_COMPAT, 841}, + {0x0EDD, 0, 2 | DECOMP_COMPAT, 843}, + {0x0F0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0F0B}, + {0x0F18, 220, 0, 0}, + {0x0F19, 220, 0, 0}, + {0x0F35, 220, 0, 0}, + {0x0F37, 220, 0, 0}, + {0x0F39, 216, 0, 0}, + {0x0F43, 0, 2 | DECOMP_NO_COMPOSE, 845}, /* in exclusion list */ + {0x0F4D, 0, 2 | DECOMP_NO_COMPOSE, 847}, /* in exclusion list */ + {0x0F52, 0, 2 | DECOMP_NO_COMPOSE, 849}, /* in exclusion list */ + {0x0F57, 0, 2 | DECOMP_NO_COMPOSE, 851}, /* in exclusion list */ + {0x0F5C, 0, 2 | DECOMP_NO_COMPOSE, 853}, /* in exclusion list */ + {0x0F69, 0, 2 | DECOMP_NO_COMPOSE, 855}, /* in exclusion list */ + {0x0F71, 129, 0, 0}, + {0x0F72, 130, 0, 0}, + {0x0F73, 0, 2 | DECOMP_NO_COMPOSE, 857}, /* non-starter decomposition */ + {0x0F74, 132, 0, 0}, + {0x0F75, 0, 2 | DECOMP_NO_COMPOSE, 859}, /* non-starter decomposition */ + {0x0F76, 0, 2 | DECOMP_NO_COMPOSE, 861}, /* in exclusion list */ + {0x0F77, 0, 2 | DECOMP_COMPAT, 863}, + {0x0F78, 0, 2 | DECOMP_NO_COMPOSE, 865}, /* in exclusion list */ + {0x0F79, 0, 2 | DECOMP_COMPAT, 867}, + {0x0F7A, 130, 0, 0}, + {0x0F7B, 130, 0, 0}, + {0x0F7C, 130, 0, 0}, + {0x0F7D, 130, 0, 0}, + {0x0F80, 130, 0, 0}, + {0x0F81, 0, 2 | DECOMP_NO_COMPOSE, 869}, /* non-starter decomposition */ + {0x0F82, 230, 0, 0}, + {0x0F83, 230, 0, 0}, + {0x0F84, 9, 0, 0}, + {0x0F86, 230, 0, 0}, + {0x0F87, 230, 0, 0}, + {0x0F93, 0, 2 | DECOMP_NO_COMPOSE, 871}, /* in exclusion list */ + {0x0F9D, 0, 2 | DECOMP_NO_COMPOSE, 873}, /* in exclusion list */ + {0x0FA2, 0, 2 | DECOMP_NO_COMPOSE, 875}, /* in exclusion list */ + {0x0FA7, 0, 2 | DECOMP_NO_COMPOSE, 877}, /* in exclusion list */ + {0x0FAC, 0, 2 | DECOMP_NO_COMPOSE, 879}, /* in exclusion list */ + {0x0FB9, 0, 2 | DECOMP_NO_COMPOSE, 881}, /* in exclusion list */ + {0x0FC6, 220, 0, 0}, + {0x1026, 0, 2, 883}, + {0x1037, 7, 0, 0}, + {0x1039, 9, 0, 0}, + {0x103A, 9, 0, 0}, + {0x108D, 220, 0, 0}, + {0x10FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x10DC}, + {0x135D, 230, 0, 0}, + {0x135E, 230, 0, 0}, + {0x135F, 230, 0, 0}, + {0x1714, 9, 0, 0}, + {0x1715, 9, 0, 0}, + {0x1734, 9, 0, 0}, + {0x17D2, 9, 0, 0}, + {0x17DD, 230, 0, 0}, + {0x18A9, 228, 0, 0}, + {0x1939, 222, 0, 0}, + {0x193A, 230, 0, 0}, + {0x193B, 220, 0, 0}, + {0x1A17, 230, 0, 0}, + {0x1A18, 220, 0, 0}, + {0x1A60, 9, 0, 0}, + {0x1A75, 230, 0, 0}, + {0x1A76, 230, 0, 0}, + {0x1A77, 230, 0, 0}, + {0x1A78, 230, 0, 0}, + {0x1A79, 230, 0, 0}, + {0x1A7A, 230, 0, 0}, + {0x1A7B, 230, 0, 0}, + {0x1A7C, 230, 0, 0}, + {0x1A7F, 220, 0, 0}, + {0x1AB0, 230, 0, 0}, + {0x1AB1, 230, 0, 0}, + {0x1AB2, 230, 0, 0}, + {0x1AB3, 230, 0, 0}, + {0x1AB4, 230, 0, 0}, + {0x1AB5, 220, 0, 0}, + {0x1AB6, 220, 0, 0}, + {0x1AB7, 220, 0, 0}, + {0x1AB8, 220, 0, 0}, + {0x1AB9, 220, 0, 0}, + {0x1ABA, 220, 0, 0}, + {0x1ABB, 230, 0, 0}, + {0x1ABC, 230, 0, 0}, + {0x1ABD, 220, 0, 0}, + {0x1ABF, 220, 0, 0}, + {0x1AC0, 220, 0, 0}, + {0x1AC1, 230, 0, 0}, + {0x1AC2, 230, 0, 0}, + {0x1AC3, 220, 0, 0}, + {0x1AC4, 220, 0, 0}, + {0x1AC5, 230, 0, 0}, + {0x1AC6, 230, 0, 0}, + {0x1AC7, 230, 0, 0}, + {0x1AC8, 230, 0, 0}, + {0x1AC9, 230, 0, 0}, + {0x1ACA, 220, 0, 0}, + {0x1ACB, 230, 0, 0}, + {0x1ACC, 230, 0, 0}, + {0x1ACD, 230, 0, 0}, + {0x1ACE, 230, 0, 0}, + {0x1B06, 0, 2, 885}, + {0x1B08, 0, 2, 887}, + {0x1B0A, 0, 2, 889}, + {0x1B0C, 0, 2, 891}, + {0x1B0E, 0, 2, 893}, + {0x1B12, 0, 2, 895}, + {0x1B34, 7, 0, 0}, + {0x1B3B, 0, 2, 897}, + {0x1B3D, 0, 2, 899}, + {0x1B40, 0, 2, 901}, + {0x1B41, 0, 2, 903}, + {0x1B43, 0, 2, 905}, + {0x1B44, 9, 0, 0}, + {0x1B6B, 230, 0, 0}, + {0x1B6C, 220, 0, 0}, + {0x1B6D, 230, 0, 0}, + {0x1B6E, 230, 0, 0}, + {0x1B6F, 230, 0, 0}, + {0x1B70, 230, 0, 0}, + {0x1B71, 230, 0, 0}, + {0x1B72, 230, 0, 0}, + {0x1B73, 230, 0, 0}, + {0x1BAA, 9, 0, 0}, + {0x1BAB, 9, 0, 0}, + {0x1BE6, 7, 0, 0}, + {0x1BF2, 9, 0, 0}, + {0x1BF3, 9, 0, 0}, + {0x1C37, 7, 0, 0}, + {0x1CD0, 230, 0, 0}, + {0x1CD1, 230, 0, 0}, + {0x1CD2, 230, 0, 0}, + {0x1CD4, 1, 0, 0}, + {0x1CD5, 220, 0, 0}, + {0x1CD6, 220, 0, 0}, + {0x1CD7, 220, 0, 0}, + {0x1CD8, 220, 0, 0}, + {0x1CD9, 220, 0, 0}, + {0x1CDA, 230, 0, 0}, + {0x1CDB, 230, 0, 0}, + {0x1CDC, 220, 0, 0}, + {0x1CDD, 220, 0, 0}, + {0x1CDE, 220, 0, 0}, + {0x1CDF, 220, 0, 0}, + {0x1CE0, 230, 0, 0}, + {0x1CE2, 1, 0, 0}, + {0x1CE3, 1, 0, 0}, + {0x1CE4, 1, 0, 0}, + {0x1CE5, 1, 0, 0}, + {0x1CE6, 1, 0, 0}, + {0x1CE7, 1, 0, 0}, + {0x1CE8, 1, 0, 0}, + {0x1CED, 220, 0, 0}, + {0x1CF4, 230, 0, 0}, + {0x1CF8, 230, 0, 0}, + {0x1CF9, 230, 0, 0}, + {0x1D2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00C6}, + {0x1D2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x018E}, + {0x1D33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0222}, + {0x1D3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0250}, + {0x1D45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0251}, + {0x1D46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D02}, + {0x1D47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0259}, + {0x1D4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025B}, + {0x1D4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025C}, + {0x1D4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x014B}, + {0x1D52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0254}, + {0x1D54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D16}, + {0x1D55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D17}, + {0x1D56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D1D}, + {0x1D5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026F}, + {0x1D5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D25}, + {0x1D5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x043D}, + {0x1D9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0252}, + {0x1D9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0255}, + {0x1D9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00F0}, + {0x1D9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025C}, + {0x1DA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1DA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025F}, + {0x1DA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0261}, + {0x1DA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0265}, + {0x1DA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0268}, + {0x1DA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0269}, + {0x1DA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026A}, + {0x1DA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D7B}, + {0x1DA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029D}, + {0x1DA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026D}, + {0x1DAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D85}, + {0x1DAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029F}, + {0x1DAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0271}, + {0x1DAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0270}, + {0x1DAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0272}, + {0x1DAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0273}, + {0x1DB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0274}, + {0x1DB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0275}, + {0x1DB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0278}, + {0x1DB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0282}, + {0x1DB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0283}, + {0x1DB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01AB}, + {0x1DB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0289}, + {0x1DB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028A}, + {0x1DB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D1C}, + {0x1DB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028B}, + {0x1DBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028C}, + {0x1DBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1DBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0290}, + {0x1DBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0291}, + {0x1DBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0292}, + {0x1DBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1DC0, 230, 0, 0}, + {0x1DC1, 230, 0, 0}, + {0x1DC2, 220, 0, 0}, + {0x1DC3, 230, 0, 0}, + {0x1DC4, 230, 0, 0}, + {0x1DC5, 230, 0, 0}, + {0x1DC6, 230, 0, 0}, + {0x1DC7, 230, 0, 0}, + {0x1DC8, 230, 0, 0}, + {0x1DC9, 230, 0, 0}, + {0x1DCA, 220, 0, 0}, + {0x1DCB, 230, 0, 0}, + {0x1DCC, 230, 0, 0}, + {0x1DCD, 234, 0, 0}, + {0x1DCE, 214, 0, 0}, + {0x1DCF, 220, 0, 0}, + {0x1DD0, 202, 0, 0}, + {0x1DD1, 230, 0, 0}, + {0x1DD2, 230, 0, 0}, + {0x1DD3, 230, 0, 0}, + {0x1DD4, 230, 0, 0}, + {0x1DD5, 230, 0, 0}, + {0x1DD6, 230, 0, 0}, + {0x1DD7, 230, 0, 0}, + {0x1DD8, 230, 0, 0}, + {0x1DD9, 230, 0, 0}, + {0x1DDA, 230, 0, 0}, + {0x1DDB, 230, 0, 0}, + {0x1DDC, 230, 0, 0}, + {0x1DDD, 230, 0, 0}, + {0x1DDE, 230, 0, 0}, + {0x1DDF, 230, 0, 0}, + {0x1DE0, 230, 0, 0}, + {0x1DE1, 230, 0, 0}, + {0x1DE2, 230, 0, 0}, + {0x1DE3, 230, 0, 0}, + {0x1DE4, 230, 0, 0}, + {0x1DE5, 230, 0, 0}, + {0x1DE6, 230, 0, 0}, + {0x1DE7, 230, 0, 0}, + {0x1DE8, 230, 0, 0}, + {0x1DE9, 230, 0, 0}, + {0x1DEA, 230, 0, 0}, + {0x1DEB, 230, 0, 0}, + {0x1DEC, 230, 0, 0}, + {0x1DED, 230, 0, 0}, + {0x1DEE, 230, 0, 0}, + {0x1DEF, 230, 0, 0}, + {0x1DF0, 230, 0, 0}, + {0x1DF1, 230, 0, 0}, + {0x1DF2, 230, 0, 0}, + {0x1DF3, 230, 0, 0}, + {0x1DF4, 230, 0, 0}, + {0x1DF5, 230, 0, 0}, + {0x1DF6, 232, 0, 0}, + {0x1DF7, 228, 0, 0}, + {0x1DF8, 228, 0, 0}, + {0x1DF9, 220, 0, 0}, + {0x1DFA, 218, 0, 0}, + {0x1DFB, 230, 0, 0}, + {0x1DFC, 233, 0, 0}, + {0x1DFD, 220, 0, 0}, + {0x1DFE, 230, 0, 0}, + {0x1DFF, 220, 0, 0}, + {0x1E00, 0, 2, 907}, + {0x1E01, 0, 2, 909}, + {0x1E02, 0, 2, 911}, + {0x1E03, 0, 2, 913}, + {0x1E04, 0, 2, 915}, + {0x1E05, 0, 2, 917}, + {0x1E06, 0, 2, 919}, + {0x1E07, 0, 2, 921}, + {0x1E08, 0, 2, 923}, + {0x1E09, 0, 2, 925}, + {0x1E0A, 0, 2, 927}, + {0x1E0B, 0, 2, 929}, + {0x1E0C, 0, 2, 931}, + {0x1E0D, 0, 2, 933}, + {0x1E0E, 0, 2, 935}, + {0x1E0F, 0, 2, 937}, + {0x1E10, 0, 2, 939}, + {0x1E11, 0, 2, 941}, + {0x1E12, 0, 2, 943}, + {0x1E13, 0, 2, 945}, + {0x1E14, 0, 2, 947}, + {0x1E15, 0, 2, 949}, + {0x1E16, 0, 2, 951}, + {0x1E17, 0, 2, 953}, + {0x1E18, 0, 2, 955}, + {0x1E19, 0, 2, 957}, + {0x1E1A, 0, 2, 959}, + {0x1E1B, 0, 2, 961}, + {0x1E1C, 0, 2, 963}, + {0x1E1D, 0, 2, 965}, + {0x1E1E, 0, 2, 967}, + {0x1E1F, 0, 2, 969}, + {0x1E20, 0, 2, 971}, + {0x1E21, 0, 2, 973}, + {0x1E22, 0, 2, 975}, + {0x1E23, 0, 2, 977}, + {0x1E24, 0, 2, 979}, + {0x1E25, 0, 2, 981}, + {0x1E26, 0, 2, 983}, + {0x1E27, 0, 2, 985}, + {0x1E28, 0, 2, 987}, + {0x1E29, 0, 2, 989}, + {0x1E2A, 0, 2, 991}, + {0x1E2B, 0, 2, 993}, + {0x1E2C, 0, 2, 995}, + {0x1E2D, 0, 2, 997}, + {0x1E2E, 0, 2, 999}, + {0x1E2F, 0, 2, 1001}, + {0x1E30, 0, 2, 1003}, + {0x1E31, 0, 2, 1005}, + {0x1E32, 0, 2, 1007}, + {0x1E33, 0, 2, 1009}, + {0x1E34, 0, 2, 1011}, + {0x1E35, 0, 2, 1013}, + {0x1E36, 0, 2, 1015}, + {0x1E37, 0, 2, 1017}, + {0x1E38, 0, 2, 1019}, + {0x1E39, 0, 2, 1021}, + {0x1E3A, 0, 2, 1023}, + {0x1E3B, 0, 2, 1025}, + {0x1E3C, 0, 2, 1027}, + {0x1E3D, 0, 2, 1029}, + {0x1E3E, 0, 2, 1031}, + {0x1E3F, 0, 2, 1033}, + {0x1E40, 0, 2, 1035}, + {0x1E41, 0, 2, 1037}, + {0x1E42, 0, 2, 1039}, + {0x1E43, 0, 2, 1041}, + {0x1E44, 0, 2, 1043}, + {0x1E45, 0, 2, 1045}, + {0x1E46, 0, 2, 1047}, + {0x1E47, 0, 2, 1049}, + {0x1E48, 0, 2, 1051}, + {0x1E49, 0, 2, 1053}, + {0x1E4A, 0, 2, 1055}, + {0x1E4B, 0, 2, 1057}, + {0x1E4C, 0, 2, 1059}, + {0x1E4D, 0, 2, 1061}, + {0x1E4E, 0, 2, 1063}, + {0x1E4F, 0, 2, 1065}, + {0x1E50, 0, 2, 1067}, + {0x1E51, 0, 2, 1069}, + {0x1E52, 0, 2, 1071}, + {0x1E53, 0, 2, 1073}, + {0x1E54, 0, 2, 1075}, + {0x1E55, 0, 2, 1077}, + {0x1E56, 0, 2, 1079}, + {0x1E57, 0, 2, 1081}, + {0x1E58, 0, 2, 1083}, + {0x1E59, 0, 2, 1085}, + {0x1E5A, 0, 2, 1087}, + {0x1E5B, 0, 2, 1089}, + {0x1E5C, 0, 2, 1091}, + {0x1E5D, 0, 2, 1093}, + {0x1E5E, 0, 2, 1095}, + {0x1E5F, 0, 2, 1097}, + {0x1E60, 0, 2, 1099}, + {0x1E61, 0, 2, 1101}, + {0x1E62, 0, 2, 1103}, + {0x1E63, 0, 2, 1105}, + {0x1E64, 0, 2, 1107}, + {0x1E65, 0, 2, 1109}, + {0x1E66, 0, 2, 1111}, + {0x1E67, 0, 2, 1113}, + {0x1E68, 0, 2, 1115}, + {0x1E69, 0, 2, 1117}, + {0x1E6A, 0, 2, 1119}, + {0x1E6B, 0, 2, 1121}, + {0x1E6C, 0, 2, 1123}, + {0x1E6D, 0, 2, 1125}, + {0x1E6E, 0, 2, 1127}, + {0x1E6F, 0, 2, 1129}, + {0x1E70, 0, 2, 1131}, + {0x1E71, 0, 2, 1133}, + {0x1E72, 0, 2, 1135}, + {0x1E73, 0, 2, 1137}, + {0x1E74, 0, 2, 1139}, + {0x1E75, 0, 2, 1141}, + {0x1E76, 0, 2, 1143}, + {0x1E77, 0, 2, 1145}, + {0x1E78, 0, 2, 1147}, + {0x1E79, 0, 2, 1149}, + {0x1E7A, 0, 2, 1151}, + {0x1E7B, 0, 2, 1153}, + {0x1E7C, 0, 2, 1155}, + {0x1E7D, 0, 2, 1157}, + {0x1E7E, 0, 2, 1159}, + {0x1E7F, 0, 2, 1161}, + {0x1E80, 0, 2, 1163}, + {0x1E81, 0, 2, 1165}, + {0x1E82, 0, 2, 1167}, + {0x1E83, 0, 2, 1169}, + {0x1E84, 0, 2, 1171}, + {0x1E85, 0, 2, 1173}, + {0x1E86, 0, 2, 1175}, + {0x1E87, 0, 2, 1177}, + {0x1E88, 0, 2, 1179}, + {0x1E89, 0, 2, 1181}, + {0x1E8A, 0, 2, 1183}, + {0x1E8B, 0, 2, 1185}, + {0x1E8C, 0, 2, 1187}, + {0x1E8D, 0, 2, 1189}, + {0x1E8E, 0, 2, 1191}, + {0x1E8F, 0, 2, 1193}, + {0x1E90, 0, 2, 1195}, + {0x1E91, 0, 2, 1197}, + {0x1E92, 0, 2, 1199}, + {0x1E93, 0, 2, 1201}, + {0x1E94, 0, 2, 1203}, + {0x1E95, 0, 2, 1205}, + {0x1E96, 0, 2, 1207}, + {0x1E97, 0, 2, 1209}, + {0x1E98, 0, 2, 1211}, + {0x1E99, 0, 2, 1213}, + {0x1E9A, 0, 2 | DECOMP_COMPAT, 1215}, + {0x1E9B, 0, 2, 1217}, + {0x1EA0, 0, 2, 1219}, + {0x1EA1, 0, 2, 1221}, + {0x1EA2, 0, 2, 1223}, + {0x1EA3, 0, 2, 1225}, + {0x1EA4, 0, 2, 1227}, + {0x1EA5, 0, 2, 1229}, + {0x1EA6, 0, 2, 1231}, + {0x1EA7, 0, 2, 1233}, + {0x1EA8, 0, 2, 1235}, + {0x1EA9, 0, 2, 1237}, + {0x1EAA, 0, 2, 1239}, + {0x1EAB, 0, 2, 1241}, + {0x1EAC, 0, 2, 1243}, + {0x1EAD, 0, 2, 1245}, + {0x1EAE, 0, 2, 1247}, + {0x1EAF, 0, 2, 1249}, + {0x1EB0, 0, 2, 1251}, + {0x1EB1, 0, 2, 1253}, + {0x1EB2, 0, 2, 1255}, + {0x1EB3, 0, 2, 1257}, + {0x1EB4, 0, 2, 1259}, + {0x1EB5, 0, 2, 1261}, + {0x1EB6, 0, 2, 1263}, + {0x1EB7, 0, 2, 1265}, + {0x1EB8, 0, 2, 1267}, + {0x1EB9, 0, 2, 1269}, + {0x1EBA, 0, 2, 1271}, + {0x1EBB, 0, 2, 1273}, + {0x1EBC, 0, 2, 1275}, + {0x1EBD, 0, 2, 1277}, + {0x1EBE, 0, 2, 1279}, + {0x1EBF, 0, 2, 1281}, + {0x1EC0, 0, 2, 1283}, + {0x1EC1, 0, 2, 1285}, + {0x1EC2, 0, 2, 1287}, + {0x1EC3, 0, 2, 1289}, + {0x1EC4, 0, 2, 1291}, + {0x1EC5, 0, 2, 1293}, + {0x1EC6, 0, 2, 1295}, + {0x1EC7, 0, 2, 1297}, + {0x1EC8, 0, 2, 1299}, + {0x1EC9, 0, 2, 1301}, + {0x1ECA, 0, 2, 1303}, + {0x1ECB, 0, 2, 1305}, + {0x1ECC, 0, 2, 1307}, + {0x1ECD, 0, 2, 1309}, + {0x1ECE, 0, 2, 1311}, + {0x1ECF, 0, 2, 1313}, + {0x1ED0, 0, 2, 1315}, + {0x1ED1, 0, 2, 1317}, + {0x1ED2, 0, 2, 1319}, + {0x1ED3, 0, 2, 1321}, + {0x1ED4, 0, 2, 1323}, + {0x1ED5, 0, 2, 1325}, + {0x1ED6, 0, 2, 1327}, + {0x1ED7, 0, 2, 1329}, + {0x1ED8, 0, 2, 1331}, + {0x1ED9, 0, 2, 1333}, + {0x1EDA, 0, 2, 1335}, + {0x1EDB, 0, 2, 1337}, + {0x1EDC, 0, 2, 1339}, + {0x1EDD, 0, 2, 1341}, + {0x1EDE, 0, 2, 1343}, + {0x1EDF, 0, 2, 1345}, + {0x1EE0, 0, 2, 1347}, + {0x1EE1, 0, 2, 1349}, + {0x1EE2, 0, 2, 1351}, + {0x1EE3, 0, 2, 1353}, + {0x1EE4, 0, 2, 1355}, + {0x1EE5, 0, 2, 1357}, + {0x1EE6, 0, 2, 1359}, + {0x1EE7, 0, 2, 1361}, + {0x1EE8, 0, 2, 1363}, + {0x1EE9, 0, 2, 1365}, + {0x1EEA, 0, 2, 1367}, + {0x1EEB, 0, 2, 1369}, + {0x1EEC, 0, 2, 1371}, + {0x1EED, 0, 2, 1373}, + {0x1EEE, 0, 2, 1375}, + {0x1EEF, 0, 2, 1377}, + {0x1EF0, 0, 2, 1379}, + {0x1EF1, 0, 2, 1381}, + {0x1EF2, 0, 2, 1383}, + {0x1EF3, 0, 2, 1385}, + {0x1EF4, 0, 2, 1387}, + {0x1EF5, 0, 2, 1389}, + {0x1EF6, 0, 2, 1391}, + {0x1EF7, 0, 2, 1393}, + {0x1EF8, 0, 2, 1395}, + {0x1EF9, 0, 2, 1397}, + {0x1F00, 0, 2, 1399}, + {0x1F01, 0, 2, 1401}, + {0x1F02, 0, 2, 1403}, + {0x1F03, 0, 2, 1405}, + {0x1F04, 0, 2, 1407}, + {0x1F05, 0, 2, 1409}, + {0x1F06, 0, 2, 1411}, + {0x1F07, 0, 2, 1413}, + {0x1F08, 0, 2, 1415}, + {0x1F09, 0, 2, 1417}, + {0x1F0A, 0, 2, 1419}, + {0x1F0B, 0, 2, 1421}, + {0x1F0C, 0, 2, 1423}, + {0x1F0D, 0, 2, 1425}, + {0x1F0E, 0, 2, 1427}, + {0x1F0F, 0, 2, 1429}, + {0x1F10, 0, 2, 1431}, + {0x1F11, 0, 2, 1433}, + {0x1F12, 0, 2, 1435}, + {0x1F13, 0, 2, 1437}, + {0x1F14, 0, 2, 1439}, + {0x1F15, 0, 2, 1441}, + {0x1F18, 0, 2, 1443}, + {0x1F19, 0, 2, 1445}, + {0x1F1A, 0, 2, 1447}, + {0x1F1B, 0, 2, 1449}, + {0x1F1C, 0, 2, 1451}, + {0x1F1D, 0, 2, 1453}, + {0x1F20, 0, 2, 1455}, + {0x1F21, 0, 2, 1457}, + {0x1F22, 0, 2, 1459}, + {0x1F23, 0, 2, 1461}, + {0x1F24, 0, 2, 1463}, + {0x1F25, 0, 2, 1465}, + {0x1F26, 0, 2, 1467}, + {0x1F27, 0, 2, 1469}, + {0x1F28, 0, 2, 1471}, + {0x1F29, 0, 2, 1473}, + {0x1F2A, 0, 2, 1475}, + {0x1F2B, 0, 2, 1477}, + {0x1F2C, 0, 2, 1479}, + {0x1F2D, 0, 2, 1481}, + {0x1F2E, 0, 2, 1483}, + {0x1F2F, 0, 2, 1485}, + {0x1F30, 0, 2, 1487}, + {0x1F31, 0, 2, 1489}, + {0x1F32, 0, 2, 1491}, + {0x1F33, 0, 2, 1493}, + {0x1F34, 0, 2, 1495}, + {0x1F35, 0, 2, 1497}, + {0x1F36, 0, 2, 1499}, + {0x1F37, 0, 2, 1501}, + {0x1F38, 0, 2, 1503}, + {0x1F39, 0, 2, 1505}, + {0x1F3A, 0, 2, 1507}, + {0x1F3B, 0, 2, 1509}, + {0x1F3C, 0, 2, 1511}, + {0x1F3D, 0, 2, 1513}, + {0x1F3E, 0, 2, 1515}, + {0x1F3F, 0, 2, 1517}, + {0x1F40, 0, 2, 1519}, + {0x1F41, 0, 2, 1521}, + {0x1F42, 0, 2, 1523}, + {0x1F43, 0, 2, 1525}, + {0x1F44, 0, 2, 1527}, + {0x1F45, 0, 2, 1529}, + {0x1F48, 0, 2, 1531}, + {0x1F49, 0, 2, 1533}, + {0x1F4A, 0, 2, 1535}, + {0x1F4B, 0, 2, 1537}, + {0x1F4C, 0, 2, 1539}, + {0x1F4D, 0, 2, 1541}, + {0x1F50, 0, 2, 1543}, + {0x1F51, 0, 2, 1545}, + {0x1F52, 0, 2, 1547}, + {0x1F53, 0, 2, 1549}, + {0x1F54, 0, 2, 1551}, + {0x1F55, 0, 2, 1553}, + {0x1F56, 0, 2, 1555}, + {0x1F57, 0, 2, 1557}, + {0x1F59, 0, 2, 1559}, + {0x1F5B, 0, 2, 1561}, + {0x1F5D, 0, 2, 1563}, + {0x1F5F, 0, 2, 1565}, + {0x1F60, 0, 2, 1567}, + {0x1F61, 0, 2, 1569}, + {0x1F62, 0, 2, 1571}, + {0x1F63, 0, 2, 1573}, + {0x1F64, 0, 2, 1575}, + {0x1F65, 0, 2, 1577}, + {0x1F66, 0, 2, 1579}, + {0x1F67, 0, 2, 1581}, + {0x1F68, 0, 2, 1583}, + {0x1F69, 0, 2, 1585}, + {0x1F6A, 0, 2, 1587}, + {0x1F6B, 0, 2, 1589}, + {0x1F6C, 0, 2, 1591}, + {0x1F6D, 0, 2, 1593}, + {0x1F6E, 0, 2, 1595}, + {0x1F6F, 0, 2, 1597}, + {0x1F70, 0, 2, 1599}, + {0x1F71, 0, 1 | DECOMP_INLINE, 0x03AC}, + {0x1F72, 0, 2, 1601}, + {0x1F73, 0, 1 | DECOMP_INLINE, 0x03AD}, + {0x1F74, 0, 2, 1603}, + {0x1F75, 0, 1 | DECOMP_INLINE, 0x03AE}, + {0x1F76, 0, 2, 1605}, + {0x1F77, 0, 1 | DECOMP_INLINE, 0x03AF}, + {0x1F78, 0, 2, 1607}, + {0x1F79, 0, 1 | DECOMP_INLINE, 0x03CC}, + {0x1F7A, 0, 2, 1609}, + {0x1F7B, 0, 1 | DECOMP_INLINE, 0x03CD}, + {0x1F7C, 0, 2, 1611}, + {0x1F7D, 0, 1 | DECOMP_INLINE, 0x03CE}, + {0x1F80, 0, 2, 1613}, + {0x1F81, 0, 2, 1615}, + {0x1F82, 0, 2, 1617}, + {0x1F83, 0, 2, 1619}, + {0x1F84, 0, 2, 1621}, + {0x1F85, 0, 2, 1623}, + {0x1F86, 0, 2, 1625}, + {0x1F87, 0, 2, 1627}, + {0x1F88, 0, 2, 1629}, + {0x1F89, 0, 2, 1631}, + {0x1F8A, 0, 2, 1633}, + {0x1F8B, 0, 2, 1635}, + {0x1F8C, 0, 2, 1637}, + {0x1F8D, 0, 2, 1639}, + {0x1F8E, 0, 2, 1641}, + {0x1F8F, 0, 2, 1643}, + {0x1F90, 0, 2, 1645}, + {0x1F91, 0, 2, 1647}, + {0x1F92, 0, 2, 1649}, + {0x1F93, 0, 2, 1651}, + {0x1F94, 0, 2, 1653}, + {0x1F95, 0, 2, 1655}, + {0x1F96, 0, 2, 1657}, + {0x1F97, 0, 2, 1659}, + {0x1F98, 0, 2, 1661}, + {0x1F99, 0, 2, 1663}, + {0x1F9A, 0, 2, 1665}, + {0x1F9B, 0, 2, 1667}, + {0x1F9C, 0, 2, 1669}, + {0x1F9D, 0, 2, 1671}, + {0x1F9E, 0, 2, 1673}, + {0x1F9F, 0, 2, 1675}, + {0x1FA0, 0, 2, 1677}, + {0x1FA1, 0, 2, 1679}, + {0x1FA2, 0, 2, 1681}, + {0x1FA3, 0, 2, 1683}, + {0x1FA4, 0, 2, 1685}, + {0x1FA5, 0, 2, 1687}, + {0x1FA6, 0, 2, 1689}, + {0x1FA7, 0, 2, 1691}, + {0x1FA8, 0, 2, 1693}, + {0x1FA9, 0, 2, 1695}, + {0x1FAA, 0, 2, 1697}, + {0x1FAB, 0, 2, 1699}, + {0x1FAC, 0, 2, 1701}, + {0x1FAD, 0, 2, 1703}, + {0x1FAE, 0, 2, 1705}, + {0x1FAF, 0, 2, 1707}, + {0x1FB0, 0, 2, 1709}, + {0x1FB1, 0, 2, 1711}, + {0x1FB2, 0, 2, 1713}, + {0x1FB3, 0, 2, 1715}, + {0x1FB4, 0, 2, 1717}, + {0x1FB6, 0, 2, 1719}, + {0x1FB7, 0, 2, 1721}, + {0x1FB8, 0, 2, 1723}, + {0x1FB9, 0, 2, 1725}, + {0x1FBA, 0, 2, 1727}, + {0x1FBB, 0, 1 | DECOMP_INLINE, 0x0386}, + {0x1FBC, 0, 2, 1729}, + {0x1FBD, 0, 2 | DECOMP_COMPAT, 1731}, + {0x1FBE, 0, 1 | DECOMP_INLINE, 0x03B9}, + {0x1FBF, 0, 2 | DECOMP_COMPAT, 1733}, + {0x1FC0, 0, 2 | DECOMP_COMPAT, 1735}, + {0x1FC1, 0, 2, 1737}, + {0x1FC2, 0, 2, 1739}, + {0x1FC3, 0, 2, 1741}, + {0x1FC4, 0, 2, 1743}, + {0x1FC6, 0, 2, 1745}, + {0x1FC7, 0, 2, 1747}, + {0x1FC8, 0, 2, 1749}, + {0x1FC9, 0, 1 | DECOMP_INLINE, 0x0388}, + {0x1FCA, 0, 2, 1751}, + {0x1FCB, 0, 1 | DECOMP_INLINE, 0x0389}, + {0x1FCC, 0, 2, 1753}, + {0x1FCD, 0, 2, 1755}, + {0x1FCE, 0, 2, 1757}, + {0x1FCF, 0, 2, 1759}, + {0x1FD0, 0, 2, 1761}, + {0x1FD1, 0, 2, 1763}, + {0x1FD2, 0, 2, 1765}, + {0x1FD3, 0, 1 | DECOMP_INLINE, 0x0390}, + {0x1FD6, 0, 2, 1767}, + {0x1FD7, 0, 2, 1769}, + {0x1FD8, 0, 2, 1771}, + {0x1FD9, 0, 2, 1773}, + {0x1FDA, 0, 2, 1775}, + {0x1FDB, 0, 1 | DECOMP_INLINE, 0x038A}, + {0x1FDD, 0, 2, 1777}, + {0x1FDE, 0, 2, 1779}, + {0x1FDF, 0, 2, 1781}, + {0x1FE0, 0, 2, 1783}, + {0x1FE1, 0, 2, 1785}, + {0x1FE2, 0, 2, 1787}, + {0x1FE3, 0, 1 | DECOMP_INLINE, 0x03B0}, + {0x1FE4, 0, 2, 1789}, + {0x1FE5, 0, 2, 1791}, + {0x1FE6, 0, 2, 1793}, + {0x1FE7, 0, 2, 1795}, + {0x1FE8, 0, 2, 1797}, + {0x1FE9, 0, 2, 1799}, + {0x1FEA, 0, 2, 1801}, + {0x1FEB, 0, 1 | DECOMP_INLINE, 0x038E}, + {0x1FEC, 0, 2, 1803}, + {0x1FED, 0, 2, 1805}, + {0x1FEE, 0, 1 | DECOMP_INLINE, 0x0385}, + {0x1FEF, 0, 1 | DECOMP_INLINE, 0x0060}, + {0x1FF2, 0, 2, 1807}, + {0x1FF3, 0, 2, 1809}, + {0x1FF4, 0, 2, 1811}, + {0x1FF6, 0, 2, 1813}, + {0x1FF7, 0, 2, 1815}, + {0x1FF8, 0, 2, 1817}, + {0x1FF9, 0, 1 | DECOMP_INLINE, 0x038C}, + {0x1FFA, 0, 2, 1819}, + {0x1FFB, 0, 1 | DECOMP_INLINE, 0x038F}, + {0x1FFC, 0, 2, 1821}, + {0x1FFD, 0, 1 | DECOMP_INLINE, 0x00B4}, + {0x1FFE, 0, 2 | DECOMP_COMPAT, 1823}, + {0x2000, 0, 1 | DECOMP_INLINE, 0x2002}, + {0x2001, 0, 1 | DECOMP_INLINE, 0x2003}, + {0x2002, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2003, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2004, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2005, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2006, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2007, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2008, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2009, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x200A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2011, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2010}, + {0x2017, 0, 2 | DECOMP_COMPAT, 1825}, + {0x2024, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0x2025, 0, 2 | DECOMP_COMPAT, 1827}, + {0x2026, 0, 3 | DECOMP_COMPAT, 1829}, + {0x202F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2033, 0, 2 | DECOMP_COMPAT, 1832}, + {0x2034, 0, 3 | DECOMP_COMPAT, 1834}, + {0x2036, 0, 2 | DECOMP_COMPAT, 1837}, + {0x2037, 0, 3 | DECOMP_COMPAT, 1839}, + {0x203C, 0, 2 | DECOMP_COMPAT, 1842}, + {0x203E, 0, 2 | DECOMP_COMPAT, 1844}, + {0x2047, 0, 2 | DECOMP_COMPAT, 1846}, + {0x2048, 0, 2 | DECOMP_COMPAT, 1848}, + {0x2049, 0, 2 | DECOMP_COMPAT, 1850}, + {0x2057, 0, 4 | DECOMP_COMPAT, 1852}, + {0x205F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x2070, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2071, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2074, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2075, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2076, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2077, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2078, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2079, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x207A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0x207B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2212}, + {0x207C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0x207D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0x207E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0x207F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x2080, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2081, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x2082, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x2083, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x2084, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2085, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2086, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2087, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2088, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2089, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x208A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0x208B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2212}, + {0x208C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0x208D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0x208E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0x2090, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x2091, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2092, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x2093, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x2094, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0259}, + {0x2095, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x2096, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x2097, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x2098, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x2099, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x209A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x209B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x209C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x20A8, 0, 2 | DECOMP_COMPAT, 1856}, + {0x20D0, 230, 0, 0}, + {0x20D1, 230, 0, 0}, + {0x20D2, 1, 0, 0}, + {0x20D3, 1, 0, 0}, + {0x20D4, 230, 0, 0}, + {0x20D5, 230, 0, 0}, + {0x20D6, 230, 0, 0}, + {0x20D7, 230, 0, 0}, + {0x20D8, 1, 0, 0}, + {0x20D9, 1, 0, 0}, + {0x20DA, 1, 0, 0}, + {0x20DB, 230, 0, 0}, + {0x20DC, 230, 0, 0}, + {0x20E1, 230, 0, 0}, + {0x20E5, 1, 0, 0}, + {0x20E6, 1, 0, 0}, + {0x20E7, 230, 0, 0}, + {0x20E8, 220, 0, 0}, + {0x20E9, 230, 0, 0}, + {0x20EA, 1, 0, 0}, + {0x20EB, 1, 0, 0}, + {0x20EC, 220, 0, 0}, + {0x20ED, 220, 0, 0}, + {0x20EE, 220, 0, 0}, + {0x20EF, 220, 0, 0}, + {0x20F0, 230, 0, 0}, + {0x2100, 0, 3 | DECOMP_COMPAT, 1858}, + {0x2101, 0, 3 | DECOMP_COMPAT, 1861}, + {0x2102, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x2103, 0, 2 | DECOMP_COMPAT, 1864}, + {0x2105, 0, 3 | DECOMP_COMPAT, 1866}, + {0x2106, 0, 3 | DECOMP_COMPAT, 1869}, + {0x2107, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0190}, + {0x2109, 0, 2 | DECOMP_COMPAT, 1872}, + {0x210A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x210B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x210E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x210F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0127}, + {0x2110, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2111, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2112, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x2113, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x2115, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x2116, 0, 2 | DECOMP_COMPAT, 1874}, + {0x2119, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x211A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x211B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x211C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x211D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x2120, 0, 2 | DECOMP_COMPAT, 1876}, + {0x2121, 0, 3 | DECOMP_COMPAT, 1878}, + {0x2122, 0, 2 | DECOMP_COMPAT, 1881}, + {0x2124, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x2126, 0, 1 | DECOMP_INLINE, 0x03A9}, + {0x2128, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x212A, 0, 1 | DECOMP_INLINE, 0x004B}, + {0x212B, 0, 1 | DECOMP_INLINE, 0x00C5}, + {0x212C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x212D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x212F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2130, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x2131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x2133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x2134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x2135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D0}, + {0x2136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D1}, + {0x2137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D2}, + {0x2138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D3}, + {0x2139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x213B, 0, 3 | DECOMP_COMPAT, 1883}, + {0x213C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x213D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x213E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x213F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x2140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2211}, + {0x2145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x2146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x2147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x2148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x2150, 0, 3 | DECOMP_COMPAT, 1886}, + {0x2151, 0, 3 | DECOMP_COMPAT, 1889}, + {0x2152, 0, 4 | DECOMP_COMPAT, 1892}, + {0x2153, 0, 3 | DECOMP_COMPAT, 1896}, + {0x2154, 0, 3 | DECOMP_COMPAT, 1899}, + {0x2155, 0, 3 | DECOMP_COMPAT, 1902}, + {0x2156, 0, 3 | DECOMP_COMPAT, 1905}, + {0x2157, 0, 3 | DECOMP_COMPAT, 1908}, + {0x2158, 0, 3 | DECOMP_COMPAT, 1911}, + {0x2159, 0, 3 | DECOMP_COMPAT, 1914}, + {0x215A, 0, 3 | DECOMP_COMPAT, 1917}, + {0x215B, 0, 3 | DECOMP_COMPAT, 1920}, + {0x215C, 0, 3 | DECOMP_COMPAT, 1923}, + {0x215D, 0, 3 | DECOMP_COMPAT, 1926}, + {0x215E, 0, 3 | DECOMP_COMPAT, 1929}, + {0x215F, 0, 2 | DECOMP_COMPAT, 1932}, + {0x2160, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x2161, 0, 2 | DECOMP_COMPAT, 1934}, + {0x2162, 0, 3 | DECOMP_COMPAT, 1936}, + {0x2163, 0, 2 | DECOMP_COMPAT, 1939}, + {0x2164, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x2165, 0, 2 | DECOMP_COMPAT, 1941}, + {0x2166, 0, 3 | DECOMP_COMPAT, 1943}, + {0x2167, 0, 4 | DECOMP_COMPAT, 1946}, + {0x2168, 0, 2 | DECOMP_COMPAT, 1950}, + {0x2169, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x216A, 0, 2 | DECOMP_COMPAT, 1952}, + {0x216B, 0, 3 | DECOMP_COMPAT, 1954}, + {0x216C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x216D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x216E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x216F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x2170, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x2171, 0, 2 | DECOMP_COMPAT, 1957}, + {0x2172, 0, 3 | DECOMP_COMPAT, 1959}, + {0x2173, 0, 2 | DECOMP_COMPAT, 1962}, + {0x2174, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x2175, 0, 2 | DECOMP_COMPAT, 1964}, + {0x2176, 0, 3 | DECOMP_COMPAT, 1966}, + {0x2177, 0, 4 | DECOMP_COMPAT, 1969}, + {0x2178, 0, 2 | DECOMP_COMPAT, 1973}, + {0x2179, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x217A, 0, 2 | DECOMP_COMPAT, 1975}, + {0x217B, 0, 3 | DECOMP_COMPAT, 1977}, + {0x217C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x217D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x217E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x217F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x2189, 0, 3 | DECOMP_COMPAT, 1980}, + {0x219A, 0, 2, 1983}, + {0x219B, 0, 2, 1985}, + {0x21AE, 0, 2, 1987}, + {0x21CD, 0, 2, 1989}, + {0x21CE, 0, 2, 1991}, + {0x21CF, 0, 2, 1993}, + {0x2204, 0, 2, 1995}, + {0x2209, 0, 2, 1997}, + {0x220C, 0, 2, 1999}, + {0x2224, 0, 2, 2001}, + {0x2226, 0, 2, 2003}, + {0x222C, 0, 2 | DECOMP_COMPAT, 2005}, + {0x222D, 0, 3 | DECOMP_COMPAT, 2007}, + {0x222F, 0, 2 | DECOMP_COMPAT, 2010}, + {0x2230, 0, 3 | DECOMP_COMPAT, 2012}, + {0x2241, 0, 2, 2015}, + {0x2244, 0, 2, 2017}, + {0x2247, 0, 2, 2019}, + {0x2249, 0, 2, 2021}, + {0x2260, 0, 2, 2023}, + {0x2262, 0, 2, 2025}, + {0x226D, 0, 2, 2027}, + {0x226E, 0, 2, 2029}, + {0x226F, 0, 2, 2031}, + {0x2270, 0, 2, 2033}, + {0x2271, 0, 2, 2035}, + {0x2274, 0, 2, 2037}, + {0x2275, 0, 2, 2039}, + {0x2278, 0, 2, 2041}, + {0x2279, 0, 2, 2043}, + {0x2280, 0, 2, 2045}, + {0x2281, 0, 2, 2047}, + {0x2284, 0, 2, 2049}, + {0x2285, 0, 2, 2051}, + {0x2288, 0, 2, 2053}, + {0x2289, 0, 2, 2055}, + {0x22AC, 0, 2, 2057}, + {0x22AD, 0, 2, 2059}, + {0x22AE, 0, 2, 2061}, + {0x22AF, 0, 2, 2063}, + {0x22E0, 0, 2, 2065}, + {0x22E1, 0, 2, 2067}, + {0x22E2, 0, 2, 2069}, + {0x22E3, 0, 2, 2071}, + {0x22EA, 0, 2, 2073}, + {0x22EB, 0, 2, 2075}, + {0x22EC, 0, 2, 2077}, + {0x22ED, 0, 2, 2079}, + {0x2329, 0, 1 | DECOMP_INLINE, 0x3008}, + {0x232A, 0, 1 | DECOMP_INLINE, 0x3009}, + {0x2460, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x2461, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x2462, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x2463, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x2464, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x2465, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x2466, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x2467, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x2468, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x2469, 0, 2 | DECOMP_COMPAT, 2081}, + {0x246A, 0, 2 | DECOMP_COMPAT, 2083}, + {0x246B, 0, 2 | DECOMP_COMPAT, 2085}, + {0x246C, 0, 2 | DECOMP_COMPAT, 2087}, + {0x246D, 0, 2 | DECOMP_COMPAT, 2089}, + {0x246E, 0, 2 | DECOMP_COMPAT, 2091}, + {0x246F, 0, 2 | DECOMP_COMPAT, 2093}, + {0x2470, 0, 2 | DECOMP_COMPAT, 2095}, + {0x2471, 0, 2 | DECOMP_COMPAT, 2097}, + {0x2472, 0, 2 | DECOMP_COMPAT, 2099}, + {0x2473, 0, 2 | DECOMP_COMPAT, 2101}, + {0x2474, 0, 3 | DECOMP_COMPAT, 2103}, + {0x2475, 0, 3 | DECOMP_COMPAT, 2106}, + {0x2476, 0, 3 | DECOMP_COMPAT, 2109}, + {0x2477, 0, 3 | DECOMP_COMPAT, 2112}, + {0x2478, 0, 3 | DECOMP_COMPAT, 2115}, + {0x2479, 0, 3 | DECOMP_COMPAT, 2118}, + {0x247A, 0, 3 | DECOMP_COMPAT, 2121}, + {0x247B, 0, 3 | DECOMP_COMPAT, 2124}, + {0x247C, 0, 3 | DECOMP_COMPAT, 2127}, + {0x247D, 0, 4 | DECOMP_COMPAT, 2130}, + {0x247E, 0, 4 | DECOMP_COMPAT, 2134}, + {0x247F, 0, 4 | DECOMP_COMPAT, 2138}, + {0x2480, 0, 4 | DECOMP_COMPAT, 2142}, + {0x2481, 0, 4 | DECOMP_COMPAT, 2146}, + {0x2482, 0, 4 | DECOMP_COMPAT, 2150}, + {0x2483, 0, 4 | DECOMP_COMPAT, 2154}, + {0x2484, 0, 4 | DECOMP_COMPAT, 2158}, + {0x2485, 0, 4 | DECOMP_COMPAT, 2162}, + {0x2486, 0, 4 | DECOMP_COMPAT, 2166}, + {0x2487, 0, 4 | DECOMP_COMPAT, 2170}, + {0x2488, 0, 2 | DECOMP_COMPAT, 2174}, + {0x2489, 0, 2 | DECOMP_COMPAT, 2176}, + {0x248A, 0, 2 | DECOMP_COMPAT, 2178}, + {0x248B, 0, 2 | DECOMP_COMPAT, 2180}, + {0x248C, 0, 2 | DECOMP_COMPAT, 2182}, + {0x248D, 0, 2 | DECOMP_COMPAT, 2184}, + {0x248E, 0, 2 | DECOMP_COMPAT, 2186}, + {0x248F, 0, 2 | DECOMP_COMPAT, 2188}, + {0x2490, 0, 2 | DECOMP_COMPAT, 2190}, + {0x2491, 0, 3 | DECOMP_COMPAT, 2192}, + {0x2492, 0, 3 | DECOMP_COMPAT, 2195}, + {0x2493, 0, 3 | DECOMP_COMPAT, 2198}, + {0x2494, 0, 3 | DECOMP_COMPAT, 2201}, + {0x2495, 0, 3 | DECOMP_COMPAT, 2204}, + {0x2496, 0, 3 | DECOMP_COMPAT, 2207}, + {0x2497, 0, 3 | DECOMP_COMPAT, 2210}, + {0x2498, 0, 3 | DECOMP_COMPAT, 2213}, + {0x2499, 0, 3 | DECOMP_COMPAT, 2216}, + {0x249A, 0, 3 | DECOMP_COMPAT, 2219}, + {0x249B, 0, 3 | DECOMP_COMPAT, 2222}, + {0x249C, 0, 3 | DECOMP_COMPAT, 2225}, + {0x249D, 0, 3 | DECOMP_COMPAT, 2228}, + {0x249E, 0, 3 | DECOMP_COMPAT, 2231}, + {0x249F, 0, 3 | DECOMP_COMPAT, 2234}, + {0x24A0, 0, 3 | DECOMP_COMPAT, 2237}, + {0x24A1, 0, 3 | DECOMP_COMPAT, 2240}, + {0x24A2, 0, 3 | DECOMP_COMPAT, 2243}, + {0x24A3, 0, 3 | DECOMP_COMPAT, 2246}, + {0x24A4, 0, 3 | DECOMP_COMPAT, 2249}, + {0x24A5, 0, 3 | DECOMP_COMPAT, 2252}, + {0x24A6, 0, 3 | DECOMP_COMPAT, 2255}, + {0x24A7, 0, 3 | DECOMP_COMPAT, 2258}, + {0x24A8, 0, 3 | DECOMP_COMPAT, 2261}, + {0x24A9, 0, 3 | DECOMP_COMPAT, 2264}, + {0x24AA, 0, 3 | DECOMP_COMPAT, 2267}, + {0x24AB, 0, 3 | DECOMP_COMPAT, 2270}, + {0x24AC, 0, 3 | DECOMP_COMPAT, 2273}, + {0x24AD, 0, 3 | DECOMP_COMPAT, 2276}, + {0x24AE, 0, 3 | DECOMP_COMPAT, 2279}, + {0x24AF, 0, 3 | DECOMP_COMPAT, 2282}, + {0x24B0, 0, 3 | DECOMP_COMPAT, 2285}, + {0x24B1, 0, 3 | DECOMP_COMPAT, 2288}, + {0x24B2, 0, 3 | DECOMP_COMPAT, 2291}, + {0x24B3, 0, 3 | DECOMP_COMPAT, 2294}, + {0x24B4, 0, 3 | DECOMP_COMPAT, 2297}, + {0x24B5, 0, 3 | DECOMP_COMPAT, 2300}, + {0x24B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x24B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x24B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x24B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x24BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x24BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x24BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x24BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x24BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x24BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x24C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x24C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x24C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x24C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x24C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x24C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x24C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x24C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x24C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x24C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x24CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x24CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x24CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x24CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x24CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x24CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x24D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x24D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x24D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x24D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x24D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x24D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x24D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x24D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x24D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x24D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x24DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x24DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x24DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x24DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x24DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x24DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x24E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x24E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x24E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x24E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x24E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x24E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x24E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x24E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x24E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x24E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x24EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x2A0C, 0, 4 | DECOMP_COMPAT, 2303}, + {0x2A74, 0, 3 | DECOMP_COMPAT, 2307}, + {0x2A75, 0, 2 | DECOMP_COMPAT, 2310}, + {0x2A76, 0, 3 | DECOMP_COMPAT, 2312}, + {0x2ADC, 0, 2 | DECOMP_NO_COMPOSE, 2315}, /* in exclusion list */ + {0x2C7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x2C7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x2CEF, 230, 0, 0}, + {0x2CF0, 230, 0, 0}, + {0x2CF1, 230, 0, 0}, + {0x2D6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2D61}, + {0x2D7F, 9, 0, 0}, + {0x2DE0, 230, 0, 0}, + {0x2DE1, 230, 0, 0}, + {0x2DE2, 230, 0, 0}, + {0x2DE3, 230, 0, 0}, + {0x2DE4, 230, 0, 0}, + {0x2DE5, 230, 0, 0}, + {0x2DE6, 230, 0, 0}, + {0x2DE7, 230, 0, 0}, + {0x2DE8, 230, 0, 0}, + {0x2DE9, 230, 0, 0}, + {0x2DEA, 230, 0, 0}, + {0x2DEB, 230, 0, 0}, + {0x2DEC, 230, 0, 0}, + {0x2DED, 230, 0, 0}, + {0x2DEE, 230, 0, 0}, + {0x2DEF, 230, 0, 0}, + {0x2DF0, 230, 0, 0}, + {0x2DF1, 230, 0, 0}, + {0x2DF2, 230, 0, 0}, + {0x2DF3, 230, 0, 0}, + {0x2DF4, 230, 0, 0}, + {0x2DF5, 230, 0, 0}, + {0x2DF6, 230, 0, 0}, + {0x2DF7, 230, 0, 0}, + {0x2DF8, 230, 0, 0}, + {0x2DF9, 230, 0, 0}, + {0x2DFA, 230, 0, 0}, + {0x2DFB, 230, 0, 0}, + {0x2DFC, 230, 0, 0}, + {0x2DFD, 230, 0, 0}, + {0x2DFE, 230, 0, 0}, + {0x2DFF, 230, 0, 0}, + {0x2E9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BCD}, + {0x2EF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F9F}, + {0x2F00, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x2F01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E28}, + {0x2F02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E36}, + {0x2F03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E3F}, + {0x2F04, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E59}, + {0x2F05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E85}, + {0x2F06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x2F07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EA0}, + {0x2F08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EBA}, + {0x2F09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x513F}, + {0x2F0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5165}, + {0x2F0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516B}, + {0x2F0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5182}, + {0x2F0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5196}, + {0x2F0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51AB}, + {0x2F0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51E0}, + {0x2F10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x51F5}, + {0x2F11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5200}, + {0x2F12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x529B}, + {0x2F13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x52F9}, + {0x2F14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5315}, + {0x2F15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x531A}, + {0x2F16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5338}, + {0x2F17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x2F18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x535C}, + {0x2F19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5369}, + {0x2F1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5382}, + {0x2F1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53B6}, + {0x2F1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53C8}, + {0x2F1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53E3}, + {0x2F1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56D7}, + {0x2F1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x571F}, + {0x2F20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x58EB}, + {0x2F21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5902}, + {0x2F22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x590A}, + {0x2F23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5915}, + {0x2F24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5927}, + {0x2F25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5973}, + {0x2F26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B50}, + {0x2F27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B80}, + {0x2F28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5BF8}, + {0x2F29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C0F}, + {0x2F2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C22}, + {0x2F2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C38}, + {0x2F2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C6E}, + {0x2F2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5C71}, + {0x2F2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DDB}, + {0x2F2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE5}, + {0x2F30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DF1}, + {0x2F31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DFE}, + {0x2F32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E72}, + {0x2F33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7A}, + {0x2F34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7F}, + {0x2F35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5EF4}, + {0x2F36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5EFE}, + {0x2F37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F0B}, + {0x2F38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F13}, + {0x2F39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F50}, + {0x2F3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F61}, + {0x2F3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F73}, + {0x2F3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5FC3}, + {0x2F3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6208}, + {0x2F3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6236}, + {0x2F3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x624B}, + {0x2F40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x652F}, + {0x2F41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6534}, + {0x2F42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6587}, + {0x2F43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6597}, + {0x2F44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65A4}, + {0x2F45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65B9}, + {0x2F46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E0}, + {0x2F47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E5}, + {0x2F48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x66F0}, + {0x2F49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x2F4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6728}, + {0x2F4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B20}, + {0x2F4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B62}, + {0x2F4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B79}, + {0x2F4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BB3}, + {0x2F4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BCB}, + {0x2F50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BD4}, + {0x2F51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6BDB}, + {0x2F52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C0F}, + {0x2F53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C14}, + {0x2F54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C34}, + {0x2F55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x706B}, + {0x2F56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x722A}, + {0x2F57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7236}, + {0x2F58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x723B}, + {0x2F59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x723F}, + {0x2F5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7247}, + {0x2F5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7259}, + {0x2F5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x725B}, + {0x2F5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x72AC}, + {0x2F5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7384}, + {0x2F5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7389}, + {0x2F60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x74DC}, + {0x2F61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x74E6}, + {0x2F62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7518}, + {0x2F63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x751F}, + {0x2F64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7528}, + {0x2F65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7530}, + {0x2F66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x758B}, + {0x2F67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7592}, + {0x2F68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7676}, + {0x2F69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x767D}, + {0x2F6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76AE}, + {0x2F6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76BF}, + {0x2F6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76EE}, + {0x2F6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77DB}, + {0x2F6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77E2}, + {0x2F6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x77F3}, + {0x2F70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x793A}, + {0x2F71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79B8}, + {0x2F72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79BE}, + {0x2F73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7A74}, + {0x2F74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7ACB}, + {0x2F75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7AF9}, + {0x2F76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7C73}, + {0x2F77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7CF8}, + {0x2F78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F36}, + {0x2F79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F51}, + {0x2F7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7F8A}, + {0x2F7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7FBD}, + {0x2F7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8001}, + {0x2F7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x800C}, + {0x2F7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8012}, + {0x2F7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8033}, + {0x2F80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x807F}, + {0x2F81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8089}, + {0x2F82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81E3}, + {0x2F83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81EA}, + {0x2F84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81F3}, + {0x2F85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x81FC}, + {0x2F86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x820C}, + {0x2F87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x821B}, + {0x2F88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x821F}, + {0x2F89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x826E}, + {0x2F8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8272}, + {0x2F8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8278}, + {0x2F8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x864D}, + {0x2F8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x866B}, + {0x2F8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8840}, + {0x2F8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x884C}, + {0x2F90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8863}, + {0x2F91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x897E}, + {0x2F92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x898B}, + {0x2F93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x89D2}, + {0x2F94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8A00}, + {0x2F95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C37}, + {0x2F96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C46}, + {0x2F97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C55}, + {0x2F98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C78}, + {0x2F99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8C9D}, + {0x2F9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D64}, + {0x2F9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D70}, + {0x2F9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8DB3}, + {0x2F9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8EAB}, + {0x2F9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8ECA}, + {0x2F9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8F9B}, + {0x2FA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8FB0}, + {0x2FA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8FB5}, + {0x2FA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9091}, + {0x2FA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9149}, + {0x2FA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91C6}, + {0x2FA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91CC}, + {0x2FA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91D1}, + {0x2FA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9577}, + {0x2FA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9580}, + {0x2FA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x961C}, + {0x2FAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96B6}, + {0x2FAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96B9}, + {0x2FAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x96E8}, + {0x2FAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9751}, + {0x2FAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x975E}, + {0x2FAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9762}, + {0x2FB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9769}, + {0x2FB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97CB}, + {0x2FB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97ED}, + {0x2FB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x97F3}, + {0x2FB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9801}, + {0x2FB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98A8}, + {0x2FB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98DB}, + {0x2FB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x98DF}, + {0x2FB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9996}, + {0x2FB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9999}, + {0x2FBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x99AC}, + {0x2FBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9AA8}, + {0x2FBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9AD8}, + {0x2FBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ADF}, + {0x2FBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B25}, + {0x2FBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B2F}, + {0x2FC0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B32}, + {0x2FC1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B3C}, + {0x2FC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9B5A}, + {0x2FC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9CE5}, + {0x2FC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9E75}, + {0x2FC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9E7F}, + {0x2FC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EA5}, + {0x2FC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EBB}, + {0x2FC8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EC3}, + {0x2FC9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ECD}, + {0x2FCA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9ED1}, + {0x2FCB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EF9}, + {0x2FCC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9EFD}, + {0x2FCD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F0E}, + {0x2FCE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F13}, + {0x2FCF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F20}, + {0x2FD0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F3B}, + {0x2FD1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F4A}, + {0x2FD2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F52}, + {0x2FD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F8D}, + {0x2FD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9F9C}, + {0x2FD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9FA0}, + {0x3000, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0020}, + {0x302A, 218, 0, 0}, + {0x302B, 228, 0, 0}, + {0x302C, 232, 0, 0}, + {0x302D, 222, 0, 0}, + {0x302E, 224, 0, 0}, + {0x302F, 224, 0, 0}, + {0x3036, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3012}, + {0x3038, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x3039, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5344}, + {0x303A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5345}, + {0x304C, 0, 2, 2317}, + {0x304E, 0, 2, 2319}, + {0x3050, 0, 2, 2321}, + {0x3052, 0, 2, 2323}, + {0x3054, 0, 2, 2325}, + {0x3056, 0, 2, 2327}, + {0x3058, 0, 2, 2329}, + {0x305A, 0, 2, 2331}, + {0x305C, 0, 2, 2333}, + {0x305E, 0, 2, 2335}, + {0x3060, 0, 2, 2337}, + {0x3062, 0, 2, 2339}, + {0x3065, 0, 2, 2341}, + {0x3067, 0, 2, 2343}, + {0x3069, 0, 2, 2345}, + {0x3070, 0, 2, 2347}, + {0x3071, 0, 2, 2349}, + {0x3073, 0, 2, 2351}, + {0x3074, 0, 2, 2353}, + {0x3076, 0, 2, 2355}, + {0x3077, 0, 2, 2357}, + {0x3079, 0, 2, 2359}, + {0x307A, 0, 2, 2361}, + {0x307C, 0, 2, 2363}, + {0x307D, 0, 2, 2365}, + {0x3094, 0, 2, 2367}, + {0x3099, 8, 0, 0}, + {0x309A, 8, 0, 0}, + {0x309B, 0, 2 | DECOMP_COMPAT, 2369}, + {0x309C, 0, 2 | DECOMP_COMPAT, 2371}, + {0x309E, 0, 2, 2373}, + {0x309F, 0, 2 | DECOMP_COMPAT, 2375}, + {0x30AC, 0, 2, 2377}, + {0x30AE, 0, 2, 2379}, + {0x30B0, 0, 2, 2381}, + {0x30B2, 0, 2, 2383}, + {0x30B4, 0, 2, 2385}, + {0x30B6, 0, 2, 2387}, + {0x30B8, 0, 2, 2389}, + {0x30BA, 0, 2, 2391}, + {0x30BC, 0, 2, 2393}, + {0x30BE, 0, 2, 2395}, + {0x30C0, 0, 2, 2397}, + {0x30C2, 0, 2, 2399}, + {0x30C5, 0, 2, 2401}, + {0x30C7, 0, 2, 2403}, + {0x30C9, 0, 2, 2405}, + {0x30D0, 0, 2, 2407}, + {0x30D1, 0, 2, 2409}, + {0x30D3, 0, 2, 2411}, + {0x30D4, 0, 2, 2413}, + {0x30D6, 0, 2, 2415}, + {0x30D7, 0, 2, 2417}, + {0x30D9, 0, 2, 2419}, + {0x30DA, 0, 2, 2421}, + {0x30DC, 0, 2, 2423}, + {0x30DD, 0, 2, 2425}, + {0x30F4, 0, 2, 2427}, + {0x30F7, 0, 2, 2429}, + {0x30F8, 0, 2, 2431}, + {0x30F9, 0, 2, 2433}, + {0x30FA, 0, 2, 2435}, + {0x30FE, 0, 2, 2437}, + {0x30FF, 0, 2 | DECOMP_COMPAT, 2439}, + {0x3131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1100}, + {0x3132, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1101}, + {0x3133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AA}, + {0x3134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1102}, + {0x3135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AC}, + {0x3136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11AD}, + {0x3137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1103}, + {0x3138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1104}, + {0x3139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1105}, + {0x313A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B0}, + {0x313B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B1}, + {0x313C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B2}, + {0x313D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B3}, + {0x313E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B4}, + {0x313F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11B5}, + {0x3140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111A}, + {0x3141, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1106}, + {0x3142, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1107}, + {0x3143, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1108}, + {0x3144, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1121}, + {0x3145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1109}, + {0x3146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110A}, + {0x3147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110B}, + {0x3148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110C}, + {0x3149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110D}, + {0x314A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110E}, + {0x314B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110F}, + {0x314C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1110}, + {0x314D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1111}, + {0x314E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1112}, + {0x314F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1161}, + {0x3150, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1162}, + {0x3151, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1163}, + {0x3152, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1164}, + {0x3153, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1165}, + {0x3154, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1166}, + {0x3155, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1167}, + {0x3156, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1168}, + {0x3157, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1169}, + {0x3158, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116A}, + {0x3159, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116B}, + {0x315A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116C}, + {0x315B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116D}, + {0x315C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116E}, + {0x315D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x116F}, + {0x315E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1170}, + {0x315F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1171}, + {0x3160, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1172}, + {0x3161, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1173}, + {0x3162, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1174}, + {0x3163, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1175}, + {0x3164, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1160}, + {0x3165, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1114}, + {0x3166, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1115}, + {0x3167, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11C7}, + {0x3168, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11C8}, + {0x3169, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11CC}, + {0x316A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11CE}, + {0x316B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D3}, + {0x316C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D7}, + {0x316D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11D9}, + {0x316E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111C}, + {0x316F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11DD}, + {0x3170, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11DF}, + {0x3171, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111D}, + {0x3172, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x111E}, + {0x3173, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1120}, + {0x3174, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1122}, + {0x3175, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1123}, + {0x3176, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1127}, + {0x3177, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1129}, + {0x3178, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112B}, + {0x3179, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112C}, + {0x317A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112D}, + {0x317B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112E}, + {0x317C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x112F}, + {0x317D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1132}, + {0x317E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1136}, + {0x317F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1140}, + {0x3180, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1147}, + {0x3181, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x114C}, + {0x3182, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11F1}, + {0x3183, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11F2}, + {0x3184, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1157}, + {0x3185, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1158}, + {0x3186, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1159}, + {0x3187, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1184}, + {0x3188, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1185}, + {0x3189, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1188}, + {0x318A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1191}, + {0x318B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1192}, + {0x318C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1194}, + {0x318D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x119E}, + {0x318E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x11A1}, + {0x3192, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x3193, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x3194, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x3195, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56DB}, + {0x3196, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0A}, + {0x3197, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x3198, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0B}, + {0x3199, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7532}, + {0x319A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E59}, + {0x319B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E19}, + {0x319C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E01}, + {0x319D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5929}, + {0x319E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5730}, + {0x319F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EBA}, + {0x3200, 0, 3 | DECOMP_COMPAT, 2441}, + {0x3201, 0, 3 | DECOMP_COMPAT, 2444}, + {0x3202, 0, 3 | DECOMP_COMPAT, 2447}, + {0x3203, 0, 3 | DECOMP_COMPAT, 2450}, + {0x3204, 0, 3 | DECOMP_COMPAT, 2453}, + {0x3205, 0, 3 | DECOMP_COMPAT, 2456}, + {0x3206, 0, 3 | DECOMP_COMPAT, 2459}, + {0x3207, 0, 3 | DECOMP_COMPAT, 2462}, + {0x3208, 0, 3 | DECOMP_COMPAT, 2465}, + {0x3209, 0, 3 | DECOMP_COMPAT, 2468}, + {0x320A, 0, 3 | DECOMP_COMPAT, 2471}, + {0x320B, 0, 3 | DECOMP_COMPAT, 2474}, + {0x320C, 0, 3 | DECOMP_COMPAT, 2477}, + {0x320D, 0, 3 | DECOMP_COMPAT, 2480}, + {0x320E, 0, 4 | DECOMP_COMPAT, 2483}, + {0x320F, 0, 4 | DECOMP_COMPAT, 2487}, + {0x3210, 0, 4 | DECOMP_COMPAT, 2491}, + {0x3211, 0, 4 | DECOMP_COMPAT, 2495}, + {0x3212, 0, 4 | DECOMP_COMPAT, 2499}, + {0x3213, 0, 4 | DECOMP_COMPAT, 2503}, + {0x3214, 0, 4 | DECOMP_COMPAT, 2507}, + {0x3215, 0, 4 | DECOMP_COMPAT, 2511}, + {0x3216, 0, 4 | DECOMP_COMPAT, 2515}, + {0x3217, 0, 4 | DECOMP_COMPAT, 2519}, + {0x3218, 0, 4 | DECOMP_COMPAT, 2523}, + {0x3219, 0, 4 | DECOMP_COMPAT, 2527}, + {0x321A, 0, 4 | DECOMP_COMPAT, 2531}, + {0x321B, 0, 4 | DECOMP_COMPAT, 2535}, + {0x321C, 0, 4 | DECOMP_COMPAT, 2539}, + {0x321D, 0, 7 | DECOMP_COMPAT, 2543}, + {0x321E, 0, 6 | DECOMP_COMPAT, 2550}, + {0x3220, 0, 3 | DECOMP_COMPAT, 2556}, + {0x3221, 0, 3 | DECOMP_COMPAT, 2559}, + {0x3222, 0, 3 | DECOMP_COMPAT, 2562}, + {0x3223, 0, 3 | DECOMP_COMPAT, 2565}, + {0x3224, 0, 3 | DECOMP_COMPAT, 2568}, + {0x3225, 0, 3 | DECOMP_COMPAT, 2571}, + {0x3226, 0, 3 | DECOMP_COMPAT, 2574}, + {0x3227, 0, 3 | DECOMP_COMPAT, 2577}, + {0x3228, 0, 3 | DECOMP_COMPAT, 2580}, + {0x3229, 0, 3 | DECOMP_COMPAT, 2583}, + {0x322A, 0, 3 | DECOMP_COMPAT, 2586}, + {0x322B, 0, 3 | DECOMP_COMPAT, 2589}, + {0x322C, 0, 3 | DECOMP_COMPAT, 2592}, + {0x322D, 0, 3 | DECOMP_COMPAT, 2595}, + {0x322E, 0, 3 | DECOMP_COMPAT, 2598}, + {0x322F, 0, 3 | DECOMP_COMPAT, 2601}, + {0x3230, 0, 3 | DECOMP_COMPAT, 2604}, + {0x3231, 0, 3 | DECOMP_COMPAT, 2607}, + {0x3232, 0, 3 | DECOMP_COMPAT, 2610}, + {0x3233, 0, 3 | DECOMP_COMPAT, 2613}, + {0x3234, 0, 3 | DECOMP_COMPAT, 2616}, + {0x3235, 0, 3 | DECOMP_COMPAT, 2619}, + {0x3236, 0, 3 | DECOMP_COMPAT, 2622}, + {0x3237, 0, 3 | DECOMP_COMPAT, 2625}, + {0x3238, 0, 3 | DECOMP_COMPAT, 2628}, + {0x3239, 0, 3 | DECOMP_COMPAT, 2631}, + {0x323A, 0, 3 | DECOMP_COMPAT, 2634}, + {0x323B, 0, 3 | DECOMP_COMPAT, 2637}, + {0x323C, 0, 3 | DECOMP_COMPAT, 2640}, + {0x323D, 0, 3 | DECOMP_COMPAT, 2643}, + {0x323E, 0, 3 | DECOMP_COMPAT, 2646}, + {0x323F, 0, 3 | DECOMP_COMPAT, 2649}, + {0x3240, 0, 3 | DECOMP_COMPAT, 2652}, + {0x3241, 0, 3 | DECOMP_COMPAT, 2655}, + {0x3242, 0, 3 | DECOMP_COMPAT, 2658}, + {0x3243, 0, 3 | DECOMP_COMPAT, 2661}, + {0x3244, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x554F}, + {0x3245, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5E7C}, + {0x3246, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6587}, + {0x3247, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7B8F}, + {0x3250, 0, 3 | DECOMP_COMPAT, 2664}, + {0x3251, 0, 2 | DECOMP_COMPAT, 2667}, + {0x3252, 0, 2 | DECOMP_COMPAT, 2669}, + {0x3253, 0, 2 | DECOMP_COMPAT, 2671}, + {0x3254, 0, 2 | DECOMP_COMPAT, 2673}, + {0x3255, 0, 2 | DECOMP_COMPAT, 2675}, + {0x3256, 0, 2 | DECOMP_COMPAT, 2677}, + {0x3257, 0, 2 | DECOMP_COMPAT, 2679}, + {0x3258, 0, 2 | DECOMP_COMPAT, 2681}, + {0x3259, 0, 2 | DECOMP_COMPAT, 2683}, + {0x325A, 0, 2 | DECOMP_COMPAT, 2685}, + {0x325B, 0, 2 | DECOMP_COMPAT, 2687}, + {0x325C, 0, 2 | DECOMP_COMPAT, 2689}, + {0x325D, 0, 2 | DECOMP_COMPAT, 2691}, + {0x325E, 0, 2 | DECOMP_COMPAT, 2693}, + {0x325F, 0, 2 | DECOMP_COMPAT, 2695}, + {0x3260, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1100}, + {0x3261, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1102}, + {0x3262, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1103}, + {0x3263, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1105}, + {0x3264, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1106}, + {0x3265, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1107}, + {0x3266, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1109}, + {0x3267, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110B}, + {0x3268, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110C}, + {0x3269, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110E}, + {0x326A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x110F}, + {0x326B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1110}, + {0x326C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1111}, + {0x326D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1112}, + {0x326E, 0, 2 | DECOMP_COMPAT, 2697}, + {0x326F, 0, 2 | DECOMP_COMPAT, 2699}, + {0x3270, 0, 2 | DECOMP_COMPAT, 2701}, + {0x3271, 0, 2 | DECOMP_COMPAT, 2703}, + {0x3272, 0, 2 | DECOMP_COMPAT, 2705}, + {0x3273, 0, 2 | DECOMP_COMPAT, 2707}, + {0x3274, 0, 2 | DECOMP_COMPAT, 2709}, + {0x3275, 0, 2 | DECOMP_COMPAT, 2711}, + {0x3276, 0, 2 | DECOMP_COMPAT, 2713}, + {0x3277, 0, 2 | DECOMP_COMPAT, 2715}, + {0x3278, 0, 2 | DECOMP_COMPAT, 2717}, + {0x3279, 0, 2 | DECOMP_COMPAT, 2719}, + {0x327A, 0, 2 | DECOMP_COMPAT, 2721}, + {0x327B, 0, 2 | DECOMP_COMPAT, 2723}, + {0x327C, 0, 5 | DECOMP_COMPAT, 2725}, + {0x327D, 0, 4 | DECOMP_COMPAT, 2730}, + {0x327E, 0, 2 | DECOMP_COMPAT, 2734}, + {0x3280, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x3281, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x3282, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x3283, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x56DB}, + {0x3284, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E94}, + {0x3285, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516D}, + {0x3286, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E03}, + {0x3287, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x516B}, + {0x3288, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E5D}, + {0x3289, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5341}, + {0x328A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x328B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x706B}, + {0x328C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6C34}, + {0x328D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6728}, + {0x328E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x91D1}, + {0x328F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x571F}, + {0x3290, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65E5}, + {0x3291, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x682A}, + {0x3292, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6709}, + {0x3293, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x793E}, + {0x3294, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x540D}, + {0x3295, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7279}, + {0x3296, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CA1}, + {0x3297, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x795D}, + {0x3298, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x52B4}, + {0x3299, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x79D8}, + {0x329A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7537}, + {0x329B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5973}, + {0x329C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9069}, + {0x329D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x512A}, + {0x329E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5370}, + {0x329F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6CE8}, + {0x32A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x9805}, + {0x32A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4F11}, + {0x32A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5199}, + {0x32A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6B63}, + {0x32A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0A}, + {0x32A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x32A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E0B}, + {0x32A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE6}, + {0x32A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53F3}, + {0x32A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x533B}, + {0x32AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B97}, + {0x32AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B66}, + {0x32AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x76E3}, + {0x32AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4F01}, + {0x32AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CC7}, + {0x32AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5354}, + {0x32B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x591C}, + {0x32B1, 0, 2 | DECOMP_COMPAT, 2736}, + {0x32B2, 0, 2 | DECOMP_COMPAT, 2738}, + {0x32B3, 0, 2 | DECOMP_COMPAT, 2740}, + {0x32B4, 0, 2 | DECOMP_COMPAT, 2742}, + {0x32B5, 0, 2 | DECOMP_COMPAT, 2744}, + {0x32B6, 0, 2 | DECOMP_COMPAT, 2746}, + {0x32B7, 0, 2 | DECOMP_COMPAT, 2748}, + {0x32B8, 0, 2 | DECOMP_COMPAT, 2750}, + {0x32B9, 0, 2 | DECOMP_COMPAT, 2752}, + {0x32BA, 0, 2 | DECOMP_COMPAT, 2754}, + {0x32BB, 0, 2 | DECOMP_COMPAT, 2756}, + {0x32BC, 0, 2 | DECOMP_COMPAT, 2758}, + {0x32BD, 0, 2 | DECOMP_COMPAT, 2760}, + {0x32BE, 0, 2 | DECOMP_COMPAT, 2762}, + {0x32BF, 0, 2 | DECOMP_COMPAT, 2764}, + {0x32C0, 0, 2 | DECOMP_COMPAT, 2766}, + {0x32C1, 0, 2 | DECOMP_COMPAT, 2768}, + {0x32C2, 0, 2 | DECOMP_COMPAT, 2770}, + {0x32C3, 0, 2 | DECOMP_COMPAT, 2772}, + {0x32C4, 0, 2 | DECOMP_COMPAT, 2774}, + {0x32C5, 0, 2 | DECOMP_COMPAT, 2776}, + {0x32C6, 0, 2 | DECOMP_COMPAT, 2778}, + {0x32C7, 0, 2 | DECOMP_COMPAT, 2780}, + {0x32C8, 0, 2 | DECOMP_COMPAT, 2782}, + {0x32C9, 0, 3 | DECOMP_COMPAT, 2784}, + {0x32CA, 0, 3 | DECOMP_COMPAT, 2787}, + {0x32CB, 0, 3 | DECOMP_COMPAT, 2790}, + {0x32CC, 0, 2 | DECOMP_COMPAT, 2793}, + {0x32CD, 0, 3 | DECOMP_COMPAT, 2795}, + {0x32CE, 0, 2 | DECOMP_COMPAT, 2798}, + {0x32CF, 0, 3 | DECOMP_COMPAT, 2800}, + {0x32D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A2}, + {0x32D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A4}, + {0x32D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A6}, + {0x32D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A8}, + {0x32D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AA}, + {0x32D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AB}, + {0x32D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AD}, + {0x32D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AF}, + {0x32D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B1}, + {0x32D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B3}, + {0x32DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0x32DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B7}, + {0x32DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B9}, + {0x32DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BB}, + {0x32DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BD}, + {0x32DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BF}, + {0x32E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C1}, + {0x32E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C4}, + {0x32E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C6}, + {0x32E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C8}, + {0x32E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CA}, + {0x32E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CB}, + {0x32E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CC}, + {0x32E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CD}, + {0x32E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CE}, + {0x32E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CF}, + {0x32EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D2}, + {0x32EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D5}, + {0x32EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D8}, + {0x32ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DB}, + {0x32EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DE}, + {0x32EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DF}, + {0x32F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E0}, + {0x32F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E1}, + {0x32F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E2}, + {0x32F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E4}, + {0x32F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E6}, + {0x32F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E8}, + {0x32F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E9}, + {0x32F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EA}, + {0x32F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EB}, + {0x32F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EC}, + {0x32FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30ED}, + {0x32FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EF}, + {0x32FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F0}, + {0x32FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F1}, + {0x32FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F2}, + {0x32FF, 0, 2 | DECOMP_COMPAT, 2803}, + {0x3300, 0, 4 | DECOMP_COMPAT, 2805}, + {0x3301, 0, 4 | DECOMP_COMPAT, 2809}, + {0x3302, 0, 4 | DECOMP_COMPAT, 2813}, + {0x3303, 0, 3 | DECOMP_COMPAT, 2817}, + {0x3304, 0, 4 | DECOMP_COMPAT, 2820}, + {0x3305, 0, 3 | DECOMP_COMPAT, 2824}, + {0x3306, 0, 3 | DECOMP_COMPAT, 2827}, + {0x3307, 0, 5 | DECOMP_COMPAT, 2830}, + {0x3308, 0, 4 | DECOMP_COMPAT, 2835}, + {0x3309, 0, 3 | DECOMP_COMPAT, 2839}, + {0x330A, 0, 3 | DECOMP_COMPAT, 2842}, + {0x330B, 0, 3 | DECOMP_COMPAT, 2845}, + {0x330C, 0, 4 | DECOMP_COMPAT, 2848}, + {0x330D, 0, 4 | DECOMP_COMPAT, 2852}, + {0x330E, 0, 3 | DECOMP_COMPAT, 2856}, + {0x330F, 0, 3 | DECOMP_COMPAT, 2859}, + {0x3310, 0, 2 | DECOMP_COMPAT, 2862}, + {0x3311, 0, 3 | DECOMP_COMPAT, 2864}, + {0x3312, 0, 4 | DECOMP_COMPAT, 2867}, + {0x3313, 0, 4 | DECOMP_COMPAT, 2871}, + {0x3314, 0, 2 | DECOMP_COMPAT, 2875}, + {0x3315, 0, 5 | DECOMP_COMPAT, 2877}, + {0x3316, 0, 6 | DECOMP_COMPAT, 2882}, + {0x3317, 0, 5 | DECOMP_COMPAT, 2888}, + {0x3318, 0, 3 | DECOMP_COMPAT, 2893}, + {0x3319, 0, 5 | DECOMP_COMPAT, 2896}, + {0x331A, 0, 5 | DECOMP_COMPAT, 2901}, + {0x331B, 0, 4 | DECOMP_COMPAT, 2906}, + {0x331C, 0, 3 | DECOMP_COMPAT, 2910}, + {0x331D, 0, 3 | DECOMP_COMPAT, 2913}, + {0x331E, 0, 3 | DECOMP_COMPAT, 2916}, + {0x331F, 0, 4 | DECOMP_COMPAT, 2919}, + {0x3320, 0, 5 | DECOMP_COMPAT, 2923}, + {0x3321, 0, 4 | DECOMP_COMPAT, 2928}, + {0x3322, 0, 3 | DECOMP_COMPAT, 2932}, + {0x3323, 0, 3 | DECOMP_COMPAT, 2935}, + {0x3324, 0, 3 | DECOMP_COMPAT, 2938}, + {0x3325, 0, 2 | DECOMP_COMPAT, 2941}, + {0x3326, 0, 2 | DECOMP_COMPAT, 2943}, + {0x3327, 0, 2 | DECOMP_COMPAT, 2945}, + {0x3328, 0, 2 | DECOMP_COMPAT, 2947}, + {0x3329, 0, 3 | DECOMP_COMPAT, 2949}, + {0x332A, 0, 3 | DECOMP_COMPAT, 2952}, + {0x332B, 0, 5 | DECOMP_COMPAT, 2955}, + {0x332C, 0, 3 | DECOMP_COMPAT, 2960}, + {0x332D, 0, 4 | DECOMP_COMPAT, 2963}, + {0x332E, 0, 5 | DECOMP_COMPAT, 2967}, + {0x332F, 0, 3 | DECOMP_COMPAT, 2972}, + {0x3330, 0, 2 | DECOMP_COMPAT, 2975}, + {0x3331, 0, 2 | DECOMP_COMPAT, 2977}, + {0x3332, 0, 5 | DECOMP_COMPAT, 2979}, + {0x3333, 0, 4 | DECOMP_COMPAT, 2984}, + {0x3334, 0, 5 | DECOMP_COMPAT, 2988}, + {0x3335, 0, 3 | DECOMP_COMPAT, 2993}, + {0x3336, 0, 5 | DECOMP_COMPAT, 2996}, + {0x3337, 0, 2 | DECOMP_COMPAT, 3001}, + {0x3338, 0, 3 | DECOMP_COMPAT, 3003}, + {0x3339, 0, 3 | DECOMP_COMPAT, 3006}, + {0x333A, 0, 3 | DECOMP_COMPAT, 3009}, + {0x333B, 0, 3 | DECOMP_COMPAT, 3012}, + {0x333C, 0, 3 | DECOMP_COMPAT, 3015}, + {0x333D, 0, 4 | DECOMP_COMPAT, 3018}, + {0x333E, 0, 3 | DECOMP_COMPAT, 3022}, + {0x333F, 0, 2 | DECOMP_COMPAT, 3025}, + {0x3340, 0, 3 | DECOMP_COMPAT, 3027}, + {0x3341, 0, 3 | DECOMP_COMPAT, 3030}, + {0x3342, 0, 3 | DECOMP_COMPAT, 3033}, + {0x3343, 0, 4 | DECOMP_COMPAT, 3036}, + {0x3344, 0, 3 | DECOMP_COMPAT, 3040}, + {0x3345, 0, 3 | DECOMP_COMPAT, 3043}, + {0x3346, 0, 3 | DECOMP_COMPAT, 3046}, + {0x3347, 0, 5 | DECOMP_COMPAT, 3049}, + {0x3348, 0, 4 | DECOMP_COMPAT, 3054}, + {0x3349, 0, 2 | DECOMP_COMPAT, 3058}, + {0x334A, 0, 5 | DECOMP_COMPAT, 3060}, + {0x334B, 0, 2 | DECOMP_COMPAT, 3065}, + {0x334C, 0, 4 | DECOMP_COMPAT, 3067}, + {0x334D, 0, 4 | DECOMP_COMPAT, 3071}, + {0x334E, 0, 3 | DECOMP_COMPAT, 3075}, + {0x334F, 0, 3 | DECOMP_COMPAT, 3078}, + {0x3350, 0, 3 | DECOMP_COMPAT, 3081}, + {0x3351, 0, 4 | DECOMP_COMPAT, 3084}, + {0x3352, 0, 2 | DECOMP_COMPAT, 3088}, + {0x3353, 0, 3 | DECOMP_COMPAT, 3090}, + {0x3354, 0, 4 | DECOMP_COMPAT, 3093}, + {0x3355, 0, 2 | DECOMP_COMPAT, 3097}, + {0x3356, 0, 5 | DECOMP_COMPAT, 3099}, + {0x3357, 0, 3 | DECOMP_COMPAT, 3104}, + {0x3358, 0, 2 | DECOMP_COMPAT, 3107}, + {0x3359, 0, 2 | DECOMP_COMPAT, 3109}, + {0x335A, 0, 2 | DECOMP_COMPAT, 3111}, + {0x335B, 0, 2 | DECOMP_COMPAT, 3113}, + {0x335C, 0, 2 | DECOMP_COMPAT, 3115}, + {0x335D, 0, 2 | DECOMP_COMPAT, 3117}, + {0x335E, 0, 2 | DECOMP_COMPAT, 3119}, + {0x335F, 0, 2 | DECOMP_COMPAT, 3121}, + {0x3360, 0, 2 | DECOMP_COMPAT, 3123}, + {0x3361, 0, 2 | DECOMP_COMPAT, 3125}, + {0x3362, 0, 3 | DECOMP_COMPAT, 3127}, + {0x3363, 0, 3 | DECOMP_COMPAT, 3130}, + {0x3364, 0, 3 | DECOMP_COMPAT, 3133}, + {0x3365, 0, 3 | DECOMP_COMPAT, 3136}, + {0x3366, 0, 3 | DECOMP_COMPAT, 3139}, + {0x3367, 0, 3 | DECOMP_COMPAT, 3142}, + {0x3368, 0, 3 | DECOMP_COMPAT, 3145}, + {0x3369, 0, 3 | DECOMP_COMPAT, 3148}, + {0x336A, 0, 3 | DECOMP_COMPAT, 3151}, + {0x336B, 0, 3 | DECOMP_COMPAT, 3154}, + {0x336C, 0, 3 | DECOMP_COMPAT, 3157}, + {0x336D, 0, 3 | DECOMP_COMPAT, 3160}, + {0x336E, 0, 3 | DECOMP_COMPAT, 3163}, + {0x336F, 0, 3 | DECOMP_COMPAT, 3166}, + {0x3370, 0, 3 | DECOMP_COMPAT, 3169}, + {0x3371, 0, 3 | DECOMP_COMPAT, 3172}, + {0x3372, 0, 2 | DECOMP_COMPAT, 3175}, + {0x3373, 0, 2 | DECOMP_COMPAT, 3177}, + {0x3374, 0, 3 | DECOMP_COMPAT, 3179}, + {0x3375, 0, 2 | DECOMP_COMPAT, 3182}, + {0x3376, 0, 2 | DECOMP_COMPAT, 3184}, + {0x3377, 0, 2 | DECOMP_COMPAT, 3186}, + {0x3378, 0, 3 | DECOMP_COMPAT, 3188}, + {0x3379, 0, 3 | DECOMP_COMPAT, 3191}, + {0x337A, 0, 2 | DECOMP_COMPAT, 3194}, + {0x337B, 0, 2 | DECOMP_COMPAT, 3196}, + {0x337C, 0, 2 | DECOMP_COMPAT, 3198}, + {0x337D, 0, 2 | DECOMP_COMPAT, 3200}, + {0x337E, 0, 2 | DECOMP_COMPAT, 3202}, + {0x337F, 0, 4 | DECOMP_COMPAT, 3204}, + {0x3380, 0, 2 | DECOMP_COMPAT, 3208}, + {0x3381, 0, 2 | DECOMP_COMPAT, 3210}, + {0x3382, 0, 2 | DECOMP_COMPAT, 3212}, + {0x3383, 0, 2 | DECOMP_COMPAT, 3214}, + {0x3384, 0, 2 | DECOMP_COMPAT, 3216}, + {0x3385, 0, 2 | DECOMP_COMPAT, 3218}, + {0x3386, 0, 2 | DECOMP_COMPAT, 3220}, + {0x3387, 0, 2 | DECOMP_COMPAT, 3222}, + {0x3388, 0, 3 | DECOMP_COMPAT, 3224}, + {0x3389, 0, 4 | DECOMP_COMPAT, 3227}, + {0x338A, 0, 2 | DECOMP_COMPAT, 3231}, + {0x338B, 0, 2 | DECOMP_COMPAT, 3233}, + {0x338C, 0, 2 | DECOMP_COMPAT, 3235}, + {0x338D, 0, 2 | DECOMP_COMPAT, 3237}, + {0x338E, 0, 2 | DECOMP_COMPAT, 3239}, + {0x338F, 0, 2 | DECOMP_COMPAT, 3241}, + {0x3390, 0, 2 | DECOMP_COMPAT, 3243}, + {0x3391, 0, 3 | DECOMP_COMPAT, 3245}, + {0x3392, 0, 3 | DECOMP_COMPAT, 3248}, + {0x3393, 0, 3 | DECOMP_COMPAT, 3251}, + {0x3394, 0, 3 | DECOMP_COMPAT, 3254}, + {0x3395, 0, 2 | DECOMP_COMPAT, 3257}, + {0x3396, 0, 2 | DECOMP_COMPAT, 3259}, + {0x3397, 0, 2 | DECOMP_COMPAT, 3261}, + {0x3398, 0, 2 | DECOMP_COMPAT, 3263}, + {0x3399, 0, 2 | DECOMP_COMPAT, 3265}, + {0x339A, 0, 2 | DECOMP_COMPAT, 3267}, + {0x339B, 0, 2 | DECOMP_COMPAT, 3269}, + {0x339C, 0, 2 | DECOMP_COMPAT, 3271}, + {0x339D, 0, 2 | DECOMP_COMPAT, 3273}, + {0x339E, 0, 2 | DECOMP_COMPAT, 3275}, + {0x339F, 0, 3 | DECOMP_COMPAT, 3277}, + {0x33A0, 0, 3 | DECOMP_COMPAT, 3280}, + {0x33A1, 0, 2 | DECOMP_COMPAT, 3283}, + {0x33A2, 0, 3 | DECOMP_COMPAT, 3285}, + {0x33A3, 0, 3 | DECOMP_COMPAT, 3288}, + {0x33A4, 0, 3 | DECOMP_COMPAT, 3291}, + {0x33A5, 0, 2 | DECOMP_COMPAT, 3294}, + {0x33A6, 0, 3 | DECOMP_COMPAT, 3296}, + {0x33A7, 0, 3 | DECOMP_COMPAT, 3299}, + {0x33A8, 0, 4 | DECOMP_COMPAT, 3302}, + {0x33A9, 0, 2 | DECOMP_COMPAT, 3306}, + {0x33AA, 0, 3 | DECOMP_COMPAT, 3308}, + {0x33AB, 0, 3 | DECOMP_COMPAT, 3311}, + {0x33AC, 0, 3 | DECOMP_COMPAT, 3314}, + {0x33AD, 0, 3 | DECOMP_COMPAT, 3317}, + {0x33AE, 0, 5 | DECOMP_COMPAT, 3320}, + {0x33AF, 0, 6 | DECOMP_COMPAT, 3325}, + {0x33B0, 0, 2 | DECOMP_COMPAT, 3331}, + {0x33B1, 0, 2 | DECOMP_COMPAT, 3333}, + {0x33B2, 0, 2 | DECOMP_COMPAT, 3335}, + {0x33B3, 0, 2 | DECOMP_COMPAT, 3337}, + {0x33B4, 0, 2 | DECOMP_COMPAT, 3339}, + {0x33B5, 0, 2 | DECOMP_COMPAT, 3341}, + {0x33B6, 0, 2 | DECOMP_COMPAT, 3343}, + {0x33B7, 0, 2 | DECOMP_COMPAT, 3345}, + {0x33B8, 0, 2 | DECOMP_COMPAT, 3347}, + {0x33B9, 0, 2 | DECOMP_COMPAT, 3349}, + {0x33BA, 0, 2 | DECOMP_COMPAT, 3351}, + {0x33BB, 0, 2 | DECOMP_COMPAT, 3353}, + {0x33BC, 0, 2 | DECOMP_COMPAT, 3355}, + {0x33BD, 0, 2 | DECOMP_COMPAT, 3357}, + {0x33BE, 0, 2 | DECOMP_COMPAT, 3359}, + {0x33BF, 0, 2 | DECOMP_COMPAT, 3361}, + {0x33C0, 0, 2 | DECOMP_COMPAT, 3363}, + {0x33C1, 0, 2 | DECOMP_COMPAT, 3365}, + {0x33C2, 0, 4 | DECOMP_COMPAT, 3367}, + {0x33C3, 0, 2 | DECOMP_COMPAT, 3371}, + {0x33C4, 0, 2 | DECOMP_COMPAT, 3373}, + {0x33C5, 0, 2 | DECOMP_COMPAT, 3375}, + {0x33C6, 0, 4 | DECOMP_COMPAT, 3377}, + {0x33C7, 0, 3 | DECOMP_COMPAT, 3381}, + {0x33C8, 0, 2 | DECOMP_COMPAT, 3384}, + {0x33C9, 0, 2 | DECOMP_COMPAT, 3386}, + {0x33CA, 0, 2 | DECOMP_COMPAT, 3388}, + {0x33CB, 0, 2 | DECOMP_COMPAT, 3390}, + {0x33CC, 0, 2 | DECOMP_COMPAT, 3392}, + {0x33CD, 0, 2 | DECOMP_COMPAT, 3394}, + {0x33CE, 0, 2 | DECOMP_COMPAT, 3396}, + {0x33CF, 0, 2 | DECOMP_COMPAT, 3398}, + {0x33D0, 0, 2 | DECOMP_COMPAT, 3400}, + {0x33D1, 0, 2 | DECOMP_COMPAT, 3402}, + {0x33D2, 0, 3 | DECOMP_COMPAT, 3404}, + {0x33D3, 0, 2 | DECOMP_COMPAT, 3407}, + {0x33D4, 0, 2 | DECOMP_COMPAT, 3409}, + {0x33D5, 0, 3 | DECOMP_COMPAT, 3411}, + {0x33D6, 0, 3 | DECOMP_COMPAT, 3414}, + {0x33D7, 0, 2 | DECOMP_COMPAT, 3417}, + {0x33D8, 0, 4 | DECOMP_COMPAT, 3419}, + {0x33D9, 0, 3 | DECOMP_COMPAT, 3423}, + {0x33DA, 0, 2 | DECOMP_COMPAT, 3426}, + {0x33DB, 0, 2 | DECOMP_COMPAT, 3428}, + {0x33DC, 0, 2 | DECOMP_COMPAT, 3430}, + {0x33DD, 0, 2 | DECOMP_COMPAT, 3432}, + {0x33DE, 0, 3 | DECOMP_COMPAT, 3434}, + {0x33DF, 0, 3 | DECOMP_COMPAT, 3437}, + {0x33E0, 0, 2 | DECOMP_COMPAT, 3440}, + {0x33E1, 0, 2 | DECOMP_COMPAT, 3442}, + {0x33E2, 0, 2 | DECOMP_COMPAT, 3444}, + {0x33E3, 0, 2 | DECOMP_COMPAT, 3446}, + {0x33E4, 0, 2 | DECOMP_COMPAT, 3448}, + {0x33E5, 0, 2 | DECOMP_COMPAT, 3450}, + {0x33E6, 0, 2 | DECOMP_COMPAT, 3452}, + {0x33E7, 0, 2 | DECOMP_COMPAT, 3454}, + {0x33E8, 0, 2 | DECOMP_COMPAT, 3456}, + {0x33E9, 0, 3 | DECOMP_COMPAT, 3458}, + {0x33EA, 0, 3 | DECOMP_COMPAT, 3461}, + {0x33EB, 0, 3 | DECOMP_COMPAT, 3464}, + {0x33EC, 0, 3 | DECOMP_COMPAT, 3467}, + {0x33ED, 0, 3 | DECOMP_COMPAT, 3470}, + {0x33EE, 0, 3 | DECOMP_COMPAT, 3473}, + {0x33EF, 0, 3 | DECOMP_COMPAT, 3476}, + {0x33F0, 0, 3 | DECOMP_COMPAT, 3479}, + {0x33F1, 0, 3 | DECOMP_COMPAT, 3482}, + {0x33F2, 0, 3 | DECOMP_COMPAT, 3485}, + {0x33F3, 0, 3 | DECOMP_COMPAT, 3488}, + {0x33F4, 0, 3 | DECOMP_COMPAT, 3491}, + {0x33F5, 0, 3 | DECOMP_COMPAT, 3494}, + {0x33F6, 0, 3 | DECOMP_COMPAT, 3497}, + {0x33F7, 0, 3 | DECOMP_COMPAT, 3500}, + {0x33F8, 0, 3 | DECOMP_COMPAT, 3503}, + {0x33F9, 0, 3 | DECOMP_COMPAT, 3506}, + {0x33FA, 0, 3 | DECOMP_COMPAT, 3509}, + {0x33FB, 0, 3 | DECOMP_COMPAT, 3512}, + {0x33FC, 0, 3 | DECOMP_COMPAT, 3515}, + {0x33FD, 0, 3 | DECOMP_COMPAT, 3518}, + {0x33FE, 0, 3 | DECOMP_COMPAT, 3521}, + {0x33FF, 0, 3 | DECOMP_COMPAT, 3524}, + {0xA66F, 230, 0, 0}, + {0xA674, 230, 0, 0}, + {0xA675, 230, 0, 0}, + {0xA676, 230, 0, 0}, + {0xA677, 230, 0, 0}, + {0xA678, 230, 0, 0}, + {0xA679, 230, 0, 0}, + {0xA67A, 230, 0, 0}, + {0xA67B, 230, 0, 0}, + {0xA67C, 230, 0, 0}, + {0xA67D, 230, 0, 0}, + {0xA69C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044A}, + {0xA69D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x044C}, + {0xA69E, 230, 0, 0}, + {0xA69F, 230, 0, 0}, + {0xA6F0, 230, 0, 0}, + {0xA6F1, 230, 0, 0}, + {0xA770, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA76F}, + {0xA7F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0xA7F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0xA7F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0xA7F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0126}, + {0xA7F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0153}, + {0xA806, 9, 0, 0}, + {0xA82C, 9, 0, 0}, + {0xA8C4, 9, 0, 0}, + {0xA8E0, 230, 0, 0}, + {0xA8E1, 230, 0, 0}, + {0xA8E2, 230, 0, 0}, + {0xA8E3, 230, 0, 0}, + {0xA8E4, 230, 0, 0}, + {0xA8E5, 230, 0, 0}, + {0xA8E6, 230, 0, 0}, + {0xA8E7, 230, 0, 0}, + {0xA8E8, 230, 0, 0}, + {0xA8E9, 230, 0, 0}, + {0xA8EA, 230, 0, 0}, + {0xA8EB, 230, 0, 0}, + {0xA8EC, 230, 0, 0}, + {0xA8ED, 230, 0, 0}, + {0xA8EE, 230, 0, 0}, + {0xA8EF, 230, 0, 0}, + {0xA8F0, 230, 0, 0}, + {0xA8F1, 230, 0, 0}, + {0xA92B, 220, 0, 0}, + {0xA92C, 220, 0, 0}, + {0xA92D, 220, 0, 0}, + {0xA953, 9, 0, 0}, + {0xA9B3, 7, 0, 0}, + {0xA9C0, 9, 0, 0}, + {0xAAB0, 230, 0, 0}, + {0xAAB2, 230, 0, 0}, + {0xAAB3, 230, 0, 0}, + {0xAAB4, 220, 0, 0}, + {0xAAB7, 230, 0, 0}, + {0xAAB8, 230, 0, 0}, + {0xAABE, 230, 0, 0}, + {0xAABF, 230, 0, 0}, + {0xAAC1, 230, 0, 0}, + {0xAAF6, 9, 0, 0}, + {0xAB5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA727}, + {0xAB5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB37}, + {0xAB5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026B}, + {0xAB5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB52}, + {0xAB69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028D}, + {0xABED, 9, 0, 0}, + {0xF900, 0, 1 | DECOMP_INLINE, 0x8C48}, + {0xF901, 0, 1 | DECOMP_INLINE, 0x66F4}, + {0xF902, 0, 1 | DECOMP_INLINE, 0x8ECA}, + {0xF903, 0, 1 | DECOMP_INLINE, 0x8CC8}, + {0xF904, 0, 1 | DECOMP_INLINE, 0x6ED1}, + {0xF905, 0, 1 | DECOMP_INLINE, 0x4E32}, + {0xF906, 0, 1 | DECOMP_INLINE, 0x53E5}, + {0xF907, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xF908, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xF909, 0, 1 | DECOMP_INLINE, 0x5951}, + {0xF90A, 0, 1 | DECOMP_INLINE, 0x91D1}, + {0xF90B, 0, 1 | DECOMP_INLINE, 0x5587}, + {0xF90C, 0, 1 | DECOMP_INLINE, 0x5948}, + {0xF90D, 0, 1 | DECOMP_INLINE, 0x61F6}, + {0xF90E, 0, 1 | DECOMP_INLINE, 0x7669}, + {0xF90F, 0, 1 | DECOMP_INLINE, 0x7F85}, + {0xF910, 0, 1 | DECOMP_INLINE, 0x863F}, + {0xF911, 0, 1 | DECOMP_INLINE, 0x87BA}, + {0xF912, 0, 1 | DECOMP_INLINE, 0x88F8}, + {0xF913, 0, 1 | DECOMP_INLINE, 0x908F}, + {0xF914, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF915, 0, 1 | DECOMP_INLINE, 0x6D1B}, + {0xF916, 0, 1 | DECOMP_INLINE, 0x70D9}, + {0xF917, 0, 1 | DECOMP_INLINE, 0x73DE}, + {0xF918, 0, 1 | DECOMP_INLINE, 0x843D}, + {0xF919, 0, 1 | DECOMP_INLINE, 0x916A}, + {0xF91A, 0, 1 | DECOMP_INLINE, 0x99F1}, + {0xF91B, 0, 1 | DECOMP_INLINE, 0x4E82}, + {0xF91C, 0, 1 | DECOMP_INLINE, 0x5375}, + {0xF91D, 0, 1 | DECOMP_INLINE, 0x6B04}, + {0xF91E, 0, 1 | DECOMP_INLINE, 0x721B}, + {0xF91F, 0, 1 | DECOMP_INLINE, 0x862D}, + {0xF920, 0, 1 | DECOMP_INLINE, 0x9E1E}, + {0xF921, 0, 1 | DECOMP_INLINE, 0x5D50}, + {0xF922, 0, 1 | DECOMP_INLINE, 0x6FEB}, + {0xF923, 0, 1 | DECOMP_INLINE, 0x85CD}, + {0xF924, 0, 1 | DECOMP_INLINE, 0x8964}, + {0xF925, 0, 1 | DECOMP_INLINE, 0x62C9}, + {0xF926, 0, 1 | DECOMP_INLINE, 0x81D8}, + {0xF927, 0, 1 | DECOMP_INLINE, 0x881F}, + {0xF928, 0, 1 | DECOMP_INLINE, 0x5ECA}, + {0xF929, 0, 1 | DECOMP_INLINE, 0x6717}, + {0xF92A, 0, 1 | DECOMP_INLINE, 0x6D6A}, + {0xF92B, 0, 1 | DECOMP_INLINE, 0x72FC}, + {0xF92C, 0, 1 | DECOMP_INLINE, 0x90CE}, + {0xF92D, 0, 1 | DECOMP_INLINE, 0x4F86}, + {0xF92E, 0, 1 | DECOMP_INLINE, 0x51B7}, + {0xF92F, 0, 1 | DECOMP_INLINE, 0x52DE}, + {0xF930, 0, 1 | DECOMP_INLINE, 0x64C4}, + {0xF931, 0, 1 | DECOMP_INLINE, 0x6AD3}, + {0xF932, 0, 1 | DECOMP_INLINE, 0x7210}, + {0xF933, 0, 1 | DECOMP_INLINE, 0x76E7}, + {0xF934, 0, 1 | DECOMP_INLINE, 0x8001}, + {0xF935, 0, 1 | DECOMP_INLINE, 0x8606}, + {0xF936, 0, 1 | DECOMP_INLINE, 0x865C}, + {0xF937, 0, 1 | DECOMP_INLINE, 0x8DEF}, + {0xF938, 0, 1 | DECOMP_INLINE, 0x9732}, + {0xF939, 0, 1 | DECOMP_INLINE, 0x9B6F}, + {0xF93A, 0, 1 | DECOMP_INLINE, 0x9DFA}, + {0xF93B, 0, 1 | DECOMP_INLINE, 0x788C}, + {0xF93C, 0, 1 | DECOMP_INLINE, 0x797F}, + {0xF93D, 0, 1 | DECOMP_INLINE, 0x7DA0}, + {0xF93E, 0, 1 | DECOMP_INLINE, 0x83C9}, + {0xF93F, 0, 1 | DECOMP_INLINE, 0x9304}, + {0xF940, 0, 1 | DECOMP_INLINE, 0x9E7F}, + {0xF941, 0, 1 | DECOMP_INLINE, 0x8AD6}, + {0xF942, 0, 1 | DECOMP_INLINE, 0x58DF}, + {0xF943, 0, 1 | DECOMP_INLINE, 0x5F04}, + {0xF944, 0, 1 | DECOMP_INLINE, 0x7C60}, + {0xF945, 0, 1 | DECOMP_INLINE, 0x807E}, + {0xF946, 0, 1 | DECOMP_INLINE, 0x7262}, + {0xF947, 0, 1 | DECOMP_INLINE, 0x78CA}, + {0xF948, 0, 1 | DECOMP_INLINE, 0x8CC2}, + {0xF949, 0, 1 | DECOMP_INLINE, 0x96F7}, + {0xF94A, 0, 1 | DECOMP_INLINE, 0x58D8}, + {0xF94B, 0, 1 | DECOMP_INLINE, 0x5C62}, + {0xF94C, 0, 1 | DECOMP_INLINE, 0x6A13}, + {0xF94D, 0, 1 | DECOMP_INLINE, 0x6DDA}, + {0xF94E, 0, 1 | DECOMP_INLINE, 0x6F0F}, + {0xF94F, 0, 1 | DECOMP_INLINE, 0x7D2F}, + {0xF950, 0, 1 | DECOMP_INLINE, 0x7E37}, + {0xF951, 0, 1 | DECOMP_INLINE, 0x964B}, + {0xF952, 0, 1 | DECOMP_INLINE, 0x52D2}, + {0xF953, 0, 1 | DECOMP_INLINE, 0x808B}, + {0xF954, 0, 1 | DECOMP_INLINE, 0x51DC}, + {0xF955, 0, 1 | DECOMP_INLINE, 0x51CC}, + {0xF956, 0, 1 | DECOMP_INLINE, 0x7A1C}, + {0xF957, 0, 1 | DECOMP_INLINE, 0x7DBE}, + {0xF958, 0, 1 | DECOMP_INLINE, 0x83F1}, + {0xF959, 0, 1 | DECOMP_INLINE, 0x9675}, + {0xF95A, 0, 1 | DECOMP_INLINE, 0x8B80}, + {0xF95B, 0, 1 | DECOMP_INLINE, 0x62CF}, + {0xF95C, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF95D, 0, 1 | DECOMP_INLINE, 0x8AFE}, + {0xF95E, 0, 1 | DECOMP_INLINE, 0x4E39}, + {0xF95F, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0xF960, 0, 1 | DECOMP_INLINE, 0x6012}, + {0xF961, 0, 1 | DECOMP_INLINE, 0x7387}, + {0xF962, 0, 1 | DECOMP_INLINE, 0x7570}, + {0xF963, 0, 1 | DECOMP_INLINE, 0x5317}, + {0xF964, 0, 1 | DECOMP_INLINE, 0x78FB}, + {0xF965, 0, 1 | DECOMP_INLINE, 0x4FBF}, + {0xF966, 0, 1 | DECOMP_INLINE, 0x5FA9}, + {0xF967, 0, 1 | DECOMP_INLINE, 0x4E0D}, + {0xF968, 0, 1 | DECOMP_INLINE, 0x6CCC}, + {0xF969, 0, 1 | DECOMP_INLINE, 0x6578}, + {0xF96A, 0, 1 | DECOMP_INLINE, 0x7D22}, + {0xF96B, 0, 1 | DECOMP_INLINE, 0x53C3}, + {0xF96C, 0, 1 | DECOMP_INLINE, 0x585E}, + {0xF96D, 0, 1 | DECOMP_INLINE, 0x7701}, + {0xF96E, 0, 1 | DECOMP_INLINE, 0x8449}, + {0xF96F, 0, 1 | DECOMP_INLINE, 0x8AAA}, + {0xF970, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0xF971, 0, 1 | DECOMP_INLINE, 0x8FB0}, + {0xF972, 0, 1 | DECOMP_INLINE, 0x6C88}, + {0xF973, 0, 1 | DECOMP_INLINE, 0x62FE}, + {0xF974, 0, 1 | DECOMP_INLINE, 0x82E5}, + {0xF975, 0, 1 | DECOMP_INLINE, 0x63A0}, + {0xF976, 0, 1 | DECOMP_INLINE, 0x7565}, + {0xF977, 0, 1 | DECOMP_INLINE, 0x4EAE}, + {0xF978, 0, 1 | DECOMP_INLINE, 0x5169}, + {0xF979, 0, 1 | DECOMP_INLINE, 0x51C9}, + {0xF97A, 0, 1 | DECOMP_INLINE, 0x6881}, + {0xF97B, 0, 1 | DECOMP_INLINE, 0x7CE7}, + {0xF97C, 0, 1 | DECOMP_INLINE, 0x826F}, + {0xF97D, 0, 1 | DECOMP_INLINE, 0x8AD2}, + {0xF97E, 0, 1 | DECOMP_INLINE, 0x91CF}, + {0xF97F, 0, 1 | DECOMP_INLINE, 0x52F5}, + {0xF980, 0, 1 | DECOMP_INLINE, 0x5442}, + {0xF981, 0, 1 | DECOMP_INLINE, 0x5973}, + {0xF982, 0, 1 | DECOMP_INLINE, 0x5EEC}, + {0xF983, 0, 1 | DECOMP_INLINE, 0x65C5}, + {0xF984, 0, 1 | DECOMP_INLINE, 0x6FFE}, + {0xF985, 0, 1 | DECOMP_INLINE, 0x792A}, + {0xF986, 0, 1 | DECOMP_INLINE, 0x95AD}, + {0xF987, 0, 1 | DECOMP_INLINE, 0x9A6A}, + {0xF988, 0, 1 | DECOMP_INLINE, 0x9E97}, + {0xF989, 0, 1 | DECOMP_INLINE, 0x9ECE}, + {0xF98A, 0, 1 | DECOMP_INLINE, 0x529B}, + {0xF98B, 0, 1 | DECOMP_INLINE, 0x66C6}, + {0xF98C, 0, 1 | DECOMP_INLINE, 0x6B77}, + {0xF98D, 0, 1 | DECOMP_INLINE, 0x8F62}, + {0xF98E, 0, 1 | DECOMP_INLINE, 0x5E74}, + {0xF98F, 0, 1 | DECOMP_INLINE, 0x6190}, + {0xF990, 0, 1 | DECOMP_INLINE, 0x6200}, + {0xF991, 0, 1 | DECOMP_INLINE, 0x649A}, + {0xF992, 0, 1 | DECOMP_INLINE, 0x6F23}, + {0xF993, 0, 1 | DECOMP_INLINE, 0x7149}, + {0xF994, 0, 1 | DECOMP_INLINE, 0x7489}, + {0xF995, 0, 1 | DECOMP_INLINE, 0x79CA}, + {0xF996, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xF997, 0, 1 | DECOMP_INLINE, 0x806F}, + {0xF998, 0, 1 | DECOMP_INLINE, 0x8F26}, + {0xF999, 0, 1 | DECOMP_INLINE, 0x84EE}, + {0xF99A, 0, 1 | DECOMP_INLINE, 0x9023}, + {0xF99B, 0, 1 | DECOMP_INLINE, 0x934A}, + {0xF99C, 0, 1 | DECOMP_INLINE, 0x5217}, + {0xF99D, 0, 1 | DECOMP_INLINE, 0x52A3}, + {0xF99E, 0, 1 | DECOMP_INLINE, 0x54BD}, + {0xF99F, 0, 1 | DECOMP_INLINE, 0x70C8}, + {0xF9A0, 0, 1 | DECOMP_INLINE, 0x88C2}, + {0xF9A1, 0, 1 | DECOMP_INLINE, 0x8AAA}, + {0xF9A2, 0, 1 | DECOMP_INLINE, 0x5EC9}, + {0xF9A3, 0, 1 | DECOMP_INLINE, 0x5FF5}, + {0xF9A4, 0, 1 | DECOMP_INLINE, 0x637B}, + {0xF9A5, 0, 1 | DECOMP_INLINE, 0x6BAE}, + {0xF9A6, 0, 1 | DECOMP_INLINE, 0x7C3E}, + {0xF9A7, 0, 1 | DECOMP_INLINE, 0x7375}, + {0xF9A8, 0, 1 | DECOMP_INLINE, 0x4EE4}, + {0xF9A9, 0, 1 | DECOMP_INLINE, 0x56F9}, + {0xF9AA, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0xF9AB, 0, 1 | DECOMP_INLINE, 0x5DBA}, + {0xF9AC, 0, 1 | DECOMP_INLINE, 0x601C}, + {0xF9AD, 0, 1 | DECOMP_INLINE, 0x73B2}, + {0xF9AE, 0, 1 | DECOMP_INLINE, 0x7469}, + {0xF9AF, 0, 1 | DECOMP_INLINE, 0x7F9A}, + {0xF9B0, 0, 1 | DECOMP_INLINE, 0x8046}, + {0xF9B1, 0, 1 | DECOMP_INLINE, 0x9234}, + {0xF9B2, 0, 1 | DECOMP_INLINE, 0x96F6}, + {0xF9B3, 0, 1 | DECOMP_INLINE, 0x9748}, + {0xF9B4, 0, 1 | DECOMP_INLINE, 0x9818}, + {0xF9B5, 0, 1 | DECOMP_INLINE, 0x4F8B}, + {0xF9B6, 0, 1 | DECOMP_INLINE, 0x79AE}, + {0xF9B7, 0, 1 | DECOMP_INLINE, 0x91B4}, + {0xF9B8, 0, 1 | DECOMP_INLINE, 0x96B8}, + {0xF9B9, 0, 1 | DECOMP_INLINE, 0x60E1}, + {0xF9BA, 0, 1 | DECOMP_INLINE, 0x4E86}, + {0xF9BB, 0, 1 | DECOMP_INLINE, 0x50DA}, + {0xF9BC, 0, 1 | DECOMP_INLINE, 0x5BEE}, + {0xF9BD, 0, 1 | DECOMP_INLINE, 0x5C3F}, + {0xF9BE, 0, 1 | DECOMP_INLINE, 0x6599}, + {0xF9BF, 0, 1 | DECOMP_INLINE, 0x6A02}, + {0xF9C0, 0, 1 | DECOMP_INLINE, 0x71CE}, + {0xF9C1, 0, 1 | DECOMP_INLINE, 0x7642}, + {0xF9C2, 0, 1 | DECOMP_INLINE, 0x84FC}, + {0xF9C3, 0, 1 | DECOMP_INLINE, 0x907C}, + {0xF9C4, 0, 1 | DECOMP_INLINE, 0x9F8D}, + {0xF9C5, 0, 1 | DECOMP_INLINE, 0x6688}, + {0xF9C6, 0, 1 | DECOMP_INLINE, 0x962E}, + {0xF9C7, 0, 1 | DECOMP_INLINE, 0x5289}, + {0xF9C8, 0, 1 | DECOMP_INLINE, 0x677B}, + {0xF9C9, 0, 1 | DECOMP_INLINE, 0x67F3}, + {0xF9CA, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0xF9CB, 0, 1 | DECOMP_INLINE, 0x6E9C}, + {0xF9CC, 0, 1 | DECOMP_INLINE, 0x7409}, + {0xF9CD, 0, 1 | DECOMP_INLINE, 0x7559}, + {0xF9CE, 0, 1 | DECOMP_INLINE, 0x786B}, + {0xF9CF, 0, 1 | DECOMP_INLINE, 0x7D10}, + {0xF9D0, 0, 1 | DECOMP_INLINE, 0x985E}, + {0xF9D1, 0, 1 | DECOMP_INLINE, 0x516D}, + {0xF9D2, 0, 1 | DECOMP_INLINE, 0x622E}, + {0xF9D3, 0, 1 | DECOMP_INLINE, 0x9678}, + {0xF9D4, 0, 1 | DECOMP_INLINE, 0x502B}, + {0xF9D5, 0, 1 | DECOMP_INLINE, 0x5D19}, + {0xF9D6, 0, 1 | DECOMP_INLINE, 0x6DEA}, + {0xF9D7, 0, 1 | DECOMP_INLINE, 0x8F2A}, + {0xF9D8, 0, 1 | DECOMP_INLINE, 0x5F8B}, + {0xF9D9, 0, 1 | DECOMP_INLINE, 0x6144}, + {0xF9DA, 0, 1 | DECOMP_INLINE, 0x6817}, + {0xF9DB, 0, 1 | DECOMP_INLINE, 0x7387}, + {0xF9DC, 0, 1 | DECOMP_INLINE, 0x9686}, + {0xF9DD, 0, 1 | DECOMP_INLINE, 0x5229}, + {0xF9DE, 0, 1 | DECOMP_INLINE, 0x540F}, + {0xF9DF, 0, 1 | DECOMP_INLINE, 0x5C65}, + {0xF9E0, 0, 1 | DECOMP_INLINE, 0x6613}, + {0xF9E1, 0, 1 | DECOMP_INLINE, 0x674E}, + {0xF9E2, 0, 1 | DECOMP_INLINE, 0x68A8}, + {0xF9E3, 0, 1 | DECOMP_INLINE, 0x6CE5}, + {0xF9E4, 0, 1 | DECOMP_INLINE, 0x7406}, + {0xF9E5, 0, 1 | DECOMP_INLINE, 0x75E2}, + {0xF9E6, 0, 1 | DECOMP_INLINE, 0x7F79}, + {0xF9E7, 0, 1 | DECOMP_INLINE, 0x88CF}, + {0xF9E8, 0, 1 | DECOMP_INLINE, 0x88E1}, + {0xF9E9, 0, 1 | DECOMP_INLINE, 0x91CC}, + {0xF9EA, 0, 1 | DECOMP_INLINE, 0x96E2}, + {0xF9EB, 0, 1 | DECOMP_INLINE, 0x533F}, + {0xF9EC, 0, 1 | DECOMP_INLINE, 0x6EBA}, + {0xF9ED, 0, 1 | DECOMP_INLINE, 0x541D}, + {0xF9EE, 0, 1 | DECOMP_INLINE, 0x71D0}, + {0xF9EF, 0, 1 | DECOMP_INLINE, 0x7498}, + {0xF9F0, 0, 1 | DECOMP_INLINE, 0x85FA}, + {0xF9F1, 0, 1 | DECOMP_INLINE, 0x96A3}, + {0xF9F2, 0, 1 | DECOMP_INLINE, 0x9C57}, + {0xF9F3, 0, 1 | DECOMP_INLINE, 0x9E9F}, + {0xF9F4, 0, 1 | DECOMP_INLINE, 0x6797}, + {0xF9F5, 0, 1 | DECOMP_INLINE, 0x6DCB}, + {0xF9F6, 0, 1 | DECOMP_INLINE, 0x81E8}, + {0xF9F7, 0, 1 | DECOMP_INLINE, 0x7ACB}, + {0xF9F8, 0, 1 | DECOMP_INLINE, 0x7B20}, + {0xF9F9, 0, 1 | DECOMP_INLINE, 0x7C92}, + {0xF9FA, 0, 1 | DECOMP_INLINE, 0x72C0}, + {0xF9FB, 0, 1 | DECOMP_INLINE, 0x7099}, + {0xF9FC, 0, 1 | DECOMP_INLINE, 0x8B58}, + {0xF9FD, 0, 1 | DECOMP_INLINE, 0x4EC0}, + {0xF9FE, 0, 1 | DECOMP_INLINE, 0x8336}, + {0xF9FF, 0, 1 | DECOMP_INLINE, 0x523A}, + {0xFA00, 0, 1 | DECOMP_INLINE, 0x5207}, + {0xFA01, 0, 1 | DECOMP_INLINE, 0x5EA6}, + {0xFA02, 0, 1 | DECOMP_INLINE, 0x62D3}, + {0xFA03, 0, 1 | DECOMP_INLINE, 0x7CD6}, + {0xFA04, 0, 1 | DECOMP_INLINE, 0x5B85}, + {0xFA05, 0, 1 | DECOMP_INLINE, 0x6D1E}, + {0xFA06, 0, 1 | DECOMP_INLINE, 0x66B4}, + {0xFA07, 0, 1 | DECOMP_INLINE, 0x8F3B}, + {0xFA08, 0, 1 | DECOMP_INLINE, 0x884C}, + {0xFA09, 0, 1 | DECOMP_INLINE, 0x964D}, + {0xFA0A, 0, 1 | DECOMP_INLINE, 0x898B}, + {0xFA0B, 0, 1 | DECOMP_INLINE, 0x5ED3}, + {0xFA0C, 0, 1 | DECOMP_INLINE, 0x5140}, + {0xFA0D, 0, 1 | DECOMP_INLINE, 0x55C0}, + {0xFA10, 0, 1 | DECOMP_INLINE, 0x585A}, + {0xFA12, 0, 1 | DECOMP_INLINE, 0x6674}, + {0xFA15, 0, 1 | DECOMP_INLINE, 0x51DE}, + {0xFA16, 0, 1 | DECOMP_INLINE, 0x732A}, + {0xFA17, 0, 1 | DECOMP_INLINE, 0x76CA}, + {0xFA18, 0, 1 | DECOMP_INLINE, 0x793C}, + {0xFA19, 0, 1 | DECOMP_INLINE, 0x795E}, + {0xFA1A, 0, 1 | DECOMP_INLINE, 0x7965}, + {0xFA1B, 0, 1 | DECOMP_INLINE, 0x798F}, + {0xFA1C, 0, 1 | DECOMP_INLINE, 0x9756}, + {0xFA1D, 0, 1 | DECOMP_INLINE, 0x7CBE}, + {0xFA1E, 0, 1 | DECOMP_INLINE, 0x7FBD}, + {0xFA20, 0, 1 | DECOMP_INLINE, 0x8612}, + {0xFA22, 0, 1 | DECOMP_INLINE, 0x8AF8}, + {0xFA25, 0, 1 | DECOMP_INLINE, 0x9038}, + {0xFA26, 0, 1 | DECOMP_INLINE, 0x90FD}, + {0xFA2A, 0, 1 | DECOMP_INLINE, 0x98EF}, + {0xFA2B, 0, 1 | DECOMP_INLINE, 0x98FC}, + {0xFA2C, 0, 1 | DECOMP_INLINE, 0x9928}, + {0xFA2D, 0, 1 | DECOMP_INLINE, 0x9DB4}, + {0xFA2E, 0, 1 | DECOMP_INLINE, 0x90DE}, + {0xFA2F, 0, 1 | DECOMP_INLINE, 0x96B7}, + {0xFA30, 0, 1 | DECOMP_INLINE, 0x4FAE}, + {0xFA31, 0, 1 | DECOMP_INLINE, 0x50E7}, + {0xFA32, 0, 1 | DECOMP_INLINE, 0x514D}, + {0xFA33, 0, 1 | DECOMP_INLINE, 0x52C9}, + {0xFA34, 0, 1 | DECOMP_INLINE, 0x52E4}, + {0xFA35, 0, 1 | DECOMP_INLINE, 0x5351}, + {0xFA36, 0, 1 | DECOMP_INLINE, 0x559D}, + {0xFA37, 0, 1 | DECOMP_INLINE, 0x5606}, + {0xFA38, 0, 1 | DECOMP_INLINE, 0x5668}, + {0xFA39, 0, 1 | DECOMP_INLINE, 0x5840}, + {0xFA3A, 0, 1 | DECOMP_INLINE, 0x58A8}, + {0xFA3B, 0, 1 | DECOMP_INLINE, 0x5C64}, + {0xFA3C, 0, 1 | DECOMP_INLINE, 0x5C6E}, + {0xFA3D, 0, 1 | DECOMP_INLINE, 0x6094}, + {0xFA3E, 0, 1 | DECOMP_INLINE, 0x6168}, + {0xFA3F, 0, 1 | DECOMP_INLINE, 0x618E}, + {0xFA40, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0xFA41, 0, 1 | DECOMP_INLINE, 0x654F}, + {0xFA42, 0, 1 | DECOMP_INLINE, 0x65E2}, + {0xFA43, 0, 1 | DECOMP_INLINE, 0x6691}, + {0xFA44, 0, 1 | DECOMP_INLINE, 0x6885}, + {0xFA45, 0, 1 | DECOMP_INLINE, 0x6D77}, + {0xFA46, 0, 1 | DECOMP_INLINE, 0x6E1A}, + {0xFA47, 0, 1 | DECOMP_INLINE, 0x6F22}, + {0xFA48, 0, 1 | DECOMP_INLINE, 0x716E}, + {0xFA49, 0, 1 | DECOMP_INLINE, 0x722B}, + {0xFA4A, 0, 1 | DECOMP_INLINE, 0x7422}, + {0xFA4B, 0, 1 | DECOMP_INLINE, 0x7891}, + {0xFA4C, 0, 1 | DECOMP_INLINE, 0x793E}, + {0xFA4D, 0, 1 | DECOMP_INLINE, 0x7949}, + {0xFA4E, 0, 1 | DECOMP_INLINE, 0x7948}, + {0xFA4F, 0, 1 | DECOMP_INLINE, 0x7950}, + {0xFA50, 0, 1 | DECOMP_INLINE, 0x7956}, + {0xFA51, 0, 1 | DECOMP_INLINE, 0x795D}, + {0xFA52, 0, 1 | DECOMP_INLINE, 0x798D}, + {0xFA53, 0, 1 | DECOMP_INLINE, 0x798E}, + {0xFA54, 0, 1 | DECOMP_INLINE, 0x7A40}, + {0xFA55, 0, 1 | DECOMP_INLINE, 0x7A81}, + {0xFA56, 0, 1 | DECOMP_INLINE, 0x7BC0}, + {0xFA57, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xFA58, 0, 1 | DECOMP_INLINE, 0x7E09}, + {0xFA59, 0, 1 | DECOMP_INLINE, 0x7E41}, + {0xFA5A, 0, 1 | DECOMP_INLINE, 0x7F72}, + {0xFA5B, 0, 1 | DECOMP_INLINE, 0x8005}, + {0xFA5C, 0, 1 | DECOMP_INLINE, 0x81ED}, + {0xFA5D, 0, 1 | DECOMP_INLINE, 0x8279}, + {0xFA5E, 0, 1 | DECOMP_INLINE, 0x8279}, + {0xFA5F, 0, 1 | DECOMP_INLINE, 0x8457}, + {0xFA60, 0, 1 | DECOMP_INLINE, 0x8910}, + {0xFA61, 0, 1 | DECOMP_INLINE, 0x8996}, + {0xFA62, 0, 1 | DECOMP_INLINE, 0x8B01}, + {0xFA63, 0, 1 | DECOMP_INLINE, 0x8B39}, + {0xFA64, 0, 1 | DECOMP_INLINE, 0x8CD3}, + {0xFA65, 0, 1 | DECOMP_INLINE, 0x8D08}, + {0xFA66, 0, 1 | DECOMP_INLINE, 0x8FB6}, + {0xFA67, 0, 1 | DECOMP_INLINE, 0x9038}, + {0xFA68, 0, 1 | DECOMP_INLINE, 0x96E3}, + {0xFA69, 0, 1 | DECOMP_INLINE, 0x97FF}, + {0xFA6A, 0, 1 | DECOMP_INLINE, 0x983B}, + {0xFA6B, 0, 1 | DECOMP_INLINE, 0x6075}, + {0xFA6C, 0, 1, 3527}, + {0xFA6D, 0, 1 | DECOMP_INLINE, 0x8218}, + {0xFA70, 0, 1 | DECOMP_INLINE, 0x4E26}, + {0xFA71, 0, 1 | DECOMP_INLINE, 0x51B5}, + {0xFA72, 0, 1 | DECOMP_INLINE, 0x5168}, + {0xFA73, 0, 1 | DECOMP_INLINE, 0x4F80}, + {0xFA74, 0, 1 | DECOMP_INLINE, 0x5145}, + {0xFA75, 0, 1 | DECOMP_INLINE, 0x5180}, + {0xFA76, 0, 1 | DECOMP_INLINE, 0x52C7}, + {0xFA77, 0, 1 | DECOMP_INLINE, 0x52FA}, + {0xFA78, 0, 1 | DECOMP_INLINE, 0x559D}, + {0xFA79, 0, 1 | DECOMP_INLINE, 0x5555}, + {0xFA7A, 0, 1 | DECOMP_INLINE, 0x5599}, + {0xFA7B, 0, 1 | DECOMP_INLINE, 0x55E2}, + {0xFA7C, 0, 1 | DECOMP_INLINE, 0x585A}, + {0xFA7D, 0, 1 | DECOMP_INLINE, 0x58B3}, + {0xFA7E, 0, 1 | DECOMP_INLINE, 0x5944}, + {0xFA7F, 0, 1 | DECOMP_INLINE, 0x5954}, + {0xFA80, 0, 1 | DECOMP_INLINE, 0x5A62}, + {0xFA81, 0, 1 | DECOMP_INLINE, 0x5B28}, + {0xFA82, 0, 1 | DECOMP_INLINE, 0x5ED2}, + {0xFA83, 0, 1 | DECOMP_INLINE, 0x5ED9}, + {0xFA84, 0, 1 | DECOMP_INLINE, 0x5F69}, + {0xFA85, 0, 1 | DECOMP_INLINE, 0x5FAD}, + {0xFA86, 0, 1 | DECOMP_INLINE, 0x60D8}, + {0xFA87, 0, 1 | DECOMP_INLINE, 0x614E}, + {0xFA88, 0, 1 | DECOMP_INLINE, 0x6108}, + {0xFA89, 0, 1 | DECOMP_INLINE, 0x618E}, + {0xFA8A, 0, 1 | DECOMP_INLINE, 0x6160}, + {0xFA8B, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0xFA8C, 0, 1 | DECOMP_INLINE, 0x6234}, + {0xFA8D, 0, 1 | DECOMP_INLINE, 0x63C4}, + {0xFA8E, 0, 1 | DECOMP_INLINE, 0x641C}, + {0xFA8F, 0, 1 | DECOMP_INLINE, 0x6452}, + {0xFA90, 0, 1 | DECOMP_INLINE, 0x6556}, + {0xFA91, 0, 1 | DECOMP_INLINE, 0x6674}, + {0xFA92, 0, 1 | DECOMP_INLINE, 0x6717}, + {0xFA93, 0, 1 | DECOMP_INLINE, 0x671B}, + {0xFA94, 0, 1 | DECOMP_INLINE, 0x6756}, + {0xFA95, 0, 1 | DECOMP_INLINE, 0x6B79}, + {0xFA96, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0xFA97, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0xFA98, 0, 1 | DECOMP_INLINE, 0x6EDB}, + {0xFA99, 0, 1 | DECOMP_INLINE, 0x6ECB}, + {0xFA9A, 0, 1 | DECOMP_INLINE, 0x6F22}, + {0xFA9B, 0, 1 | DECOMP_INLINE, 0x701E}, + {0xFA9C, 0, 1 | DECOMP_INLINE, 0x716E}, + {0xFA9D, 0, 1 | DECOMP_INLINE, 0x77A7}, + {0xFA9E, 0, 1 | DECOMP_INLINE, 0x7235}, + {0xFA9F, 0, 1 | DECOMP_INLINE, 0x72AF}, + {0xFAA0, 0, 1 | DECOMP_INLINE, 0x732A}, + {0xFAA1, 0, 1 | DECOMP_INLINE, 0x7471}, + {0xFAA2, 0, 1 | DECOMP_INLINE, 0x7506}, + {0xFAA3, 0, 1 | DECOMP_INLINE, 0x753B}, + {0xFAA4, 0, 1 | DECOMP_INLINE, 0x761D}, + {0xFAA5, 0, 1 | DECOMP_INLINE, 0x761F}, + {0xFAA6, 0, 1 | DECOMP_INLINE, 0x76CA}, + {0xFAA7, 0, 1 | DECOMP_INLINE, 0x76DB}, + {0xFAA8, 0, 1 | DECOMP_INLINE, 0x76F4}, + {0xFAA9, 0, 1 | DECOMP_INLINE, 0x774A}, + {0xFAAA, 0, 1 | DECOMP_INLINE, 0x7740}, + {0xFAAB, 0, 1 | DECOMP_INLINE, 0x78CC}, + {0xFAAC, 0, 1 | DECOMP_INLINE, 0x7AB1}, + {0xFAAD, 0, 1 | DECOMP_INLINE, 0x7BC0}, + {0xFAAE, 0, 1 | DECOMP_INLINE, 0x7C7B}, + {0xFAAF, 0, 1 | DECOMP_INLINE, 0x7D5B}, + {0xFAB0, 0, 1 | DECOMP_INLINE, 0x7DF4}, + {0xFAB1, 0, 1 | DECOMP_INLINE, 0x7F3E}, + {0xFAB2, 0, 1 | DECOMP_INLINE, 0x8005}, + {0xFAB3, 0, 1 | DECOMP_INLINE, 0x8352}, + {0xFAB4, 0, 1 | DECOMP_INLINE, 0x83EF}, + {0xFAB5, 0, 1 | DECOMP_INLINE, 0x8779}, + {0xFAB6, 0, 1 | DECOMP_INLINE, 0x8941}, + {0xFAB7, 0, 1 | DECOMP_INLINE, 0x8986}, + {0xFAB8, 0, 1 | DECOMP_INLINE, 0x8996}, + {0xFAB9, 0, 1 | DECOMP_INLINE, 0x8ABF}, + {0xFABA, 0, 1 | DECOMP_INLINE, 0x8AF8}, + {0xFABB, 0, 1 | DECOMP_INLINE, 0x8ACB}, + {0xFABC, 0, 1 | DECOMP_INLINE, 0x8B01}, + {0xFABD, 0, 1 | DECOMP_INLINE, 0x8AFE}, + {0xFABE, 0, 1 | DECOMP_INLINE, 0x8AED}, + {0xFABF, 0, 1 | DECOMP_INLINE, 0x8B39}, + {0xFAC0, 0, 1 | DECOMP_INLINE, 0x8B8A}, + {0xFAC1, 0, 1 | DECOMP_INLINE, 0x8D08}, + {0xFAC2, 0, 1 | DECOMP_INLINE, 0x8F38}, + {0xFAC3, 0, 1 | DECOMP_INLINE, 0x9072}, + {0xFAC4, 0, 1 | DECOMP_INLINE, 0x9199}, + {0xFAC5, 0, 1 | DECOMP_INLINE, 0x9276}, + {0xFAC6, 0, 1 | DECOMP_INLINE, 0x967C}, + {0xFAC7, 0, 1 | DECOMP_INLINE, 0x96E3}, + {0xFAC8, 0, 1 | DECOMP_INLINE, 0x9756}, + {0xFAC9, 0, 1 | DECOMP_INLINE, 0x97DB}, + {0xFACA, 0, 1 | DECOMP_INLINE, 0x97FF}, + {0xFACB, 0, 1 | DECOMP_INLINE, 0x980B}, + {0xFACC, 0, 1 | DECOMP_INLINE, 0x983B}, + {0xFACD, 0, 1 | DECOMP_INLINE, 0x9B12}, + {0xFACE, 0, 1 | DECOMP_INLINE, 0x9F9C}, + {0xFACF, 0, 1, 3528}, + {0xFAD0, 0, 1, 3529}, + {0xFAD1, 0, 1, 3530}, + {0xFAD2, 0, 1 | DECOMP_INLINE, 0x3B9D}, + {0xFAD3, 0, 1 | DECOMP_INLINE, 0x4018}, + {0xFAD4, 0, 1 | DECOMP_INLINE, 0x4039}, + {0xFAD5, 0, 1, 3531}, + {0xFAD6, 0, 1, 3532}, + {0xFAD7, 0, 1, 3533}, + {0xFAD8, 0, 1 | DECOMP_INLINE, 0x9F43}, + {0xFAD9, 0, 1 | DECOMP_INLINE, 0x9F8E}, + {0xFB00, 0, 2 | DECOMP_COMPAT, 3534}, + {0xFB01, 0, 2 | DECOMP_COMPAT, 3536}, + {0xFB02, 0, 2 | DECOMP_COMPAT, 3538}, + {0xFB03, 0, 3 | DECOMP_COMPAT, 3540}, + {0xFB04, 0, 3 | DECOMP_COMPAT, 3543}, + {0xFB05, 0, 2 | DECOMP_COMPAT, 3546}, + {0xFB06, 0, 2 | DECOMP_COMPAT, 3548}, + {0xFB13, 0, 2 | DECOMP_COMPAT, 3550}, + {0xFB14, 0, 2 | DECOMP_COMPAT, 3552}, + {0xFB15, 0, 2 | DECOMP_COMPAT, 3554}, + {0xFB16, 0, 2 | DECOMP_COMPAT, 3556}, + {0xFB17, 0, 2 | DECOMP_COMPAT, 3558}, + {0xFB1D, 0, 2 | DECOMP_NO_COMPOSE, 3560}, /* in exclusion list */ + {0xFB1E, 26, 0, 0}, + {0xFB1F, 0, 2 | DECOMP_NO_COMPOSE, 3562}, /* in exclusion list */ + {0xFB20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05E2}, + {0xFB21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D0}, + {0xFB22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D3}, + {0xFB23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05D4}, + {0xFB24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DB}, + {0xFB25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DC}, + {0xFB26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05DD}, + {0xFB27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05E8}, + {0xFB28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x05EA}, + {0xFB29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFB2A, 0, 2 | DECOMP_NO_COMPOSE, 3564}, /* in exclusion list */ + {0xFB2B, 0, 2 | DECOMP_NO_COMPOSE, 3566}, /* in exclusion list */ + {0xFB2C, 0, 2 | DECOMP_NO_COMPOSE, 3568}, /* in exclusion list */ + {0xFB2D, 0, 2 | DECOMP_NO_COMPOSE, 3570}, /* in exclusion list */ + {0xFB2E, 0, 2 | DECOMP_NO_COMPOSE, 3572}, /* in exclusion list */ + {0xFB2F, 0, 2 | DECOMP_NO_COMPOSE, 3574}, /* in exclusion list */ + {0xFB30, 0, 2 | DECOMP_NO_COMPOSE, 3576}, /* in exclusion list */ + {0xFB31, 0, 2 | DECOMP_NO_COMPOSE, 3578}, /* in exclusion list */ + {0xFB32, 0, 2 | DECOMP_NO_COMPOSE, 3580}, /* in exclusion list */ + {0xFB33, 0, 2 | DECOMP_NO_COMPOSE, 3582}, /* in exclusion list */ + {0xFB34, 0, 2 | DECOMP_NO_COMPOSE, 3584}, /* in exclusion list */ + {0xFB35, 0, 2 | DECOMP_NO_COMPOSE, 3586}, /* in exclusion list */ + {0xFB36, 0, 2 | DECOMP_NO_COMPOSE, 3588}, /* in exclusion list */ + {0xFB38, 0, 2 | DECOMP_NO_COMPOSE, 3590}, /* in exclusion list */ + {0xFB39, 0, 2 | DECOMP_NO_COMPOSE, 3592}, /* in exclusion list */ + {0xFB3A, 0, 2 | DECOMP_NO_COMPOSE, 3594}, /* in exclusion list */ + {0xFB3B, 0, 2 | DECOMP_NO_COMPOSE, 3596}, /* in exclusion list */ + {0xFB3C, 0, 2 | DECOMP_NO_COMPOSE, 3598}, /* in exclusion list */ + {0xFB3E, 0, 2 | DECOMP_NO_COMPOSE, 3600}, /* in exclusion list */ + {0xFB40, 0, 2 | DECOMP_NO_COMPOSE, 3602}, /* in exclusion list */ + {0xFB41, 0, 2 | DECOMP_NO_COMPOSE, 3604}, /* in exclusion list */ + {0xFB43, 0, 2 | DECOMP_NO_COMPOSE, 3606}, /* in exclusion list */ + {0xFB44, 0, 2 | DECOMP_NO_COMPOSE, 3608}, /* in exclusion list */ + {0xFB46, 0, 2 | DECOMP_NO_COMPOSE, 3610}, /* in exclusion list */ + {0xFB47, 0, 2 | DECOMP_NO_COMPOSE, 3612}, /* in exclusion list */ + {0xFB48, 0, 2 | DECOMP_NO_COMPOSE, 3614}, /* in exclusion list */ + {0xFB49, 0, 2 | DECOMP_NO_COMPOSE, 3616}, /* in exclusion list */ + {0xFB4A, 0, 2 | DECOMP_NO_COMPOSE, 3618}, /* in exclusion list */ + {0xFB4B, 0, 2 | DECOMP_NO_COMPOSE, 3620}, /* in exclusion list */ + {0xFB4C, 0, 2 | DECOMP_NO_COMPOSE, 3622}, /* in exclusion list */ + {0xFB4D, 0, 2 | DECOMP_NO_COMPOSE, 3624}, /* in exclusion list */ + {0xFB4E, 0, 2 | DECOMP_NO_COMPOSE, 3626}, /* in exclusion list */ + {0xFB4F, 0, 2 | DECOMP_COMPAT, 3628}, + {0xFB50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0671}, + {0xFB51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0671}, + {0xFB52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067B}, + {0xFB56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067E}, + {0xFB5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0680}, + {0xFB5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067A}, + {0xFB62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x067F}, + {0xFB66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0679}, + {0xFB6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A4}, + {0xFB6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A6}, + {0xFB72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0684}, + {0xFB76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0683}, + {0xFB7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0686}, + {0xFB7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0687}, + {0xFB82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068D}, + {0xFB83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068D}, + {0xFB84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068C}, + {0xFB85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068C}, + {0xFB86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068E}, + {0xFB87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x068E}, + {0xFB88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0688}, + {0xFB89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0688}, + {0xFB8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0698}, + {0xFB8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0698}, + {0xFB8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0691}, + {0xFB8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0691}, + {0xFB8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A9}, + {0xFB92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AF}, + {0xFB96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B3}, + {0xFB9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06B1}, + {0xFB9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0xFB9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0xFBA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BB}, + {0xFBA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C0}, + {0xFBA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C0}, + {0xFBA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C1}, + {0xFBAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BE}, + {0xFBAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D2}, + {0xFBAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D2}, + {0xFBB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D3}, + {0xFBB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D3}, + {0xFBD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06AD}, + {0xFBD7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C7}, + {0xFBD8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C7}, + {0xFBD9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C6}, + {0xFBDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C6}, + {0xFBDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C8}, + {0xFBDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C8}, + {0xFBDD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0677}, + {0xFBDE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CB}, + {0xFBDF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CB}, + {0xFBE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C5}, + {0xFBE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C5}, + {0xFBE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C9}, + {0xFBE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06C9}, + {0xFBE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06D0}, + {0xFBE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFBE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFBEA, 0, 2 | DECOMP_COMPAT, 3630}, + {0xFBEB, 0, 2 | DECOMP_COMPAT, 3632}, + {0xFBEC, 0, 2 | DECOMP_COMPAT, 3634}, + {0xFBED, 0, 2 | DECOMP_COMPAT, 3636}, + {0xFBEE, 0, 2 | DECOMP_COMPAT, 3638}, + {0xFBEF, 0, 2 | DECOMP_COMPAT, 3640}, + {0xFBF0, 0, 2 | DECOMP_COMPAT, 3642}, + {0xFBF1, 0, 2 | DECOMP_COMPAT, 3644}, + {0xFBF2, 0, 2 | DECOMP_COMPAT, 3646}, + {0xFBF3, 0, 2 | DECOMP_COMPAT, 3648}, + {0xFBF4, 0, 2 | DECOMP_COMPAT, 3650}, + {0xFBF5, 0, 2 | DECOMP_COMPAT, 3652}, + {0xFBF6, 0, 2 | DECOMP_COMPAT, 3654}, + {0xFBF7, 0, 2 | DECOMP_COMPAT, 3656}, + {0xFBF8, 0, 2 | DECOMP_COMPAT, 3658}, + {0xFBF9, 0, 2 | DECOMP_COMPAT, 3660}, + {0xFBFA, 0, 2 | DECOMP_COMPAT, 3662}, + {0xFBFB, 0, 2 | DECOMP_COMPAT, 3664}, + {0xFBFC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFBFF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06CC}, + {0xFC00, 0, 2 | DECOMP_COMPAT, 3666}, + {0xFC01, 0, 2 | DECOMP_COMPAT, 3668}, + {0xFC02, 0, 2 | DECOMP_COMPAT, 3670}, + {0xFC03, 0, 2 | DECOMP_COMPAT, 3672}, + {0xFC04, 0, 2 | DECOMP_COMPAT, 3674}, + {0xFC05, 0, 2 | DECOMP_COMPAT, 3676}, + {0xFC06, 0, 2 | DECOMP_COMPAT, 3678}, + {0xFC07, 0, 2 | DECOMP_COMPAT, 3680}, + {0xFC08, 0, 2 | DECOMP_COMPAT, 3682}, + {0xFC09, 0, 2 | DECOMP_COMPAT, 3684}, + {0xFC0A, 0, 2 | DECOMP_COMPAT, 3686}, + {0xFC0B, 0, 2 | DECOMP_COMPAT, 3688}, + {0xFC0C, 0, 2 | DECOMP_COMPAT, 3690}, + {0xFC0D, 0, 2 | DECOMP_COMPAT, 3692}, + {0xFC0E, 0, 2 | DECOMP_COMPAT, 3694}, + {0xFC0F, 0, 2 | DECOMP_COMPAT, 3696}, + {0xFC10, 0, 2 | DECOMP_COMPAT, 3698}, + {0xFC11, 0, 2 | DECOMP_COMPAT, 3700}, + {0xFC12, 0, 2 | DECOMP_COMPAT, 3702}, + {0xFC13, 0, 2 | DECOMP_COMPAT, 3704}, + {0xFC14, 0, 2 | DECOMP_COMPAT, 3706}, + {0xFC15, 0, 2 | DECOMP_COMPAT, 3708}, + {0xFC16, 0, 2 | DECOMP_COMPAT, 3710}, + {0xFC17, 0, 2 | DECOMP_COMPAT, 3712}, + {0xFC18, 0, 2 | DECOMP_COMPAT, 3714}, + {0xFC19, 0, 2 | DECOMP_COMPAT, 3716}, + {0xFC1A, 0, 2 | DECOMP_COMPAT, 3718}, + {0xFC1B, 0, 2 | DECOMP_COMPAT, 3720}, + {0xFC1C, 0, 2 | DECOMP_COMPAT, 3722}, + {0xFC1D, 0, 2 | DECOMP_COMPAT, 3724}, + {0xFC1E, 0, 2 | DECOMP_COMPAT, 3726}, + {0xFC1F, 0, 2 | DECOMP_COMPAT, 3728}, + {0xFC20, 0, 2 | DECOMP_COMPAT, 3730}, + {0xFC21, 0, 2 | DECOMP_COMPAT, 3732}, + {0xFC22, 0, 2 | DECOMP_COMPAT, 3734}, + {0xFC23, 0, 2 | DECOMP_COMPAT, 3736}, + {0xFC24, 0, 2 | DECOMP_COMPAT, 3738}, + {0xFC25, 0, 2 | DECOMP_COMPAT, 3740}, + {0xFC26, 0, 2 | DECOMP_COMPAT, 3742}, + {0xFC27, 0, 2 | DECOMP_COMPAT, 3744}, + {0xFC28, 0, 2 | DECOMP_COMPAT, 3746}, + {0xFC29, 0, 2 | DECOMP_COMPAT, 3748}, + {0xFC2A, 0, 2 | DECOMP_COMPAT, 3750}, + {0xFC2B, 0, 2 | DECOMP_COMPAT, 3752}, + {0xFC2C, 0, 2 | DECOMP_COMPAT, 3754}, + {0xFC2D, 0, 2 | DECOMP_COMPAT, 3756}, + {0xFC2E, 0, 2 | DECOMP_COMPAT, 3758}, + {0xFC2F, 0, 2 | DECOMP_COMPAT, 3760}, + {0xFC30, 0, 2 | DECOMP_COMPAT, 3762}, + {0xFC31, 0, 2 | DECOMP_COMPAT, 3764}, + {0xFC32, 0, 2 | DECOMP_COMPAT, 3766}, + {0xFC33, 0, 2 | DECOMP_COMPAT, 3768}, + {0xFC34, 0, 2 | DECOMP_COMPAT, 3770}, + {0xFC35, 0, 2 | DECOMP_COMPAT, 3772}, + {0xFC36, 0, 2 | DECOMP_COMPAT, 3774}, + {0xFC37, 0, 2 | DECOMP_COMPAT, 3776}, + {0xFC38, 0, 2 | DECOMP_COMPAT, 3778}, + {0xFC39, 0, 2 | DECOMP_COMPAT, 3780}, + {0xFC3A, 0, 2 | DECOMP_COMPAT, 3782}, + {0xFC3B, 0, 2 | DECOMP_COMPAT, 3784}, + {0xFC3C, 0, 2 | DECOMP_COMPAT, 3786}, + {0xFC3D, 0, 2 | DECOMP_COMPAT, 3788}, + {0xFC3E, 0, 2 | DECOMP_COMPAT, 3790}, + {0xFC3F, 0, 2 | DECOMP_COMPAT, 3792}, + {0xFC40, 0, 2 | DECOMP_COMPAT, 3794}, + {0xFC41, 0, 2 | DECOMP_COMPAT, 3796}, + {0xFC42, 0, 2 | DECOMP_COMPAT, 3798}, + {0xFC43, 0, 2 | DECOMP_COMPAT, 3800}, + {0xFC44, 0, 2 | DECOMP_COMPAT, 3802}, + {0xFC45, 0, 2 | DECOMP_COMPAT, 3804}, + {0xFC46, 0, 2 | DECOMP_COMPAT, 3806}, + {0xFC47, 0, 2 | DECOMP_COMPAT, 3808}, + {0xFC48, 0, 2 | DECOMP_COMPAT, 3810}, + {0xFC49, 0, 2 | DECOMP_COMPAT, 3812}, + {0xFC4A, 0, 2 | DECOMP_COMPAT, 3814}, + {0xFC4B, 0, 2 | DECOMP_COMPAT, 3816}, + {0xFC4C, 0, 2 | DECOMP_COMPAT, 3818}, + {0xFC4D, 0, 2 | DECOMP_COMPAT, 3820}, + {0xFC4E, 0, 2 | DECOMP_COMPAT, 3822}, + {0xFC4F, 0, 2 | DECOMP_COMPAT, 3824}, + {0xFC50, 0, 2 | DECOMP_COMPAT, 3826}, + {0xFC51, 0, 2 | DECOMP_COMPAT, 3828}, + {0xFC52, 0, 2 | DECOMP_COMPAT, 3830}, + {0xFC53, 0, 2 | DECOMP_COMPAT, 3832}, + {0xFC54, 0, 2 | DECOMP_COMPAT, 3834}, + {0xFC55, 0, 2 | DECOMP_COMPAT, 3836}, + {0xFC56, 0, 2 | DECOMP_COMPAT, 3838}, + {0xFC57, 0, 2 | DECOMP_COMPAT, 3840}, + {0xFC58, 0, 2 | DECOMP_COMPAT, 3842}, + {0xFC59, 0, 2 | DECOMP_COMPAT, 3844}, + {0xFC5A, 0, 2 | DECOMP_COMPAT, 3846}, + {0xFC5B, 0, 2 | DECOMP_COMPAT, 3848}, + {0xFC5C, 0, 2 | DECOMP_COMPAT, 3850}, + {0xFC5D, 0, 2 | DECOMP_COMPAT, 3852}, + {0xFC5E, 0, 3 | DECOMP_COMPAT, 3854}, + {0xFC5F, 0, 3 | DECOMP_COMPAT, 3857}, + {0xFC60, 0, 3 | DECOMP_COMPAT, 3860}, + {0xFC61, 0, 3 | DECOMP_COMPAT, 3863}, + {0xFC62, 0, 3 | DECOMP_COMPAT, 3866}, + {0xFC63, 0, 3 | DECOMP_COMPAT, 3869}, + {0xFC64, 0, 2 | DECOMP_COMPAT, 3872}, + {0xFC65, 0, 2 | DECOMP_COMPAT, 3874}, + {0xFC66, 0, 2 | DECOMP_COMPAT, 3876}, + {0xFC67, 0, 2 | DECOMP_COMPAT, 3878}, + {0xFC68, 0, 2 | DECOMP_COMPAT, 3880}, + {0xFC69, 0, 2 | DECOMP_COMPAT, 3882}, + {0xFC6A, 0, 2 | DECOMP_COMPAT, 3884}, + {0xFC6B, 0, 2 | DECOMP_COMPAT, 3886}, + {0xFC6C, 0, 2 | DECOMP_COMPAT, 3888}, + {0xFC6D, 0, 2 | DECOMP_COMPAT, 3890}, + {0xFC6E, 0, 2 | DECOMP_COMPAT, 3892}, + {0xFC6F, 0, 2 | DECOMP_COMPAT, 3894}, + {0xFC70, 0, 2 | DECOMP_COMPAT, 3896}, + {0xFC71, 0, 2 | DECOMP_COMPAT, 3898}, + {0xFC72, 0, 2 | DECOMP_COMPAT, 3900}, + {0xFC73, 0, 2 | DECOMP_COMPAT, 3902}, + {0xFC74, 0, 2 | DECOMP_COMPAT, 3904}, + {0xFC75, 0, 2 | DECOMP_COMPAT, 3906}, + {0xFC76, 0, 2 | DECOMP_COMPAT, 3908}, + {0xFC77, 0, 2 | DECOMP_COMPAT, 3910}, + {0xFC78, 0, 2 | DECOMP_COMPAT, 3912}, + {0xFC79, 0, 2 | DECOMP_COMPAT, 3914}, + {0xFC7A, 0, 2 | DECOMP_COMPAT, 3916}, + {0xFC7B, 0, 2 | DECOMP_COMPAT, 3918}, + {0xFC7C, 0, 2 | DECOMP_COMPAT, 3920}, + {0xFC7D, 0, 2 | DECOMP_COMPAT, 3922}, + {0xFC7E, 0, 2 | DECOMP_COMPAT, 3924}, + {0xFC7F, 0, 2 | DECOMP_COMPAT, 3926}, + {0xFC80, 0, 2 | DECOMP_COMPAT, 3928}, + {0xFC81, 0, 2 | DECOMP_COMPAT, 3930}, + {0xFC82, 0, 2 | DECOMP_COMPAT, 3932}, + {0xFC83, 0, 2 | DECOMP_COMPAT, 3934}, + {0xFC84, 0, 2 | DECOMP_COMPAT, 3936}, + {0xFC85, 0, 2 | DECOMP_COMPAT, 3938}, + {0xFC86, 0, 2 | DECOMP_COMPAT, 3940}, + {0xFC87, 0, 2 | DECOMP_COMPAT, 3942}, + {0xFC88, 0, 2 | DECOMP_COMPAT, 3944}, + {0xFC89, 0, 2 | DECOMP_COMPAT, 3946}, + {0xFC8A, 0, 2 | DECOMP_COMPAT, 3948}, + {0xFC8B, 0, 2 | DECOMP_COMPAT, 3950}, + {0xFC8C, 0, 2 | DECOMP_COMPAT, 3952}, + {0xFC8D, 0, 2 | DECOMP_COMPAT, 3954}, + {0xFC8E, 0, 2 | DECOMP_COMPAT, 3956}, + {0xFC8F, 0, 2 | DECOMP_COMPAT, 3958}, + {0xFC90, 0, 2 | DECOMP_COMPAT, 3960}, + {0xFC91, 0, 2 | DECOMP_COMPAT, 3962}, + {0xFC92, 0, 2 | DECOMP_COMPAT, 3964}, + {0xFC93, 0, 2 | DECOMP_COMPAT, 3966}, + {0xFC94, 0, 2 | DECOMP_COMPAT, 3968}, + {0xFC95, 0, 2 | DECOMP_COMPAT, 3970}, + {0xFC96, 0, 2 | DECOMP_COMPAT, 3972}, + {0xFC97, 0, 2 | DECOMP_COMPAT, 3974}, + {0xFC98, 0, 2 | DECOMP_COMPAT, 3976}, + {0xFC99, 0, 2 | DECOMP_COMPAT, 3978}, + {0xFC9A, 0, 2 | DECOMP_COMPAT, 3980}, + {0xFC9B, 0, 2 | DECOMP_COMPAT, 3982}, + {0xFC9C, 0, 2 | DECOMP_COMPAT, 3984}, + {0xFC9D, 0, 2 | DECOMP_COMPAT, 3986}, + {0xFC9E, 0, 2 | DECOMP_COMPAT, 3988}, + {0xFC9F, 0, 2 | DECOMP_COMPAT, 3990}, + {0xFCA0, 0, 2 | DECOMP_COMPAT, 3992}, + {0xFCA1, 0, 2 | DECOMP_COMPAT, 3994}, + {0xFCA2, 0, 2 | DECOMP_COMPAT, 3996}, + {0xFCA3, 0, 2 | DECOMP_COMPAT, 3998}, + {0xFCA4, 0, 2 | DECOMP_COMPAT, 4000}, + {0xFCA5, 0, 2 | DECOMP_COMPAT, 4002}, + {0xFCA6, 0, 2 | DECOMP_COMPAT, 4004}, + {0xFCA7, 0, 2 | DECOMP_COMPAT, 4006}, + {0xFCA8, 0, 2 | DECOMP_COMPAT, 4008}, + {0xFCA9, 0, 2 | DECOMP_COMPAT, 4010}, + {0xFCAA, 0, 2 | DECOMP_COMPAT, 4012}, + {0xFCAB, 0, 2 | DECOMP_COMPAT, 4014}, + {0xFCAC, 0, 2 | DECOMP_COMPAT, 4016}, + {0xFCAD, 0, 2 | DECOMP_COMPAT, 4018}, + {0xFCAE, 0, 2 | DECOMP_COMPAT, 4020}, + {0xFCAF, 0, 2 | DECOMP_COMPAT, 4022}, + {0xFCB0, 0, 2 | DECOMP_COMPAT, 4024}, + {0xFCB1, 0, 2 | DECOMP_COMPAT, 4026}, + {0xFCB2, 0, 2 | DECOMP_COMPAT, 4028}, + {0xFCB3, 0, 2 | DECOMP_COMPAT, 4030}, + {0xFCB4, 0, 2 | DECOMP_COMPAT, 4032}, + {0xFCB5, 0, 2 | DECOMP_COMPAT, 4034}, + {0xFCB6, 0, 2 | DECOMP_COMPAT, 4036}, + {0xFCB7, 0, 2 | DECOMP_COMPAT, 4038}, + {0xFCB8, 0, 2 | DECOMP_COMPAT, 4040}, + {0xFCB9, 0, 2 | DECOMP_COMPAT, 4042}, + {0xFCBA, 0, 2 | DECOMP_COMPAT, 4044}, + {0xFCBB, 0, 2 | DECOMP_COMPAT, 4046}, + {0xFCBC, 0, 2 | DECOMP_COMPAT, 4048}, + {0xFCBD, 0, 2 | DECOMP_COMPAT, 4050}, + {0xFCBE, 0, 2 | DECOMP_COMPAT, 4052}, + {0xFCBF, 0, 2 | DECOMP_COMPAT, 4054}, + {0xFCC0, 0, 2 | DECOMP_COMPAT, 4056}, + {0xFCC1, 0, 2 | DECOMP_COMPAT, 4058}, + {0xFCC2, 0, 2 | DECOMP_COMPAT, 4060}, + {0xFCC3, 0, 2 | DECOMP_COMPAT, 4062}, + {0xFCC4, 0, 2 | DECOMP_COMPAT, 4064}, + {0xFCC5, 0, 2 | DECOMP_COMPAT, 4066}, + {0xFCC6, 0, 2 | DECOMP_COMPAT, 4068}, + {0xFCC7, 0, 2 | DECOMP_COMPAT, 4070}, + {0xFCC8, 0, 2 | DECOMP_COMPAT, 4072}, + {0xFCC9, 0, 2 | DECOMP_COMPAT, 4074}, + {0xFCCA, 0, 2 | DECOMP_COMPAT, 4076}, + {0xFCCB, 0, 2 | DECOMP_COMPAT, 4078}, + {0xFCCC, 0, 2 | DECOMP_COMPAT, 4080}, + {0xFCCD, 0, 2 | DECOMP_COMPAT, 4082}, + {0xFCCE, 0, 2 | DECOMP_COMPAT, 4084}, + {0xFCCF, 0, 2 | DECOMP_COMPAT, 4086}, + {0xFCD0, 0, 2 | DECOMP_COMPAT, 4088}, + {0xFCD1, 0, 2 | DECOMP_COMPAT, 4090}, + {0xFCD2, 0, 2 | DECOMP_COMPAT, 4092}, + {0xFCD3, 0, 2 | DECOMP_COMPAT, 4094}, + {0xFCD4, 0, 2 | DECOMP_COMPAT, 4096}, + {0xFCD5, 0, 2 | DECOMP_COMPAT, 4098}, + {0xFCD6, 0, 2 | DECOMP_COMPAT, 4100}, + {0xFCD7, 0, 2 | DECOMP_COMPAT, 4102}, + {0xFCD8, 0, 2 | DECOMP_COMPAT, 4104}, + {0xFCD9, 0, 2 | DECOMP_COMPAT, 4106}, + {0xFCDA, 0, 2 | DECOMP_COMPAT, 4108}, + {0xFCDB, 0, 2 | DECOMP_COMPAT, 4110}, + {0xFCDC, 0, 2 | DECOMP_COMPAT, 4112}, + {0xFCDD, 0, 2 | DECOMP_COMPAT, 4114}, + {0xFCDE, 0, 2 | DECOMP_COMPAT, 4116}, + {0xFCDF, 0, 2 | DECOMP_COMPAT, 4118}, + {0xFCE0, 0, 2 | DECOMP_COMPAT, 4120}, + {0xFCE1, 0, 2 | DECOMP_COMPAT, 4122}, + {0xFCE2, 0, 2 | DECOMP_COMPAT, 4124}, + {0xFCE3, 0, 2 | DECOMP_COMPAT, 4126}, + {0xFCE4, 0, 2 | DECOMP_COMPAT, 4128}, + {0xFCE5, 0, 2 | DECOMP_COMPAT, 4130}, + {0xFCE6, 0, 2 | DECOMP_COMPAT, 4132}, + {0xFCE7, 0, 2 | DECOMP_COMPAT, 4134}, + {0xFCE8, 0, 2 | DECOMP_COMPAT, 4136}, + {0xFCE9, 0, 2 | DECOMP_COMPAT, 4138}, + {0xFCEA, 0, 2 | DECOMP_COMPAT, 4140}, + {0xFCEB, 0, 2 | DECOMP_COMPAT, 4142}, + {0xFCEC, 0, 2 | DECOMP_COMPAT, 4144}, + {0xFCED, 0, 2 | DECOMP_COMPAT, 4146}, + {0xFCEE, 0, 2 | DECOMP_COMPAT, 4148}, + {0xFCEF, 0, 2 | DECOMP_COMPAT, 4150}, + {0xFCF0, 0, 2 | DECOMP_COMPAT, 4152}, + {0xFCF1, 0, 2 | DECOMP_COMPAT, 4154}, + {0xFCF2, 0, 3 | DECOMP_COMPAT, 4156}, + {0xFCF3, 0, 3 | DECOMP_COMPAT, 4159}, + {0xFCF4, 0, 3 | DECOMP_COMPAT, 4162}, + {0xFCF5, 0, 2 | DECOMP_COMPAT, 4165}, + {0xFCF6, 0, 2 | DECOMP_COMPAT, 4167}, + {0xFCF7, 0, 2 | DECOMP_COMPAT, 4169}, + {0xFCF8, 0, 2 | DECOMP_COMPAT, 4171}, + {0xFCF9, 0, 2 | DECOMP_COMPAT, 4173}, + {0xFCFA, 0, 2 | DECOMP_COMPAT, 4175}, + {0xFCFB, 0, 2 | DECOMP_COMPAT, 4177}, + {0xFCFC, 0, 2 | DECOMP_COMPAT, 4179}, + {0xFCFD, 0, 2 | DECOMP_COMPAT, 4181}, + {0xFCFE, 0, 2 | DECOMP_COMPAT, 4183}, + {0xFCFF, 0, 2 | DECOMP_COMPAT, 4185}, + {0xFD00, 0, 2 | DECOMP_COMPAT, 4187}, + {0xFD01, 0, 2 | DECOMP_COMPAT, 4189}, + {0xFD02, 0, 2 | DECOMP_COMPAT, 4191}, + {0xFD03, 0, 2 | DECOMP_COMPAT, 4193}, + {0xFD04, 0, 2 | DECOMP_COMPAT, 4195}, + {0xFD05, 0, 2 | DECOMP_COMPAT, 4197}, + {0xFD06, 0, 2 | DECOMP_COMPAT, 4199}, + {0xFD07, 0, 2 | DECOMP_COMPAT, 4201}, + {0xFD08, 0, 2 | DECOMP_COMPAT, 4203}, + {0xFD09, 0, 2 | DECOMP_COMPAT, 4205}, + {0xFD0A, 0, 2 | DECOMP_COMPAT, 4207}, + {0xFD0B, 0, 2 | DECOMP_COMPAT, 4209}, + {0xFD0C, 0, 2 | DECOMP_COMPAT, 4211}, + {0xFD0D, 0, 2 | DECOMP_COMPAT, 4213}, + {0xFD0E, 0, 2 | DECOMP_COMPAT, 4215}, + {0xFD0F, 0, 2 | DECOMP_COMPAT, 4217}, + {0xFD10, 0, 2 | DECOMP_COMPAT, 4219}, + {0xFD11, 0, 2 | DECOMP_COMPAT, 4221}, + {0xFD12, 0, 2 | DECOMP_COMPAT, 4223}, + {0xFD13, 0, 2 | DECOMP_COMPAT, 4225}, + {0xFD14, 0, 2 | DECOMP_COMPAT, 4227}, + {0xFD15, 0, 2 | DECOMP_COMPAT, 4229}, + {0xFD16, 0, 2 | DECOMP_COMPAT, 4231}, + {0xFD17, 0, 2 | DECOMP_COMPAT, 4233}, + {0xFD18, 0, 2 | DECOMP_COMPAT, 4235}, + {0xFD19, 0, 2 | DECOMP_COMPAT, 4237}, + {0xFD1A, 0, 2 | DECOMP_COMPAT, 4239}, + {0xFD1B, 0, 2 | DECOMP_COMPAT, 4241}, + {0xFD1C, 0, 2 | DECOMP_COMPAT, 4243}, + {0xFD1D, 0, 2 | DECOMP_COMPAT, 4245}, + {0xFD1E, 0, 2 | DECOMP_COMPAT, 4247}, + {0xFD1F, 0, 2 | DECOMP_COMPAT, 4249}, + {0xFD20, 0, 2 | DECOMP_COMPAT, 4251}, + {0xFD21, 0, 2 | DECOMP_COMPAT, 4253}, + {0xFD22, 0, 2 | DECOMP_COMPAT, 4255}, + {0xFD23, 0, 2 | DECOMP_COMPAT, 4257}, + {0xFD24, 0, 2 | DECOMP_COMPAT, 4259}, + {0xFD25, 0, 2 | DECOMP_COMPAT, 4261}, + {0xFD26, 0, 2 | DECOMP_COMPAT, 4263}, + {0xFD27, 0, 2 | DECOMP_COMPAT, 4265}, + {0xFD28, 0, 2 | DECOMP_COMPAT, 4267}, + {0xFD29, 0, 2 | DECOMP_COMPAT, 4269}, + {0xFD2A, 0, 2 | DECOMP_COMPAT, 4271}, + {0xFD2B, 0, 2 | DECOMP_COMPAT, 4273}, + {0xFD2C, 0, 2 | DECOMP_COMPAT, 4275}, + {0xFD2D, 0, 2 | DECOMP_COMPAT, 4277}, + {0xFD2E, 0, 2 | DECOMP_COMPAT, 4279}, + {0xFD2F, 0, 2 | DECOMP_COMPAT, 4281}, + {0xFD30, 0, 2 | DECOMP_COMPAT, 4283}, + {0xFD31, 0, 2 | DECOMP_COMPAT, 4285}, + {0xFD32, 0, 2 | DECOMP_COMPAT, 4287}, + {0xFD33, 0, 2 | DECOMP_COMPAT, 4289}, + {0xFD34, 0, 2 | DECOMP_COMPAT, 4291}, + {0xFD35, 0, 2 | DECOMP_COMPAT, 4293}, + {0xFD36, 0, 2 | DECOMP_COMPAT, 4295}, + {0xFD37, 0, 2 | DECOMP_COMPAT, 4297}, + {0xFD38, 0, 2 | DECOMP_COMPAT, 4299}, + {0xFD39, 0, 2 | DECOMP_COMPAT, 4301}, + {0xFD3A, 0, 2 | DECOMP_COMPAT, 4303}, + {0xFD3B, 0, 2 | DECOMP_COMPAT, 4305}, + {0xFD3C, 0, 2 | DECOMP_COMPAT, 4307}, + {0xFD3D, 0, 2 | DECOMP_COMPAT, 4309}, + {0xFD50, 0, 3 | DECOMP_COMPAT, 4311}, + {0xFD51, 0, 3 | DECOMP_COMPAT, 4314}, + {0xFD52, 0, 3 | DECOMP_COMPAT, 4317}, + {0xFD53, 0, 3 | DECOMP_COMPAT, 4320}, + {0xFD54, 0, 3 | DECOMP_COMPAT, 4323}, + {0xFD55, 0, 3 | DECOMP_COMPAT, 4326}, + {0xFD56, 0, 3 | DECOMP_COMPAT, 4329}, + {0xFD57, 0, 3 | DECOMP_COMPAT, 4332}, + {0xFD58, 0, 3 | DECOMP_COMPAT, 4335}, + {0xFD59, 0, 3 | DECOMP_COMPAT, 4338}, + {0xFD5A, 0, 3 | DECOMP_COMPAT, 4341}, + {0xFD5B, 0, 3 | DECOMP_COMPAT, 4344}, + {0xFD5C, 0, 3 | DECOMP_COMPAT, 4347}, + {0xFD5D, 0, 3 | DECOMP_COMPAT, 4350}, + {0xFD5E, 0, 3 | DECOMP_COMPAT, 4353}, + {0xFD5F, 0, 3 | DECOMP_COMPAT, 4356}, + {0xFD60, 0, 3 | DECOMP_COMPAT, 4359}, + {0xFD61, 0, 3 | DECOMP_COMPAT, 4362}, + {0xFD62, 0, 3 | DECOMP_COMPAT, 4365}, + {0xFD63, 0, 3 | DECOMP_COMPAT, 4368}, + {0xFD64, 0, 3 | DECOMP_COMPAT, 4371}, + {0xFD65, 0, 3 | DECOMP_COMPAT, 4374}, + {0xFD66, 0, 3 | DECOMP_COMPAT, 4377}, + {0xFD67, 0, 3 | DECOMP_COMPAT, 4380}, + {0xFD68, 0, 3 | DECOMP_COMPAT, 4383}, + {0xFD69, 0, 3 | DECOMP_COMPAT, 4386}, + {0xFD6A, 0, 3 | DECOMP_COMPAT, 4389}, + {0xFD6B, 0, 3 | DECOMP_COMPAT, 4392}, + {0xFD6C, 0, 3 | DECOMP_COMPAT, 4395}, + {0xFD6D, 0, 3 | DECOMP_COMPAT, 4398}, + {0xFD6E, 0, 3 | DECOMP_COMPAT, 4401}, + {0xFD6F, 0, 3 | DECOMP_COMPAT, 4404}, + {0xFD70, 0, 3 | DECOMP_COMPAT, 4407}, + {0xFD71, 0, 3 | DECOMP_COMPAT, 4410}, + {0xFD72, 0, 3 | DECOMP_COMPAT, 4413}, + {0xFD73, 0, 3 | DECOMP_COMPAT, 4416}, + {0xFD74, 0, 3 | DECOMP_COMPAT, 4419}, + {0xFD75, 0, 3 | DECOMP_COMPAT, 4422}, + {0xFD76, 0, 3 | DECOMP_COMPAT, 4425}, + {0xFD77, 0, 3 | DECOMP_COMPAT, 4428}, + {0xFD78, 0, 3 | DECOMP_COMPAT, 4431}, + {0xFD79, 0, 3 | DECOMP_COMPAT, 4434}, + {0xFD7A, 0, 3 | DECOMP_COMPAT, 4437}, + {0xFD7B, 0, 3 | DECOMP_COMPAT, 4440}, + {0xFD7C, 0, 3 | DECOMP_COMPAT, 4443}, + {0xFD7D, 0, 3 | DECOMP_COMPAT, 4446}, + {0xFD7E, 0, 3 | DECOMP_COMPAT, 4449}, + {0xFD7F, 0, 3 | DECOMP_COMPAT, 4452}, + {0xFD80, 0, 3 | DECOMP_COMPAT, 4455}, + {0xFD81, 0, 3 | DECOMP_COMPAT, 4458}, + {0xFD82, 0, 3 | DECOMP_COMPAT, 4461}, + {0xFD83, 0, 3 | DECOMP_COMPAT, 4464}, + {0xFD84, 0, 3 | DECOMP_COMPAT, 4467}, + {0xFD85, 0, 3 | DECOMP_COMPAT, 4470}, + {0xFD86, 0, 3 | DECOMP_COMPAT, 4473}, + {0xFD87, 0, 3 | DECOMP_COMPAT, 4476}, + {0xFD88, 0, 3 | DECOMP_COMPAT, 4479}, + {0xFD89, 0, 3 | DECOMP_COMPAT, 4482}, + {0xFD8A, 0, 3 | DECOMP_COMPAT, 4485}, + {0xFD8B, 0, 3 | DECOMP_COMPAT, 4488}, + {0xFD8C, 0, 3 | DECOMP_COMPAT, 4491}, + {0xFD8D, 0, 3 | DECOMP_COMPAT, 4494}, + {0xFD8E, 0, 3 | DECOMP_COMPAT, 4497}, + {0xFD8F, 0, 3 | DECOMP_COMPAT, 4500}, + {0xFD92, 0, 3 | DECOMP_COMPAT, 4503}, + {0xFD93, 0, 3 | DECOMP_COMPAT, 4506}, + {0xFD94, 0, 3 | DECOMP_COMPAT, 4509}, + {0xFD95, 0, 3 | DECOMP_COMPAT, 4512}, + {0xFD96, 0, 3 | DECOMP_COMPAT, 4515}, + {0xFD97, 0, 3 | DECOMP_COMPAT, 4518}, + {0xFD98, 0, 3 | DECOMP_COMPAT, 4521}, + {0xFD99, 0, 3 | DECOMP_COMPAT, 4524}, + {0xFD9A, 0, 3 | DECOMP_COMPAT, 4527}, + {0xFD9B, 0, 3 | DECOMP_COMPAT, 4530}, + {0xFD9C, 0, 3 | DECOMP_COMPAT, 4533}, + {0xFD9D, 0, 3 | DECOMP_COMPAT, 4536}, + {0xFD9E, 0, 3 | DECOMP_COMPAT, 4539}, + {0xFD9F, 0, 3 | DECOMP_COMPAT, 4542}, + {0xFDA0, 0, 3 | DECOMP_COMPAT, 4545}, + {0xFDA1, 0, 3 | DECOMP_COMPAT, 4548}, + {0xFDA2, 0, 3 | DECOMP_COMPAT, 4551}, + {0xFDA3, 0, 3 | DECOMP_COMPAT, 4554}, + {0xFDA4, 0, 3 | DECOMP_COMPAT, 4557}, + {0xFDA5, 0, 3 | DECOMP_COMPAT, 4560}, + {0xFDA6, 0, 3 | DECOMP_COMPAT, 4563}, + {0xFDA7, 0, 3 | DECOMP_COMPAT, 4566}, + {0xFDA8, 0, 3 | DECOMP_COMPAT, 4569}, + {0xFDA9, 0, 3 | DECOMP_COMPAT, 4572}, + {0xFDAA, 0, 3 | DECOMP_COMPAT, 4575}, + {0xFDAB, 0, 3 | DECOMP_COMPAT, 4578}, + {0xFDAC, 0, 3 | DECOMP_COMPAT, 4581}, + {0xFDAD, 0, 3 | DECOMP_COMPAT, 4584}, + {0xFDAE, 0, 3 | DECOMP_COMPAT, 4587}, + {0xFDAF, 0, 3 | DECOMP_COMPAT, 4590}, + {0xFDB0, 0, 3 | DECOMP_COMPAT, 4593}, + {0xFDB1, 0, 3 | DECOMP_COMPAT, 4596}, + {0xFDB2, 0, 3 | DECOMP_COMPAT, 4599}, + {0xFDB3, 0, 3 | DECOMP_COMPAT, 4602}, + {0xFDB4, 0, 3 | DECOMP_COMPAT, 4605}, + {0xFDB5, 0, 3 | DECOMP_COMPAT, 4608}, + {0xFDB6, 0, 3 | DECOMP_COMPAT, 4611}, + {0xFDB7, 0, 3 | DECOMP_COMPAT, 4614}, + {0xFDB8, 0, 3 | DECOMP_COMPAT, 4617}, + {0xFDB9, 0, 3 | DECOMP_COMPAT, 4620}, + {0xFDBA, 0, 3 | DECOMP_COMPAT, 4623}, + {0xFDBB, 0, 3 | DECOMP_COMPAT, 4626}, + {0xFDBC, 0, 3 | DECOMP_COMPAT, 4629}, + {0xFDBD, 0, 3 | DECOMP_COMPAT, 4632}, + {0xFDBE, 0, 3 | DECOMP_COMPAT, 4635}, + {0xFDBF, 0, 3 | DECOMP_COMPAT, 4638}, + {0xFDC0, 0, 3 | DECOMP_COMPAT, 4641}, + {0xFDC1, 0, 3 | DECOMP_COMPAT, 4644}, + {0xFDC2, 0, 3 | DECOMP_COMPAT, 4647}, + {0xFDC3, 0, 3 | DECOMP_COMPAT, 4650}, + {0xFDC4, 0, 3 | DECOMP_COMPAT, 4653}, + {0xFDC5, 0, 3 | DECOMP_COMPAT, 4656}, + {0xFDC6, 0, 3 | DECOMP_COMPAT, 4659}, + {0xFDC7, 0, 3 | DECOMP_COMPAT, 4662}, + {0xFDF0, 0, 3 | DECOMP_COMPAT, 4665}, + {0xFDF1, 0, 3 | DECOMP_COMPAT, 4668}, + {0xFDF2, 0, 4 | DECOMP_COMPAT, 4671}, + {0xFDF3, 0, 4 | DECOMP_COMPAT, 4675}, + {0xFDF4, 0, 4 | DECOMP_COMPAT, 4679}, + {0xFDF5, 0, 4 | DECOMP_COMPAT, 4683}, + {0xFDF6, 0, 4 | DECOMP_COMPAT, 4687}, + {0xFDF7, 0, 4 | DECOMP_COMPAT, 4691}, + {0xFDF8, 0, 4 | DECOMP_COMPAT, 4695}, + {0xFDF9, 0, 3 | DECOMP_COMPAT, 4699}, + {0xFDFA, 0, 18 | DECOMP_COMPAT, 4702}, + {0xFDFB, 0, 8 | DECOMP_COMPAT, 4720}, + {0xFDFC, 0, 4 | DECOMP_COMPAT, 4728}, + {0xFE10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFE11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFE12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3002}, + {0xFE13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFE14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFE15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFE16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFE17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3016}, + {0xFE18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3017}, + {0xFE19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2026}, + {0xFE20, 230, 0, 0}, + {0xFE21, 230, 0, 0}, + {0xFE22, 230, 0, 0}, + {0xFE23, 230, 0, 0}, + {0xFE24, 230, 0, 0}, + {0xFE25, 230, 0, 0}, + {0xFE26, 230, 0, 0}, + {0xFE27, 220, 0, 0}, + {0xFE28, 220, 0, 0}, + {0xFE29, 220, 0, 0}, + {0xFE2A, 220, 0, 0}, + {0xFE2B, 220, 0, 0}, + {0xFE2C, 220, 0, 0}, + {0xFE2D, 220, 0, 0}, + {0xFE2E, 230, 0, 0}, + {0xFE2F, 230, 0, 0}, + {0xFE30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2025}, + {0xFE31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2014}, + {0xFE32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2013}, + {0xFE33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFE36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFE37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFE38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFE39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3014}, + {0xFE3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3015}, + {0xFE3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3010}, + {0xFE3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3011}, + {0xFE3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300A}, + {0xFE3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300B}, + {0xFE3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3008}, + {0xFE40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3009}, + {0xFE41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300C}, + {0xFE42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300D}, + {0xFE43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300E}, + {0xFE44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300F}, + {0xFE47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005B}, + {0xFE48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005D}, + {0xFE49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x203E}, + {0xFE4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFE50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFE51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFE52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0xFE54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFE55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFE56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFE57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFE58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2014}, + {0xFE59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFE5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFE5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFE5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFE5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3014}, + {0xFE5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3015}, + {0xFE5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0023}, + {0xFE60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0026}, + {0xFE61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002A}, + {0xFE62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFE63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002D}, + {0xFE64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003C}, + {0xFE65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003E}, + {0xFE66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0xFE68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005C}, + {0xFE69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0024}, + {0xFE6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0025}, + {0xFE6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0040}, + {0xFE70, 0, 2 | DECOMP_COMPAT, 4732}, + {0xFE71, 0, 2 | DECOMP_COMPAT, 4734}, + {0xFE72, 0, 2 | DECOMP_COMPAT, 4736}, + {0xFE74, 0, 2 | DECOMP_COMPAT, 4738}, + {0xFE76, 0, 2 | DECOMP_COMPAT, 4740}, + {0xFE77, 0, 2 | DECOMP_COMPAT, 4742}, + {0xFE78, 0, 2 | DECOMP_COMPAT, 4744}, + {0xFE79, 0, 2 | DECOMP_COMPAT, 4746}, + {0xFE7A, 0, 2 | DECOMP_COMPAT, 4748}, + {0xFE7B, 0, 2 | DECOMP_COMPAT, 4750}, + {0xFE7C, 0, 2 | DECOMP_COMPAT, 4752}, + {0xFE7D, 0, 2 | DECOMP_COMPAT, 4754}, + {0xFE7E, 0, 2 | DECOMP_COMPAT, 4756}, + {0xFE7F, 0, 2 | DECOMP_COMPAT, 4758}, + {0xFE80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0621}, + {0xFE81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0622}, + {0xFE82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0622}, + {0xFE83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0623}, + {0xFE84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0623}, + {0xFE85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0624}, + {0xFE86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0624}, + {0xFE87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0625}, + {0xFE88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0625}, + {0xFE89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0626}, + {0xFE8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0xFE8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0xFE8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0xFE93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0629}, + {0xFE94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0629}, + {0xFE95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0xFE99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0xFE9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFE9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFE9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFEA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0xFEA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0xFEA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0xFEA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0xFEAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0xFEAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0xFEAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0xFEAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0xFEAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0xFEAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0xFEB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0xFEB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0xFEB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0xFEB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0xFEBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEBF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEC0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0xFEC1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0xFEC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0xFEC9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0xFECD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFECE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFECF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFED0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0xFED1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0xFED5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0xFED9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0xFEDD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEDE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEDF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0xFEE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0xFEE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0xFEE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEEC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0xFEED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0xFEEE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0xFEEF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFEF0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0649}, + {0xFEF1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0xFEF5, 0, 2 | DECOMP_COMPAT, 4760}, + {0xFEF6, 0, 2 | DECOMP_COMPAT, 4762}, + {0xFEF7, 0, 2 | DECOMP_COMPAT, 4764}, + {0xFEF8, 0, 2 | DECOMP_COMPAT, 4766}, + {0xFEF9, 0, 2 | DECOMP_COMPAT, 4768}, + {0xFEFA, 0, 2 | DECOMP_COMPAT, 4770}, + {0xFEFB, 0, 2 | DECOMP_COMPAT, 4772}, + {0xFEFC, 0, 2 | DECOMP_COMPAT, 4774}, + {0xFF01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0021}, + {0xFF02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0022}, + {0xFF03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0023}, + {0xFF04, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0024}, + {0xFF05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0025}, + {0xFF06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0026}, + {0xFF07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0027}, + {0xFF08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0028}, + {0xFF09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0029}, + {0xFF0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002A}, + {0xFF0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002B}, + {0xFF0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002C}, + {0xFF0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002D}, + {0xFF0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002E}, + {0xFF0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x002F}, + {0xFF10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0xFF11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0xFF12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0xFF13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0xFF14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0xFF15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0xFF16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0xFF17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0xFF18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0xFF19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0xFF1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003A}, + {0xFF1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003B}, + {0xFF1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003C}, + {0xFF1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003D}, + {0xFF1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003E}, + {0xFF1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x003F}, + {0xFF20, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0040}, + {0xFF21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0xFF22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0xFF23, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0xFF24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0xFF25, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0xFF26, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0xFF27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0xFF28, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0xFF29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0xFF2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0xFF2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0xFF2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0xFF2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0xFF2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0xFF2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0xFF30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0xFF31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0xFF32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0xFF33, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0xFF34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0xFF35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0xFF36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0xFF37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0xFF38, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0xFF39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0xFF3A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0xFF3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005B}, + {0xFF3C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005C}, + {0xFF3D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005D}, + {0xFF3E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005E}, + {0xFF3F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005F}, + {0xFF40, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0060}, + {0xFF41, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0xFF42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0xFF43, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0xFF44, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0xFF45, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0xFF46, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0xFF47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0xFF48, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0xFF49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0xFF4A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0xFF4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0xFF4C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0xFF4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0xFF4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0xFF4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0xFF50, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0xFF51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0xFF52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0xFF53, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0xFF54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0xFF55, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0xFF56, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0xFF57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0xFF58, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0xFF59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0xFF5A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0xFF5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007B}, + {0xFF5C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007C}, + {0xFF5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007D}, + {0xFF5E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007E}, + {0xFF5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2985}, + {0xFF60, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2986}, + {0xFF61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3002}, + {0xFF62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300C}, + {0xFF63, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x300D}, + {0xFF64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3001}, + {0xFF65, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30FB}, + {0xFF66, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F2}, + {0xFF67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A1}, + {0xFF68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A3}, + {0xFF69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A5}, + {0xFF6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A7}, + {0xFF6B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A9}, + {0xFF6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E3}, + {0xFF6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E5}, + {0xFF6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E7}, + {0xFF6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C3}, + {0xFF70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30FC}, + {0xFF71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A2}, + {0xFF72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A4}, + {0xFF73, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A6}, + {0xFF74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30A8}, + {0xFF75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AA}, + {0xFF76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AB}, + {0xFF77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AD}, + {0xFF78, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30AF}, + {0xFF79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B1}, + {0xFF7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B3}, + {0xFF7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0xFF7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B7}, + {0xFF7D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B9}, + {0xFF7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BB}, + {0xFF7F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BD}, + {0xFF80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30BF}, + {0xFF81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C1}, + {0xFF82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C4}, + {0xFF83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C6}, + {0xFF84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C8}, + {0xFF85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CA}, + {0xFF86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CB}, + {0xFF87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CC}, + {0xFF88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CD}, + {0xFF89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CE}, + {0xFF8A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30CF}, + {0xFF8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D2}, + {0xFF8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D5}, + {0xFF8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30D8}, + {0xFF8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DB}, + {0xFF8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DE}, + {0xFF90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30DF}, + {0xFF91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E0}, + {0xFF92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E1}, + {0xFF93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E2}, + {0xFF94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E4}, + {0xFF95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E6}, + {0xFF96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E8}, + {0xFF97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30E9}, + {0xFF98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EA}, + {0xFF99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EB}, + {0xFF9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EC}, + {0xFF9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30ED}, + {0xFF9C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30EF}, + {0xFF9D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30F3}, + {0xFF9E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3099}, + {0xFF9F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x309A}, + {0xFFA0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3164}, + {0xFFA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3131}, + {0xFFA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3132}, + {0xFFA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3133}, + {0xFFA4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3134}, + {0xFFA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3135}, + {0xFFA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3136}, + {0xFFA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3137}, + {0xFFA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3138}, + {0xFFA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3139}, + {0xFFAA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313A}, + {0xFFAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313B}, + {0xFFAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313C}, + {0xFFAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313D}, + {0xFFAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313E}, + {0xFFAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x313F}, + {0xFFB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3140}, + {0xFFB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3141}, + {0xFFB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3142}, + {0xFFB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3143}, + {0xFFB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3144}, + {0xFFB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3145}, + {0xFFB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3146}, + {0xFFB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3147}, + {0xFFB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3148}, + {0xFFB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3149}, + {0xFFBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314A}, + {0xFFBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314B}, + {0xFFBC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314C}, + {0xFFBD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314D}, + {0xFFBE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314E}, + {0xFFC2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x314F}, + {0xFFC3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3150}, + {0xFFC4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3151}, + {0xFFC5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3152}, + {0xFFC6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3153}, + {0xFFC7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3154}, + {0xFFCA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3155}, + {0xFFCB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3156}, + {0xFFCC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3157}, + {0xFFCD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3158}, + {0xFFCE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3159}, + {0xFFCF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315A}, + {0xFFD2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315B}, + {0xFFD3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315C}, + {0xFFD4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315D}, + {0xFFD5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315E}, + {0xFFD6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x315F}, + {0xFFD7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3160}, + {0xFFDA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3161}, + {0xFFDB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3162}, + {0xFFDC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x3163}, + {0xFFE0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A2}, + {0xFFE1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A3}, + {0xFFE2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00AC}, + {0xFFE3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00AF}, + {0xFFE4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A6}, + {0xFFE5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00A5}, + {0xFFE6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x20A9}, + {0xFFE8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2502}, + {0xFFE9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2190}, + {0xFFEA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2191}, + {0xFFEB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2192}, + {0xFFEC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2193}, + {0xFFED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x25A0}, + {0xFFEE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x25CB}, + {0x101FD, 220, 0, 0}, + {0x102E0, 220, 0, 0}, + {0x10376, 230, 0, 0}, + {0x10377, 230, 0, 0}, + {0x10378, 230, 0, 0}, + {0x10379, 230, 0, 0}, + {0x1037A, 230, 0, 0}, + {0x10781, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02D0}, + {0x10782, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02D1}, + {0x10783, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00E6}, + {0x10784, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0299}, + {0x10785, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0253}, + {0x10787, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A3}, + {0x10788, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB66}, + {0x10789, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A5}, + {0x1078A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A4}, + {0x1078B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0256}, + {0x1078C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0257}, + {0x1078D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x1D91}, + {0x1078E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0258}, + {0x1078F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x025E}, + {0x10790, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A9}, + {0x10791, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0264}, + {0x10792, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0262}, + {0x10793, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0260}, + {0x10794, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029B}, + {0x10795, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0127}, + {0x10796, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x029C}, + {0x10797, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0267}, + {0x10798, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0284}, + {0x10799, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02AA}, + {0x1079A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02AB}, + {0x1079B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026C}, + {0x1079C, 0, 1 | DECOMP_COMPAT, 4776}, + {0x1079D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xA78E}, + {0x1079E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x026E}, + {0x1079F, 0, 1 | DECOMP_COMPAT, 4777}, + {0x107A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028E}, + {0x107A1, 0, 1 | DECOMP_COMPAT, 4778}, + {0x107A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x00F8}, + {0x107A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0276}, + {0x107A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0277}, + {0x107A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x107A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027A}, + {0x107A7, 0, 1 | DECOMP_COMPAT, 4779}, + {0x107A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027D}, + {0x107A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x027E}, + {0x107AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0280}, + {0x107AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A8}, + {0x107AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A6}, + {0x107AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0xAB67}, + {0x107AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A7}, + {0x107AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0288}, + {0x107B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2C71}, + {0x107B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x028F}, + {0x107B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A1}, + {0x107B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x02A2}, + {0x107B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0298}, + {0x107B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C0}, + {0x107B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C1}, + {0x107B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x01C2}, + {0x107B9, 0, 1 | DECOMP_COMPAT, 4780}, + {0x107BA, 0, 1 | DECOMP_COMPAT, 4781}, + {0x10A0D, 220, 0, 0}, + {0x10A0F, 230, 0, 0}, + {0x10A38, 230, 0, 0}, + {0x10A39, 1, 0, 0}, + {0x10A3A, 220, 0, 0}, + {0x10A3F, 9, 0, 0}, + {0x10AE5, 230, 0, 0}, + {0x10AE6, 220, 0, 0}, + {0x10D24, 230, 0, 0}, + {0x10D25, 230, 0, 0}, + {0x10D26, 230, 0, 0}, + {0x10D27, 230, 0, 0}, + {0x10EAB, 230, 0, 0}, + {0x10EAC, 230, 0, 0}, + {0x10F46, 220, 0, 0}, + {0x10F47, 220, 0, 0}, + {0x10F48, 230, 0, 0}, + {0x10F49, 230, 0, 0}, + {0x10F4A, 230, 0, 0}, + {0x10F4B, 220, 0, 0}, + {0x10F4C, 230, 0, 0}, + {0x10F4D, 220, 0, 0}, + {0x10F4E, 220, 0, 0}, + {0x10F4F, 220, 0, 0}, + {0x10F50, 220, 0, 0}, + {0x10F82, 230, 0, 0}, + {0x10F83, 220, 0, 0}, + {0x10F84, 230, 0, 0}, + {0x10F85, 220, 0, 0}, + {0x11046, 9, 0, 0}, + {0x11070, 9, 0, 0}, + {0x1107F, 9, 0, 0}, + {0x1109A, 0, 2, 4782}, + {0x1109C, 0, 2, 4784}, + {0x110AB, 0, 2, 4786}, + {0x110B9, 9, 0, 0}, + {0x110BA, 7, 0, 0}, + {0x11100, 230, 0, 0}, + {0x11101, 230, 0, 0}, + {0x11102, 230, 0, 0}, + {0x1112E, 0, 2, 4788}, + {0x1112F, 0, 2, 4790}, + {0x11133, 9, 0, 0}, + {0x11134, 9, 0, 0}, + {0x11173, 7, 0, 0}, + {0x111C0, 9, 0, 0}, + {0x111CA, 7, 0, 0}, + {0x11235, 9, 0, 0}, + {0x11236, 7, 0, 0}, + {0x112E9, 7, 0, 0}, + {0x112EA, 9, 0, 0}, + {0x1133B, 7, 0, 0}, + {0x1133C, 7, 0, 0}, + {0x1134B, 0, 2, 4792}, + {0x1134C, 0, 2, 4794}, + {0x1134D, 9, 0, 0}, + {0x11366, 230, 0, 0}, + {0x11367, 230, 0, 0}, + {0x11368, 230, 0, 0}, + {0x11369, 230, 0, 0}, + {0x1136A, 230, 0, 0}, + {0x1136B, 230, 0, 0}, + {0x1136C, 230, 0, 0}, + {0x11370, 230, 0, 0}, + {0x11371, 230, 0, 0}, + {0x11372, 230, 0, 0}, + {0x11373, 230, 0, 0}, + {0x11374, 230, 0, 0}, + {0x11442, 9, 0, 0}, + {0x11446, 7, 0, 0}, + {0x1145E, 230, 0, 0}, + {0x114BB, 0, 2, 4796}, + {0x114BC, 0, 2, 4798}, + {0x114BE, 0, 2, 4800}, + {0x114C2, 9, 0, 0}, + {0x114C3, 7, 0, 0}, + {0x115BA, 0, 2, 4802}, + {0x115BB, 0, 2, 4804}, + {0x115BF, 9, 0, 0}, + {0x115C0, 7, 0, 0}, + {0x1163F, 9, 0, 0}, + {0x116B6, 9, 0, 0}, + {0x116B7, 7, 0, 0}, + {0x1172B, 9, 0, 0}, + {0x11839, 9, 0, 0}, + {0x1183A, 7, 0, 0}, + {0x11938, 0, 2, 4806}, + {0x1193D, 9, 0, 0}, + {0x1193E, 9, 0, 0}, + {0x11943, 7, 0, 0}, + {0x119E0, 9, 0, 0}, + {0x11A34, 9, 0, 0}, + {0x11A47, 9, 0, 0}, + {0x11A99, 9, 0, 0}, + {0x11C3F, 9, 0, 0}, + {0x11D42, 7, 0, 0}, + {0x11D44, 9, 0, 0}, + {0x11D45, 9, 0, 0}, + {0x11D97, 9, 0, 0}, + {0x16AF0, 1, 0, 0}, + {0x16AF1, 1, 0, 0}, + {0x16AF2, 1, 0, 0}, + {0x16AF3, 1, 0, 0}, + {0x16AF4, 1, 0, 0}, + {0x16B30, 230, 0, 0}, + {0x16B31, 230, 0, 0}, + {0x16B32, 230, 0, 0}, + {0x16B33, 230, 0, 0}, + {0x16B34, 230, 0, 0}, + {0x16B35, 230, 0, 0}, + {0x16B36, 230, 0, 0}, + {0x16FF0, 6, 0, 0}, + {0x16FF1, 6, 0, 0}, + {0x1BC9E, 1, 0, 0}, + {0x1D15E, 0, 2 | DECOMP_NO_COMPOSE, 4808}, /* in exclusion list */ + {0x1D15F, 0, 2 | DECOMP_NO_COMPOSE, 4810}, /* in exclusion list */ + {0x1D160, 0, 2 | DECOMP_NO_COMPOSE, 4812}, /* in exclusion list */ + {0x1D161, 0, 2 | DECOMP_NO_COMPOSE, 4814}, /* in exclusion list */ + {0x1D162, 0, 2 | DECOMP_NO_COMPOSE, 4816}, /* in exclusion list */ + {0x1D163, 0, 2 | DECOMP_NO_COMPOSE, 4818}, /* in exclusion list */ + {0x1D164, 0, 2 | DECOMP_NO_COMPOSE, 4820}, /* in exclusion list */ + {0x1D165, 216, 0, 0}, + {0x1D166, 216, 0, 0}, + {0x1D167, 1, 0, 0}, + {0x1D168, 1, 0, 0}, + {0x1D169, 1, 0, 0}, + {0x1D16D, 226, 0, 0}, + {0x1D16E, 216, 0, 0}, + {0x1D16F, 216, 0, 0}, + {0x1D170, 216, 0, 0}, + {0x1D171, 216, 0, 0}, + {0x1D172, 216, 0, 0}, + {0x1D17B, 220, 0, 0}, + {0x1D17C, 220, 0, 0}, + {0x1D17D, 220, 0, 0}, + {0x1D17E, 220, 0, 0}, + {0x1D17F, 220, 0, 0}, + {0x1D180, 220, 0, 0}, + {0x1D181, 220, 0, 0}, + {0x1D182, 220, 0, 0}, + {0x1D185, 230, 0, 0}, + {0x1D186, 230, 0, 0}, + {0x1D187, 230, 0, 0}, + {0x1D188, 230, 0, 0}, + {0x1D189, 230, 0, 0}, + {0x1D18A, 220, 0, 0}, + {0x1D18B, 220, 0, 0}, + {0x1D1AA, 230, 0, 0}, + {0x1D1AB, 230, 0, 0}, + {0x1D1AC, 230, 0, 0}, + {0x1D1AD, 230, 0, 0}, + {0x1D1BB, 0, 2 | DECOMP_NO_COMPOSE, 4822}, /* in exclusion list */ + {0x1D1BC, 0, 2 | DECOMP_NO_COMPOSE, 4824}, /* in exclusion list */ + {0x1D1BD, 0, 2 | DECOMP_NO_COMPOSE, 4826}, /* in exclusion list */ + {0x1D1BE, 0, 2 | DECOMP_NO_COMPOSE, 4828}, /* in exclusion list */ + {0x1D1BF, 0, 2 | DECOMP_NO_COMPOSE, 4830}, /* in exclusion list */ + {0x1D1C0, 0, 2 | DECOMP_NO_COMPOSE, 4832}, /* in exclusion list */ + {0x1D242, 230, 0, 0}, + {0x1D243, 230, 0, 0}, + {0x1D244, 230, 0, 0}, + {0x1D400, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D401, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D402, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D403, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D404, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D405, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D406, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D407, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D408, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D409, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D40A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D40B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D40C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D40D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D40E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D40F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D410, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D411, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D412, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D413, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D414, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D415, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D416, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D417, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D418, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D419, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D41A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D41B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D41C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D41D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D41E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D41F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D420, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D421, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D422, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D423, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D424, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D425, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D426, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D427, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D428, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D429, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D42A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D42B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D42C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D42D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D42E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D42F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D430, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D431, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D432, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D433, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D434, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D435, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D436, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D437, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D438, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D439, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D43A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D43B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D43C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D43D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D43E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D43F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D440, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D441, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D442, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D443, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D444, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D445, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D446, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D447, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D448, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D449, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D44A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D44B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D44C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D44D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D44E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D44F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D450, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D451, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D452, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D453, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D454, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D456, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D457, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D458, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D459, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D45A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D45B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D45C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D45D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D45E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D45F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D460, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D461, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D462, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D463, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D464, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D465, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D466, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D467, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D468, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D469, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D46A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D46B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D46C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D46D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D46E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D46F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D470, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D471, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D472, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D473, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D474, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D475, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D476, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D477, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D478, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D479, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D47A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D47B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D47C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D47D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D47E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D47F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D480, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D481, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D482, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D483, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D484, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D485, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D486, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D487, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D488, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D489, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D48A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D48B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D48C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D48D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D48E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D48F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D490, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D491, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D492, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D493, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D494, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D495, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D496, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D497, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D498, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D499, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D49A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D49B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D49C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D49E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D49F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D4A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D4A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D4A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D4A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D4AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D4AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D4AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D4AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D4AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D4B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D4B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D4B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D4B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D4B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D4B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D4B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D4B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D4B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D4B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D4BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D4BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D4BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D4BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D4C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D4C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D4C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D4C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D4C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D4C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D4C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D4C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D4C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D4CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D4CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D4CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D4CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D4CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D4CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D4D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D4D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D4D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D4D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D4D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D4D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D4D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D4D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D4D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D4D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D4DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D4DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D4DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D4DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D4DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D4DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D4E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D4E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D4E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D4E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D4E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D4E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D4E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D4E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D4E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D4E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D4EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D4EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D4EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D4ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D4EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D4EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D4F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D4F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D4F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D4F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D4F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D4F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D4F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D4F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D4F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D4F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D4FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D4FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D4FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D4FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D4FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D4FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D500, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D501, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D502, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D503, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D504, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D505, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D507, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D508, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D509, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D50A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D50D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D50E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D50F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D510, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D511, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D512, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D513, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D514, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D516, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D517, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D518, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D519, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D51A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D51B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D51C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D51E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D51F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D520, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D521, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D522, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D523, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D524, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D525, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D526, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D527, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D528, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D529, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D52A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D52B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D52C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D52D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D52E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D52F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D530, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D531, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D532, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D533, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D534, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D535, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D536, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D537, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D538, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D539, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D53B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D53C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D53D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D53E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D540, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D541, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D542, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D543, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D544, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D546, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D54A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D54B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D54C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D54D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D54E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D54F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D550, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D552, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D553, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D554, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D555, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D556, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D557, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D558, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D559, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D55A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D55B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D55C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D55D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D55E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D55F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D560, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D561, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D562, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D563, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D564, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D565, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D566, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D567, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D568, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D569, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D56A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D56B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D56C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D56D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D56E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D56F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D570, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D571, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D572, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D573, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D574, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D575, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D576, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D577, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D578, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D579, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D57A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D57B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D57C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D57D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D57E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D57F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D580, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D581, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D582, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D583, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D584, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D585, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D586, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D587, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D588, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D589, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D58A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D58B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D58C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D58D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D58E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D58F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D590, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D591, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D592, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D593, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D594, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D595, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D596, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D597, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D598, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D599, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D59A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D59B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D59C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D59D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D59E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D59F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D5A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D5A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D5A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D5A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D5A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D5A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D5A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D5A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D5A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D5A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D5AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D5AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D5AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D5AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D5AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D5AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D5B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D5B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D5B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D5B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D5B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D5B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D5B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D5B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D5B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D5B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D5BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D5BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D5BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D5BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D5BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D5BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D5C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D5C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D5C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D5C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D5C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D5C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D5C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D5C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D5C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D5C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D5CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D5CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D5CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D5CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D5CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D5CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D5D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D5D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D5D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D5D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D5D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D5D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D5D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D5D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D5D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D5D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D5DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D5DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D5DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D5DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D5DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D5DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D5E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D5E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D5E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D5E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D5E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D5E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D5E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D5E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D5E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D5E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D5EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D5EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D5EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D5ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D5EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D5EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D5F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D5F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D5F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D5F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D5F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D5F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D5F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D5F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D5F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D5F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D5FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D5FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D5FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D5FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D5FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D5FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D600, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D601, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D602, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D603, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D604, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D605, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D606, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D607, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D608, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D609, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D60A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D60B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D60C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D60D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D60E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D60F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D610, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D611, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D612, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D613, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D614, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D615, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D616, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D617, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D618, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D619, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D61A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D61B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D61C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D61D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D61E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D61F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D620, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D621, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D622, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D623, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D624, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D625, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D626, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D627, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D628, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D629, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D62A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D62B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D62C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D62D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D62E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D62F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D630, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D631, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D632, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D633, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D634, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D635, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D636, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D637, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D638, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D639, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D63A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D63B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D63C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D63D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D63E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D63F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D640, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D641, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D642, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D643, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D644, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D645, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D646, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D647, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D648, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D649, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D64A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D64B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D64C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D64D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D64E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D64F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D650, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D651, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D652, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D653, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D654, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D655, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D656, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D657, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D658, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D659, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D65A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D65B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D65C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D65D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D65E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D65F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D660, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D661, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D662, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D663, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D664, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D665, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D666, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D667, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D668, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D669, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D66A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D66B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D66C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D66D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D66E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D66F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D670, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1D671, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1D672, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1D673, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1D674, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1D675, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1D676, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1D677, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1D678, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1D679, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1D67A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1D67B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1D67C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1D67D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1D67E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1D67F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1D680, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1D681, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1D682, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1D683, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1D684, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1D685, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1D686, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1D687, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1D688, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1D689, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1D68A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0061}, + {0x1D68B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0062}, + {0x1D68C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0063}, + {0x1D68D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0064}, + {0x1D68E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0065}, + {0x1D68F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0066}, + {0x1D690, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0067}, + {0x1D691, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0068}, + {0x1D692, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0069}, + {0x1D693, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006A}, + {0x1D694, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006B}, + {0x1D695, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006C}, + {0x1D696, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006D}, + {0x1D697, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006E}, + {0x1D698, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x006F}, + {0x1D699, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0070}, + {0x1D69A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0071}, + {0x1D69B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0072}, + {0x1D69C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0073}, + {0x1D69D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0074}, + {0x1D69E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0075}, + {0x1D69F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0076}, + {0x1D6A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0077}, + {0x1D6A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0078}, + {0x1D6A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0079}, + {0x1D6A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x007A}, + {0x1D6A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0131}, + {0x1D6A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0237}, + {0x1D6A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D6A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D6AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D6AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D6AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D6AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D6AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D6AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D6B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D6B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D6B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D6B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D6B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D6B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D6B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D6B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D6B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D6B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D6BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D6BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D6BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D6BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D6BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D6BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D6C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D6C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D6C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D6C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D6C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D6C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D6C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D6C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D6C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D6C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D6CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D6CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D6CC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D6CD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D6CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D6CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D6D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D6D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D6D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D6D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D6D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D6D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D6D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D6D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D6D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D6D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D6DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D6DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D6DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D6DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D6DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D6DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D6E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D6E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D6E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D6E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D6E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D6E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D6E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D6E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D6E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D6E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D6EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D6EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D6EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D6ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D6EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D6EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D6F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D6F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D6F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D6F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D6F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D6F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D6F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D6F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D6F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D6F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D6FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D6FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D6FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D6FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D6FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D6FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D700, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D701, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D702, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D703, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D704, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D705, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D706, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D707, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D708, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D709, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D70A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D70B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D70C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D70D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D70E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D70F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D710, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D711, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D712, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D713, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D714, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D715, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D716, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D717, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D718, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D719, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D71A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D71B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D71C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D71D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D71E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D71F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D720, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D721, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D722, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D723, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D724, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D725, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D726, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D727, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D728, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D729, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D72A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D72B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D72C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D72D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D72E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D72F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D730, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D731, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D732, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D733, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D734, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D735, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D736, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D737, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D738, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D739, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D73A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D73B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D73C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D73D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D73E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D73F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D740, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D741, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D742, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D743, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D744, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D745, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D746, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D747, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D748, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D749, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D74A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D74B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D74C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D74D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D74E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D74F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D750, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D751, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D752, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D753, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D754, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D755, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D756, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D757, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D758, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D759, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D75A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D75B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D75C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D75D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D75E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D75F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D760, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D761, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D762, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D763, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D764, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D765, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D766, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D767, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D768, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D769, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D76A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D76B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D76C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D76D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D76E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D76F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D770, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D771, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D772, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D773, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D774, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D775, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D776, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D777, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D778, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D779, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D77A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D77B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D77C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D77D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D77E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D77F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D780, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D781, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D782, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D783, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D784, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D785, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D786, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D787, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D788, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D789, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D78A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D78B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D78C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D78D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D78E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D78F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D790, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0391}, + {0x1D791, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0392}, + {0x1D792, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0393}, + {0x1D793, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0394}, + {0x1D794, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0395}, + {0x1D795, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0396}, + {0x1D796, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0397}, + {0x1D797, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0398}, + {0x1D798, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0399}, + {0x1D799, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039A}, + {0x1D79A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039B}, + {0x1D79B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039C}, + {0x1D79C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039D}, + {0x1D79D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039E}, + {0x1D79E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x039F}, + {0x1D79F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A0}, + {0x1D7A0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A1}, + {0x1D7A1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F4}, + {0x1D7A2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A3}, + {0x1D7A3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A4}, + {0x1D7A4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A5}, + {0x1D7A5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A6}, + {0x1D7A6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A7}, + {0x1D7A7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A8}, + {0x1D7A8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03A9}, + {0x1D7A9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2207}, + {0x1D7AA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B1}, + {0x1D7AB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B2}, + {0x1D7AC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B3}, + {0x1D7AD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B4}, + {0x1D7AE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B5}, + {0x1D7AF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B6}, + {0x1D7B0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B7}, + {0x1D7B1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B8}, + {0x1D7B2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03B9}, + {0x1D7B3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BA}, + {0x1D7B4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BB}, + {0x1D7B5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BC}, + {0x1D7B6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BD}, + {0x1D7B7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BE}, + {0x1D7B8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03BF}, + {0x1D7B9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C0}, + {0x1D7BA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C1}, + {0x1D7BB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C2}, + {0x1D7BC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C3}, + {0x1D7BD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C4}, + {0x1D7BE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C5}, + {0x1D7BF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C6}, + {0x1D7C0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C7}, + {0x1D7C1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C8}, + {0x1D7C2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03C9}, + {0x1D7C3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x2202}, + {0x1D7C4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F5}, + {0x1D7C5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D1}, + {0x1D7C6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F0}, + {0x1D7C7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D5}, + {0x1D7C8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03F1}, + {0x1D7C9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03D6}, + {0x1D7CA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03DC}, + {0x1D7CB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x03DD}, + {0x1D7CE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7CF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7D0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7D1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7D2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7D3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7D4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7D5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7D6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7D7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7D8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7D9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7DA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7DB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7DC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7DD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7DE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7DF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7E0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7E1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7E2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7E3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7E4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7E5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7E6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7E7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7E8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7E9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7EA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7EB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7EC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7ED, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7EE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7EF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7F0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7F1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7F2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7F3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7F4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7F5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1D7F6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1D7F7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1D7F8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1D7F9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1D7FA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1D7FB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1D7FC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1D7FD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1D7FE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1D7FF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x1E000, 230, 0, 0}, + {0x1E001, 230, 0, 0}, + {0x1E002, 230, 0, 0}, + {0x1E003, 230, 0, 0}, + {0x1E004, 230, 0, 0}, + {0x1E005, 230, 0, 0}, + {0x1E006, 230, 0, 0}, + {0x1E008, 230, 0, 0}, + {0x1E009, 230, 0, 0}, + {0x1E00A, 230, 0, 0}, + {0x1E00B, 230, 0, 0}, + {0x1E00C, 230, 0, 0}, + {0x1E00D, 230, 0, 0}, + {0x1E00E, 230, 0, 0}, + {0x1E00F, 230, 0, 0}, + {0x1E010, 230, 0, 0}, + {0x1E011, 230, 0, 0}, + {0x1E012, 230, 0, 0}, + {0x1E013, 230, 0, 0}, + {0x1E014, 230, 0, 0}, + {0x1E015, 230, 0, 0}, + {0x1E016, 230, 0, 0}, + {0x1E017, 230, 0, 0}, + {0x1E018, 230, 0, 0}, + {0x1E01B, 230, 0, 0}, + {0x1E01C, 230, 0, 0}, + {0x1E01D, 230, 0, 0}, + {0x1E01E, 230, 0, 0}, + {0x1E01F, 230, 0, 0}, + {0x1E020, 230, 0, 0}, + {0x1E021, 230, 0, 0}, + {0x1E023, 230, 0, 0}, + {0x1E024, 230, 0, 0}, + {0x1E026, 230, 0, 0}, + {0x1E027, 230, 0, 0}, + {0x1E028, 230, 0, 0}, + {0x1E029, 230, 0, 0}, + {0x1E02A, 230, 0, 0}, + {0x1E130, 230, 0, 0}, + {0x1E131, 230, 0, 0}, + {0x1E132, 230, 0, 0}, + {0x1E133, 230, 0, 0}, + {0x1E134, 230, 0, 0}, + {0x1E135, 230, 0, 0}, + {0x1E136, 230, 0, 0}, + {0x1E2AE, 230, 0, 0}, + {0x1E2EC, 230, 0, 0}, + {0x1E2ED, 230, 0, 0}, + {0x1E2EE, 230, 0, 0}, + {0x1E2EF, 230, 0, 0}, + {0x1E8D0, 220, 0, 0}, + {0x1E8D1, 220, 0, 0}, + {0x1E8D2, 220, 0, 0}, + {0x1E8D3, 220, 0, 0}, + {0x1E8D4, 220, 0, 0}, + {0x1E8D5, 220, 0, 0}, + {0x1E8D6, 220, 0, 0}, + {0x1E944, 230, 0, 0}, + {0x1E945, 230, 0, 0}, + {0x1E946, 230, 0, 0}, + {0x1E947, 230, 0, 0}, + {0x1E948, 230, 0, 0}, + {0x1E949, 230, 0, 0}, + {0x1E94A, 7, 0, 0}, + {0x1EE00, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0x1EE01, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE02, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE03, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EE05, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EE06, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EE07, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE08, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE09, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE0A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE0B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE0C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE0D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE0E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE0F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE10, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE11, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE12, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE13, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EE14, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE15, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE16, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE17, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE18, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EE19, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE1A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE1B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE1C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066E}, + {0x1EE1D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0x1EE1E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A1}, + {0x1EE1F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066F}, + {0x1EE21, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE22, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE24, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE27, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE29, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE2A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE2B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE2C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE2D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE2E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE2F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE30, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE31, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE32, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE34, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE35, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE36, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE37, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE39, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE3B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE42, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE47, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE49, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE4B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE4D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE4E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE4F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE51, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE52, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE54, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE57, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE59, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE5B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE5D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06BA}, + {0x1EE5F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066F}, + {0x1EE61, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE62, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE64, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE67, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE68, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE69, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE6A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0643}, + {0x1EE6C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE6D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE6E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE6F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE70, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE71, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE72, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE74, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE75, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE76, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE77, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE79, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE7A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE7B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EE7C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x066E}, + {0x1EE7E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x06A1}, + {0x1EE80, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0627}, + {0x1EE81, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EE82, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EE83, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EE84, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0647}, + {0x1EE85, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EE86, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EE87, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EE88, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EE89, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EE8B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EE8C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EE8D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EE8E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EE8F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EE90, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EE91, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EE92, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EE93, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EE94, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EE95, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EE96, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EE97, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EE98, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EE99, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EE9A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EE9B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1EEA1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0628}, + {0x1EEA2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062C}, + {0x1EEA3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062F}, + {0x1EEA5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0648}, + {0x1EEA6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0632}, + {0x1EEA7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062D}, + {0x1EEA8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0637}, + {0x1EEA9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x064A}, + {0x1EEAB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0644}, + {0x1EEAC, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0645}, + {0x1EEAD, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0646}, + {0x1EEAE, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0633}, + {0x1EEAF, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0639}, + {0x1EEB0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0641}, + {0x1EEB1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0635}, + {0x1EEB2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0642}, + {0x1EEB3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0631}, + {0x1EEB4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0634}, + {0x1EEB5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062A}, + {0x1EEB6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062B}, + {0x1EEB7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x062E}, + {0x1EEB8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0630}, + {0x1EEB9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0636}, + {0x1EEBA, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0638}, + {0x1EEBB, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x063A}, + {0x1F100, 0, 2 | DECOMP_COMPAT, 4834}, + {0x1F101, 0, 2 | DECOMP_COMPAT, 4836}, + {0x1F102, 0, 2 | DECOMP_COMPAT, 4838}, + {0x1F103, 0, 2 | DECOMP_COMPAT, 4840}, + {0x1F104, 0, 2 | DECOMP_COMPAT, 4842}, + {0x1F105, 0, 2 | DECOMP_COMPAT, 4844}, + {0x1F106, 0, 2 | DECOMP_COMPAT, 4846}, + {0x1F107, 0, 2 | DECOMP_COMPAT, 4848}, + {0x1F108, 0, 2 | DECOMP_COMPAT, 4850}, + {0x1F109, 0, 2 | DECOMP_COMPAT, 4852}, + {0x1F10A, 0, 2 | DECOMP_COMPAT, 4854}, + {0x1F110, 0, 3 | DECOMP_COMPAT, 4856}, + {0x1F111, 0, 3 | DECOMP_COMPAT, 4859}, + {0x1F112, 0, 3 | DECOMP_COMPAT, 4862}, + {0x1F113, 0, 3 | DECOMP_COMPAT, 4865}, + {0x1F114, 0, 3 | DECOMP_COMPAT, 4868}, + {0x1F115, 0, 3 | DECOMP_COMPAT, 4871}, + {0x1F116, 0, 3 | DECOMP_COMPAT, 4874}, + {0x1F117, 0, 3 | DECOMP_COMPAT, 4877}, + {0x1F118, 0, 3 | DECOMP_COMPAT, 4880}, + {0x1F119, 0, 3 | DECOMP_COMPAT, 4883}, + {0x1F11A, 0, 3 | DECOMP_COMPAT, 4886}, + {0x1F11B, 0, 3 | DECOMP_COMPAT, 4889}, + {0x1F11C, 0, 3 | DECOMP_COMPAT, 4892}, + {0x1F11D, 0, 3 | DECOMP_COMPAT, 4895}, + {0x1F11E, 0, 3 | DECOMP_COMPAT, 4898}, + {0x1F11F, 0, 3 | DECOMP_COMPAT, 4901}, + {0x1F120, 0, 3 | DECOMP_COMPAT, 4904}, + {0x1F121, 0, 3 | DECOMP_COMPAT, 4907}, + {0x1F122, 0, 3 | DECOMP_COMPAT, 4910}, + {0x1F123, 0, 3 | DECOMP_COMPAT, 4913}, + {0x1F124, 0, 3 | DECOMP_COMPAT, 4916}, + {0x1F125, 0, 3 | DECOMP_COMPAT, 4919}, + {0x1F126, 0, 3 | DECOMP_COMPAT, 4922}, + {0x1F127, 0, 3 | DECOMP_COMPAT, 4925}, + {0x1F128, 0, 3 | DECOMP_COMPAT, 4928}, + {0x1F129, 0, 3 | DECOMP_COMPAT, 4931}, + {0x1F12A, 0, 3 | DECOMP_COMPAT, 4934}, + {0x1F12B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1F12C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1F12D, 0, 2 | DECOMP_COMPAT, 4937}, + {0x1F12E, 0, 2 | DECOMP_COMPAT, 4939}, + {0x1F130, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0041}, + {0x1F131, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0042}, + {0x1F132, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0043}, + {0x1F133, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0044}, + {0x1F134, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0045}, + {0x1F135, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0046}, + {0x1F136, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0047}, + {0x1F137, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0048}, + {0x1F138, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0049}, + {0x1F139, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004A}, + {0x1F13A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004B}, + {0x1F13B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004C}, + {0x1F13C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004D}, + {0x1F13D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004E}, + {0x1F13E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x004F}, + {0x1F13F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0050}, + {0x1F140, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0051}, + {0x1F141, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0052}, + {0x1F142, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0053}, + {0x1F143, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0054}, + {0x1F144, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0055}, + {0x1F145, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0056}, + {0x1F146, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0057}, + {0x1F147, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0058}, + {0x1F148, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0059}, + {0x1F149, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x005A}, + {0x1F14A, 0, 2 | DECOMP_COMPAT, 4941}, + {0x1F14B, 0, 2 | DECOMP_COMPAT, 4943}, + {0x1F14C, 0, 2 | DECOMP_COMPAT, 4945}, + {0x1F14D, 0, 2 | DECOMP_COMPAT, 4947}, + {0x1F14E, 0, 3 | DECOMP_COMPAT, 4949}, + {0x1F14F, 0, 2 | DECOMP_COMPAT, 4952}, + {0x1F16A, 0, 2 | DECOMP_COMPAT, 4954}, + {0x1F16B, 0, 2 | DECOMP_COMPAT, 4956}, + {0x1F16C, 0, 2 | DECOMP_COMPAT, 4958}, + {0x1F190, 0, 2 | DECOMP_COMPAT, 4960}, + {0x1F200, 0, 2 | DECOMP_COMPAT, 4962}, + {0x1F201, 0, 2 | DECOMP_COMPAT, 4964}, + {0x1F202, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30B5}, + {0x1F210, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x624B}, + {0x1F211, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5B57}, + {0x1F212, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53CC}, + {0x1F213, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x30C7}, + {0x1F214, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E8C}, + {0x1F215, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x591A}, + {0x1F216, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x89E3}, + {0x1F217, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5929}, + {0x1F218, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4EA4}, + {0x1F219, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6620}, + {0x1F21A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7121}, + {0x1F21B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6599}, + {0x1F21C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x524D}, + {0x1F21D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F8C}, + {0x1F21E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x518D}, + {0x1F21F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x65B0}, + {0x1F220, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x521D}, + {0x1F221, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7D42}, + {0x1F222, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x751F}, + {0x1F223, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8CA9}, + {0x1F224, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x58F0}, + {0x1F225, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5439}, + {0x1F226, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6F14}, + {0x1F227, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6295}, + {0x1F228, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6355}, + {0x1F229, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E00}, + {0x1F22A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E09}, + {0x1F22B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x904A}, + {0x1F22C, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5DE6}, + {0x1F22D, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x4E2D}, + {0x1F22E, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53F3}, + {0x1F22F, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6307}, + {0x1F230, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x8D70}, + {0x1F231, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6253}, + {0x1F232, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7981}, + {0x1F233, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7A7A}, + {0x1F234, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5408}, + {0x1F235, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6E80}, + {0x1F236, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6709}, + {0x1F237, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x6708}, + {0x1F238, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x7533}, + {0x1F239, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5272}, + {0x1F23A, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x55B6}, + {0x1F23B, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x914D}, + {0x1F240, 0, 3 | DECOMP_COMPAT, 4966}, + {0x1F241, 0, 3 | DECOMP_COMPAT, 4969}, + {0x1F242, 0, 3 | DECOMP_COMPAT, 4972}, + {0x1F243, 0, 3 | DECOMP_COMPAT, 4975}, + {0x1F244, 0, 3 | DECOMP_COMPAT, 4978}, + {0x1F245, 0, 3 | DECOMP_COMPAT, 4981}, + {0x1F246, 0, 3 | DECOMP_COMPAT, 4984}, + {0x1F247, 0, 3 | DECOMP_COMPAT, 4987}, + {0x1F248, 0, 3 | DECOMP_COMPAT, 4990}, + {0x1F250, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x5F97}, + {0x1F251, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x53EF}, + {0x1FBF0, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0030}, + {0x1FBF1, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0031}, + {0x1FBF2, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0032}, + {0x1FBF3, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0033}, + {0x1FBF4, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0034}, + {0x1FBF5, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0035}, + {0x1FBF6, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0036}, + {0x1FBF7, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0037}, + {0x1FBF8, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0038}, + {0x1FBF9, 0, 1 | DECOMP_COMPAT | DECOMP_INLINE, 0x0039}, + {0x2F800, 0, 1 | DECOMP_INLINE, 0x4E3D}, + {0x2F801, 0, 1 | DECOMP_INLINE, 0x4E38}, + {0x2F802, 0, 1 | DECOMP_INLINE, 0x4E41}, + {0x2F803, 0, 1, 4993}, + {0x2F804, 0, 1 | DECOMP_INLINE, 0x4F60}, + {0x2F805, 0, 1 | DECOMP_INLINE, 0x4FAE}, + {0x2F806, 0, 1 | DECOMP_INLINE, 0x4FBB}, + {0x2F807, 0, 1 | DECOMP_INLINE, 0x5002}, + {0x2F808, 0, 1 | DECOMP_INLINE, 0x507A}, + {0x2F809, 0, 1 | DECOMP_INLINE, 0x5099}, + {0x2F80A, 0, 1 | DECOMP_INLINE, 0x50E7}, + {0x2F80B, 0, 1 | DECOMP_INLINE, 0x50CF}, + {0x2F80C, 0, 1 | DECOMP_INLINE, 0x349E}, + {0x2F80D, 0, 1, 4994}, + {0x2F80E, 0, 1 | DECOMP_INLINE, 0x514D}, + {0x2F80F, 0, 1 | DECOMP_INLINE, 0x5154}, + {0x2F810, 0, 1 | DECOMP_INLINE, 0x5164}, + {0x2F811, 0, 1 | DECOMP_INLINE, 0x5177}, + {0x2F812, 0, 1, 4995}, + {0x2F813, 0, 1 | DECOMP_INLINE, 0x34B9}, + {0x2F814, 0, 1 | DECOMP_INLINE, 0x5167}, + {0x2F815, 0, 1 | DECOMP_INLINE, 0x518D}, + {0x2F816, 0, 1, 4996}, + {0x2F817, 0, 1 | DECOMP_INLINE, 0x5197}, + {0x2F818, 0, 1 | DECOMP_INLINE, 0x51A4}, + {0x2F819, 0, 1 | DECOMP_INLINE, 0x4ECC}, + {0x2F81A, 0, 1 | DECOMP_INLINE, 0x51AC}, + {0x2F81B, 0, 1 | DECOMP_INLINE, 0x51B5}, + {0x2F81C, 0, 1, 4997}, + {0x2F81D, 0, 1 | DECOMP_INLINE, 0x51F5}, + {0x2F81E, 0, 1 | DECOMP_INLINE, 0x5203}, + {0x2F81F, 0, 1 | DECOMP_INLINE, 0x34DF}, + {0x2F820, 0, 1 | DECOMP_INLINE, 0x523B}, + {0x2F821, 0, 1 | DECOMP_INLINE, 0x5246}, + {0x2F822, 0, 1 | DECOMP_INLINE, 0x5272}, + {0x2F823, 0, 1 | DECOMP_INLINE, 0x5277}, + {0x2F824, 0, 1 | DECOMP_INLINE, 0x3515}, + {0x2F825, 0, 1 | DECOMP_INLINE, 0x52C7}, + {0x2F826, 0, 1 | DECOMP_INLINE, 0x52C9}, + {0x2F827, 0, 1 | DECOMP_INLINE, 0x52E4}, + {0x2F828, 0, 1 | DECOMP_INLINE, 0x52FA}, + {0x2F829, 0, 1 | DECOMP_INLINE, 0x5305}, + {0x2F82A, 0, 1 | DECOMP_INLINE, 0x5306}, + {0x2F82B, 0, 1 | DECOMP_INLINE, 0x5317}, + {0x2F82C, 0, 1 | DECOMP_INLINE, 0x5349}, + {0x2F82D, 0, 1 | DECOMP_INLINE, 0x5351}, + {0x2F82E, 0, 1 | DECOMP_INLINE, 0x535A}, + {0x2F82F, 0, 1 | DECOMP_INLINE, 0x5373}, + {0x2F830, 0, 1 | DECOMP_INLINE, 0x537D}, + {0x2F831, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F832, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F833, 0, 1 | DECOMP_INLINE, 0x537F}, + {0x2F834, 0, 1, 4998}, + {0x2F835, 0, 1 | DECOMP_INLINE, 0x7070}, + {0x2F836, 0, 1 | DECOMP_INLINE, 0x53CA}, + {0x2F837, 0, 1 | DECOMP_INLINE, 0x53DF}, + {0x2F838, 0, 1, 4999}, + {0x2F839, 0, 1 | DECOMP_INLINE, 0x53EB}, + {0x2F83A, 0, 1 | DECOMP_INLINE, 0x53F1}, + {0x2F83B, 0, 1 | DECOMP_INLINE, 0x5406}, + {0x2F83C, 0, 1 | DECOMP_INLINE, 0x549E}, + {0x2F83D, 0, 1 | DECOMP_INLINE, 0x5438}, + {0x2F83E, 0, 1 | DECOMP_INLINE, 0x5448}, + {0x2F83F, 0, 1 | DECOMP_INLINE, 0x5468}, + {0x2F840, 0, 1 | DECOMP_INLINE, 0x54A2}, + {0x2F841, 0, 1 | DECOMP_INLINE, 0x54F6}, + {0x2F842, 0, 1 | DECOMP_INLINE, 0x5510}, + {0x2F843, 0, 1 | DECOMP_INLINE, 0x5553}, + {0x2F844, 0, 1 | DECOMP_INLINE, 0x5563}, + {0x2F845, 0, 1 | DECOMP_INLINE, 0x5584}, + {0x2F846, 0, 1 | DECOMP_INLINE, 0x5584}, + {0x2F847, 0, 1 | DECOMP_INLINE, 0x5599}, + {0x2F848, 0, 1 | DECOMP_INLINE, 0x55AB}, + {0x2F849, 0, 1 | DECOMP_INLINE, 0x55B3}, + {0x2F84A, 0, 1 | DECOMP_INLINE, 0x55C2}, + {0x2F84B, 0, 1 | DECOMP_INLINE, 0x5716}, + {0x2F84C, 0, 1 | DECOMP_INLINE, 0x5606}, + {0x2F84D, 0, 1 | DECOMP_INLINE, 0x5717}, + {0x2F84E, 0, 1 | DECOMP_INLINE, 0x5651}, + {0x2F84F, 0, 1 | DECOMP_INLINE, 0x5674}, + {0x2F850, 0, 1 | DECOMP_INLINE, 0x5207}, + {0x2F851, 0, 1 | DECOMP_INLINE, 0x58EE}, + {0x2F852, 0, 1 | DECOMP_INLINE, 0x57CE}, + {0x2F853, 0, 1 | DECOMP_INLINE, 0x57F4}, + {0x2F854, 0, 1 | DECOMP_INLINE, 0x580D}, + {0x2F855, 0, 1 | DECOMP_INLINE, 0x578B}, + {0x2F856, 0, 1 | DECOMP_INLINE, 0x5832}, + {0x2F857, 0, 1 | DECOMP_INLINE, 0x5831}, + {0x2F858, 0, 1 | DECOMP_INLINE, 0x58AC}, + {0x2F859, 0, 1, 5000}, + {0x2F85A, 0, 1 | DECOMP_INLINE, 0x58F2}, + {0x2F85B, 0, 1 | DECOMP_INLINE, 0x58F7}, + {0x2F85C, 0, 1 | DECOMP_INLINE, 0x5906}, + {0x2F85D, 0, 1 | DECOMP_INLINE, 0x591A}, + {0x2F85E, 0, 1 | DECOMP_INLINE, 0x5922}, + {0x2F85F, 0, 1 | DECOMP_INLINE, 0x5962}, + {0x2F860, 0, 1, 5001}, + {0x2F861, 0, 1, 5002}, + {0x2F862, 0, 1 | DECOMP_INLINE, 0x59EC}, + {0x2F863, 0, 1 | DECOMP_INLINE, 0x5A1B}, + {0x2F864, 0, 1 | DECOMP_INLINE, 0x5A27}, + {0x2F865, 0, 1 | DECOMP_INLINE, 0x59D8}, + {0x2F866, 0, 1 | DECOMP_INLINE, 0x5A66}, + {0x2F867, 0, 1 | DECOMP_INLINE, 0x36EE}, + {0x2F868, 0, 1 | DECOMP_INLINE, 0x36FC}, + {0x2F869, 0, 1 | DECOMP_INLINE, 0x5B08}, + {0x2F86A, 0, 1 | DECOMP_INLINE, 0x5B3E}, + {0x2F86B, 0, 1 | DECOMP_INLINE, 0x5B3E}, + {0x2F86C, 0, 1, 5003}, + {0x2F86D, 0, 1 | DECOMP_INLINE, 0x5BC3}, + {0x2F86E, 0, 1 | DECOMP_INLINE, 0x5BD8}, + {0x2F86F, 0, 1 | DECOMP_INLINE, 0x5BE7}, + {0x2F870, 0, 1 | DECOMP_INLINE, 0x5BF3}, + {0x2F871, 0, 1, 5004}, + {0x2F872, 0, 1 | DECOMP_INLINE, 0x5BFF}, + {0x2F873, 0, 1 | DECOMP_INLINE, 0x5C06}, + {0x2F874, 0, 1 | DECOMP_INLINE, 0x5F53}, + {0x2F875, 0, 1 | DECOMP_INLINE, 0x5C22}, + {0x2F876, 0, 1 | DECOMP_INLINE, 0x3781}, + {0x2F877, 0, 1 | DECOMP_INLINE, 0x5C60}, + {0x2F878, 0, 1 | DECOMP_INLINE, 0x5C6E}, + {0x2F879, 0, 1 | DECOMP_INLINE, 0x5CC0}, + {0x2F87A, 0, 1 | DECOMP_INLINE, 0x5C8D}, + {0x2F87B, 0, 1, 5005}, + {0x2F87C, 0, 1 | DECOMP_INLINE, 0x5D43}, + {0x2F87D, 0, 1, 5006}, + {0x2F87E, 0, 1 | DECOMP_INLINE, 0x5D6E}, + {0x2F87F, 0, 1 | DECOMP_INLINE, 0x5D6B}, + {0x2F880, 0, 1 | DECOMP_INLINE, 0x5D7C}, + {0x2F881, 0, 1 | DECOMP_INLINE, 0x5DE1}, + {0x2F882, 0, 1 | DECOMP_INLINE, 0x5DE2}, + {0x2F883, 0, 1 | DECOMP_INLINE, 0x382F}, + {0x2F884, 0, 1 | DECOMP_INLINE, 0x5DFD}, + {0x2F885, 0, 1 | DECOMP_INLINE, 0x5E28}, + {0x2F886, 0, 1 | DECOMP_INLINE, 0x5E3D}, + {0x2F887, 0, 1 | DECOMP_INLINE, 0x5E69}, + {0x2F888, 0, 1 | DECOMP_INLINE, 0x3862}, + {0x2F889, 0, 1, 5007}, + {0x2F88A, 0, 1 | DECOMP_INLINE, 0x387C}, + {0x2F88B, 0, 1 | DECOMP_INLINE, 0x5EB0}, + {0x2F88C, 0, 1 | DECOMP_INLINE, 0x5EB3}, + {0x2F88D, 0, 1 | DECOMP_INLINE, 0x5EB6}, + {0x2F88E, 0, 1 | DECOMP_INLINE, 0x5ECA}, + {0x2F88F, 0, 1, 5008}, + {0x2F890, 0, 1 | DECOMP_INLINE, 0x5EFE}, + {0x2F891, 0, 1, 5009}, + {0x2F892, 0, 1, 5010}, + {0x2F893, 0, 1 | DECOMP_INLINE, 0x8201}, + {0x2F894, 0, 1 | DECOMP_INLINE, 0x5F22}, + {0x2F895, 0, 1 | DECOMP_INLINE, 0x5F22}, + {0x2F896, 0, 1 | DECOMP_INLINE, 0x38C7}, + {0x2F897, 0, 1, 5011}, + {0x2F898, 0, 1, 5012}, + {0x2F899, 0, 1 | DECOMP_INLINE, 0x5F62}, + {0x2F89A, 0, 1 | DECOMP_INLINE, 0x5F6B}, + {0x2F89B, 0, 1 | DECOMP_INLINE, 0x38E3}, + {0x2F89C, 0, 1 | DECOMP_INLINE, 0x5F9A}, + {0x2F89D, 0, 1 | DECOMP_INLINE, 0x5FCD}, + {0x2F89E, 0, 1 | DECOMP_INLINE, 0x5FD7}, + {0x2F89F, 0, 1 | DECOMP_INLINE, 0x5FF9}, + {0x2F8A0, 0, 1 | DECOMP_INLINE, 0x6081}, + {0x2F8A1, 0, 1 | DECOMP_INLINE, 0x393A}, + {0x2F8A2, 0, 1 | DECOMP_INLINE, 0x391C}, + {0x2F8A3, 0, 1 | DECOMP_INLINE, 0x6094}, + {0x2F8A4, 0, 1, 5013}, + {0x2F8A5, 0, 1 | DECOMP_INLINE, 0x60C7}, + {0x2F8A6, 0, 1 | DECOMP_INLINE, 0x6148}, + {0x2F8A7, 0, 1 | DECOMP_INLINE, 0x614C}, + {0x2F8A8, 0, 1 | DECOMP_INLINE, 0x614E}, + {0x2F8A9, 0, 1 | DECOMP_INLINE, 0x614C}, + {0x2F8AA, 0, 1 | DECOMP_INLINE, 0x617A}, + {0x2F8AB, 0, 1 | DECOMP_INLINE, 0x618E}, + {0x2F8AC, 0, 1 | DECOMP_INLINE, 0x61B2}, + {0x2F8AD, 0, 1 | DECOMP_INLINE, 0x61A4}, + {0x2F8AE, 0, 1 | DECOMP_INLINE, 0x61AF}, + {0x2F8AF, 0, 1 | DECOMP_INLINE, 0x61DE}, + {0x2F8B0, 0, 1 | DECOMP_INLINE, 0x61F2}, + {0x2F8B1, 0, 1 | DECOMP_INLINE, 0x61F6}, + {0x2F8B2, 0, 1 | DECOMP_INLINE, 0x6210}, + {0x2F8B3, 0, 1 | DECOMP_INLINE, 0x621B}, + {0x2F8B4, 0, 1 | DECOMP_INLINE, 0x625D}, + {0x2F8B5, 0, 1 | DECOMP_INLINE, 0x62B1}, + {0x2F8B6, 0, 1 | DECOMP_INLINE, 0x62D4}, + {0x2F8B7, 0, 1 | DECOMP_INLINE, 0x6350}, + {0x2F8B8, 0, 1, 5014}, + {0x2F8B9, 0, 1 | DECOMP_INLINE, 0x633D}, + {0x2F8BA, 0, 1 | DECOMP_INLINE, 0x62FC}, + {0x2F8BB, 0, 1 | DECOMP_INLINE, 0x6368}, + {0x2F8BC, 0, 1 | DECOMP_INLINE, 0x6383}, + {0x2F8BD, 0, 1 | DECOMP_INLINE, 0x63E4}, + {0x2F8BE, 0, 1, 5015}, + {0x2F8BF, 0, 1 | DECOMP_INLINE, 0x6422}, + {0x2F8C0, 0, 1 | DECOMP_INLINE, 0x63C5}, + {0x2F8C1, 0, 1 | DECOMP_INLINE, 0x63A9}, + {0x2F8C2, 0, 1 | DECOMP_INLINE, 0x3A2E}, + {0x2F8C3, 0, 1 | DECOMP_INLINE, 0x6469}, + {0x2F8C4, 0, 1 | DECOMP_INLINE, 0x647E}, + {0x2F8C5, 0, 1 | DECOMP_INLINE, 0x649D}, + {0x2F8C6, 0, 1 | DECOMP_INLINE, 0x6477}, + {0x2F8C7, 0, 1 | DECOMP_INLINE, 0x3A6C}, + {0x2F8C8, 0, 1 | DECOMP_INLINE, 0x654F}, + {0x2F8C9, 0, 1 | DECOMP_INLINE, 0x656C}, + {0x2F8CA, 0, 1, 5016}, + {0x2F8CB, 0, 1 | DECOMP_INLINE, 0x65E3}, + {0x2F8CC, 0, 1 | DECOMP_INLINE, 0x66F8}, + {0x2F8CD, 0, 1 | DECOMP_INLINE, 0x6649}, + {0x2F8CE, 0, 1 | DECOMP_INLINE, 0x3B19}, + {0x2F8CF, 0, 1 | DECOMP_INLINE, 0x6691}, + {0x2F8D0, 0, 1 | DECOMP_INLINE, 0x3B08}, + {0x2F8D1, 0, 1 | DECOMP_INLINE, 0x3AE4}, + {0x2F8D2, 0, 1 | DECOMP_INLINE, 0x5192}, + {0x2F8D3, 0, 1 | DECOMP_INLINE, 0x5195}, + {0x2F8D4, 0, 1 | DECOMP_INLINE, 0x6700}, + {0x2F8D5, 0, 1 | DECOMP_INLINE, 0x669C}, + {0x2F8D6, 0, 1 | DECOMP_INLINE, 0x80AD}, + {0x2F8D7, 0, 1 | DECOMP_INLINE, 0x43D9}, + {0x2F8D8, 0, 1 | DECOMP_INLINE, 0x6717}, + {0x2F8D9, 0, 1 | DECOMP_INLINE, 0x671B}, + {0x2F8DA, 0, 1 | DECOMP_INLINE, 0x6721}, + {0x2F8DB, 0, 1 | DECOMP_INLINE, 0x675E}, + {0x2F8DC, 0, 1 | DECOMP_INLINE, 0x6753}, + {0x2F8DD, 0, 1, 5017}, + {0x2F8DE, 0, 1 | DECOMP_INLINE, 0x3B49}, + {0x2F8DF, 0, 1 | DECOMP_INLINE, 0x67FA}, + {0x2F8E0, 0, 1 | DECOMP_INLINE, 0x6785}, + {0x2F8E1, 0, 1 | DECOMP_INLINE, 0x6852}, + {0x2F8E2, 0, 1 | DECOMP_INLINE, 0x6885}, + {0x2F8E3, 0, 1, 5018}, + {0x2F8E4, 0, 1 | DECOMP_INLINE, 0x688E}, + {0x2F8E5, 0, 1 | DECOMP_INLINE, 0x681F}, + {0x2F8E6, 0, 1 | DECOMP_INLINE, 0x6914}, + {0x2F8E7, 0, 1 | DECOMP_INLINE, 0x3B9D}, + {0x2F8E8, 0, 1 | DECOMP_INLINE, 0x6942}, + {0x2F8E9, 0, 1 | DECOMP_INLINE, 0x69A3}, + {0x2F8EA, 0, 1 | DECOMP_INLINE, 0x69EA}, + {0x2F8EB, 0, 1 | DECOMP_INLINE, 0x6AA8}, + {0x2F8EC, 0, 1, 5019}, + {0x2F8ED, 0, 1 | DECOMP_INLINE, 0x6ADB}, + {0x2F8EE, 0, 1 | DECOMP_INLINE, 0x3C18}, + {0x2F8EF, 0, 1 | DECOMP_INLINE, 0x6B21}, + {0x2F8F0, 0, 1, 5020}, + {0x2F8F1, 0, 1 | DECOMP_INLINE, 0x6B54}, + {0x2F8F2, 0, 1 | DECOMP_INLINE, 0x3C4E}, + {0x2F8F3, 0, 1 | DECOMP_INLINE, 0x6B72}, + {0x2F8F4, 0, 1 | DECOMP_INLINE, 0x6B9F}, + {0x2F8F5, 0, 1 | DECOMP_INLINE, 0x6BBA}, + {0x2F8F6, 0, 1 | DECOMP_INLINE, 0x6BBB}, + {0x2F8F7, 0, 1, 5021}, + {0x2F8F8, 0, 1, 5022}, + {0x2F8F9, 0, 1, 5023}, + {0x2F8FA, 0, 1 | DECOMP_INLINE, 0x6C4E}, + {0x2F8FB, 0, 1, 5024}, + {0x2F8FC, 0, 1 | DECOMP_INLINE, 0x6CBF}, + {0x2F8FD, 0, 1 | DECOMP_INLINE, 0x6CCD}, + {0x2F8FE, 0, 1 | DECOMP_INLINE, 0x6C67}, + {0x2F8FF, 0, 1 | DECOMP_INLINE, 0x6D16}, + {0x2F900, 0, 1 | DECOMP_INLINE, 0x6D3E}, + {0x2F901, 0, 1 | DECOMP_INLINE, 0x6D77}, + {0x2F902, 0, 1 | DECOMP_INLINE, 0x6D41}, + {0x2F903, 0, 1 | DECOMP_INLINE, 0x6D69}, + {0x2F904, 0, 1 | DECOMP_INLINE, 0x6D78}, + {0x2F905, 0, 1 | DECOMP_INLINE, 0x6D85}, + {0x2F906, 0, 1, 5025}, + {0x2F907, 0, 1 | DECOMP_INLINE, 0x6D34}, + {0x2F908, 0, 1 | DECOMP_INLINE, 0x6E2F}, + {0x2F909, 0, 1 | DECOMP_INLINE, 0x6E6E}, + {0x2F90A, 0, 1 | DECOMP_INLINE, 0x3D33}, + {0x2F90B, 0, 1 | DECOMP_INLINE, 0x6ECB}, + {0x2F90C, 0, 1 | DECOMP_INLINE, 0x6EC7}, + {0x2F90D, 0, 1, 5026}, + {0x2F90E, 0, 1 | DECOMP_INLINE, 0x6DF9}, + {0x2F90F, 0, 1 | DECOMP_INLINE, 0x6F6E}, + {0x2F910, 0, 1, 5027}, + {0x2F911, 0, 1, 5028}, + {0x2F912, 0, 1 | DECOMP_INLINE, 0x6FC6}, + {0x2F913, 0, 1 | DECOMP_INLINE, 0x7039}, + {0x2F914, 0, 1 | DECOMP_INLINE, 0x701E}, + {0x2F915, 0, 1 | DECOMP_INLINE, 0x701B}, + {0x2F916, 0, 1 | DECOMP_INLINE, 0x3D96}, + {0x2F917, 0, 1 | DECOMP_INLINE, 0x704A}, + {0x2F918, 0, 1 | DECOMP_INLINE, 0x707D}, + {0x2F919, 0, 1 | DECOMP_INLINE, 0x7077}, + {0x2F91A, 0, 1 | DECOMP_INLINE, 0x70AD}, + {0x2F91B, 0, 1, 5029}, + {0x2F91C, 0, 1 | DECOMP_INLINE, 0x7145}, + {0x2F91D, 0, 1, 5030}, + {0x2F91E, 0, 1 | DECOMP_INLINE, 0x719C}, + {0x2F91F, 0, 1, 5031}, + {0x2F920, 0, 1 | DECOMP_INLINE, 0x7228}, + {0x2F921, 0, 1 | DECOMP_INLINE, 0x7235}, + {0x2F922, 0, 1 | DECOMP_INLINE, 0x7250}, + {0x2F923, 0, 1, 5032}, + {0x2F924, 0, 1 | DECOMP_INLINE, 0x7280}, + {0x2F925, 0, 1 | DECOMP_INLINE, 0x7295}, + {0x2F926, 0, 1, 5033}, + {0x2F927, 0, 1, 5034}, + {0x2F928, 0, 1 | DECOMP_INLINE, 0x737A}, + {0x2F929, 0, 1 | DECOMP_INLINE, 0x738B}, + {0x2F92A, 0, 1 | DECOMP_INLINE, 0x3EAC}, + {0x2F92B, 0, 1 | DECOMP_INLINE, 0x73A5}, + {0x2F92C, 0, 1 | DECOMP_INLINE, 0x3EB8}, + {0x2F92D, 0, 1 | DECOMP_INLINE, 0x3EB8}, + {0x2F92E, 0, 1 | DECOMP_INLINE, 0x7447}, + {0x2F92F, 0, 1 | DECOMP_INLINE, 0x745C}, + {0x2F930, 0, 1 | DECOMP_INLINE, 0x7471}, + {0x2F931, 0, 1 | DECOMP_INLINE, 0x7485}, + {0x2F932, 0, 1 | DECOMP_INLINE, 0x74CA}, + {0x2F933, 0, 1 | DECOMP_INLINE, 0x3F1B}, + {0x2F934, 0, 1 | DECOMP_INLINE, 0x7524}, + {0x2F935, 0, 1, 5035}, + {0x2F936, 0, 1 | DECOMP_INLINE, 0x753E}, + {0x2F937, 0, 1, 5036}, + {0x2F938, 0, 1 | DECOMP_INLINE, 0x7570}, + {0x2F939, 0, 1, 5037}, + {0x2F93A, 0, 1 | DECOMP_INLINE, 0x7610}, + {0x2F93B, 0, 1, 5038}, + {0x2F93C, 0, 1, 5039}, + {0x2F93D, 0, 1, 5040}, + {0x2F93E, 0, 1 | DECOMP_INLINE, 0x3FFC}, + {0x2F93F, 0, 1 | DECOMP_INLINE, 0x4008}, + {0x2F940, 0, 1 | DECOMP_INLINE, 0x76F4}, + {0x2F941, 0, 1, 5041}, + {0x2F942, 0, 1, 5042}, + {0x2F943, 0, 1, 5043}, + {0x2F944, 0, 1, 5044}, + {0x2F945, 0, 1 | DECOMP_INLINE, 0x771E}, + {0x2F946, 0, 1 | DECOMP_INLINE, 0x771F}, + {0x2F947, 0, 1 | DECOMP_INLINE, 0x771F}, + {0x2F948, 0, 1 | DECOMP_INLINE, 0x774A}, + {0x2F949, 0, 1 | DECOMP_INLINE, 0x4039}, + {0x2F94A, 0, 1 | DECOMP_INLINE, 0x778B}, + {0x2F94B, 0, 1 | DECOMP_INLINE, 0x4046}, + {0x2F94C, 0, 1 | DECOMP_INLINE, 0x4096}, + {0x2F94D, 0, 1, 5045}, + {0x2F94E, 0, 1 | DECOMP_INLINE, 0x784E}, + {0x2F94F, 0, 1 | DECOMP_INLINE, 0x788C}, + {0x2F950, 0, 1 | DECOMP_INLINE, 0x78CC}, + {0x2F951, 0, 1 | DECOMP_INLINE, 0x40E3}, + {0x2F952, 0, 1, 5046}, + {0x2F953, 0, 1 | DECOMP_INLINE, 0x7956}, + {0x2F954, 0, 1, 5047}, + {0x2F955, 0, 1, 5048}, + {0x2F956, 0, 1 | DECOMP_INLINE, 0x798F}, + {0x2F957, 0, 1 | DECOMP_INLINE, 0x79EB}, + {0x2F958, 0, 1 | DECOMP_INLINE, 0x412F}, + {0x2F959, 0, 1 | DECOMP_INLINE, 0x7A40}, + {0x2F95A, 0, 1 | DECOMP_INLINE, 0x7A4A}, + {0x2F95B, 0, 1 | DECOMP_INLINE, 0x7A4F}, + {0x2F95C, 0, 1, 5049}, + {0x2F95D, 0, 1, 5050}, + {0x2F95E, 0, 1, 5051}, + {0x2F95F, 0, 1 | DECOMP_INLINE, 0x7AEE}, + {0x2F960, 0, 1 | DECOMP_INLINE, 0x4202}, + {0x2F961, 0, 1, 5052}, + {0x2F962, 0, 1 | DECOMP_INLINE, 0x7BC6}, + {0x2F963, 0, 1 | DECOMP_INLINE, 0x7BC9}, + {0x2F964, 0, 1 | DECOMP_INLINE, 0x4227}, + {0x2F965, 0, 1, 5053}, + {0x2F966, 0, 1 | DECOMP_INLINE, 0x7CD2}, + {0x2F967, 0, 1 | DECOMP_INLINE, 0x42A0}, + {0x2F968, 0, 1 | DECOMP_INLINE, 0x7CE8}, + {0x2F969, 0, 1 | DECOMP_INLINE, 0x7CE3}, + {0x2F96A, 0, 1 | DECOMP_INLINE, 0x7D00}, + {0x2F96B, 0, 1, 5054}, + {0x2F96C, 0, 1 | DECOMP_INLINE, 0x7D63}, + {0x2F96D, 0, 1 | DECOMP_INLINE, 0x4301}, + {0x2F96E, 0, 1 | DECOMP_INLINE, 0x7DC7}, + {0x2F96F, 0, 1 | DECOMP_INLINE, 0x7E02}, + {0x2F970, 0, 1 | DECOMP_INLINE, 0x7E45}, + {0x2F971, 0, 1 | DECOMP_INLINE, 0x4334}, + {0x2F972, 0, 1, 5055}, + {0x2F973, 0, 1, 5056}, + {0x2F974, 0, 1 | DECOMP_INLINE, 0x4359}, + {0x2F975, 0, 1, 5057}, + {0x2F976, 0, 1 | DECOMP_INLINE, 0x7F7A}, + {0x2F977, 0, 1, 5058}, + {0x2F978, 0, 1 | DECOMP_INLINE, 0x7F95}, + {0x2F979, 0, 1 | DECOMP_INLINE, 0x7FFA}, + {0x2F97A, 0, 1 | DECOMP_INLINE, 0x8005}, + {0x2F97B, 0, 1, 5059}, + {0x2F97C, 0, 1, 5060}, + {0x2F97D, 0, 1 | DECOMP_INLINE, 0x8060}, + {0x2F97E, 0, 1, 5061}, + {0x2F97F, 0, 1 | DECOMP_INLINE, 0x8070}, + {0x2F980, 0, 1, 5062}, + {0x2F981, 0, 1 | DECOMP_INLINE, 0x43D5}, + {0x2F982, 0, 1 | DECOMP_INLINE, 0x80B2}, + {0x2F983, 0, 1 | DECOMP_INLINE, 0x8103}, + {0x2F984, 0, 1 | DECOMP_INLINE, 0x440B}, + {0x2F985, 0, 1 | DECOMP_INLINE, 0x813E}, + {0x2F986, 0, 1 | DECOMP_INLINE, 0x5AB5}, + {0x2F987, 0, 1, 5063}, + {0x2F988, 0, 1, 5064}, + {0x2F989, 0, 1, 5065}, + {0x2F98A, 0, 1, 5066}, + {0x2F98B, 0, 1 | DECOMP_INLINE, 0x8201}, + {0x2F98C, 0, 1 | DECOMP_INLINE, 0x8204}, + {0x2F98D, 0, 1 | DECOMP_INLINE, 0x8F9E}, + {0x2F98E, 0, 1 | DECOMP_INLINE, 0x446B}, + {0x2F98F, 0, 1 | DECOMP_INLINE, 0x8291}, + {0x2F990, 0, 1 | DECOMP_INLINE, 0x828B}, + {0x2F991, 0, 1 | DECOMP_INLINE, 0x829D}, + {0x2F992, 0, 1 | DECOMP_INLINE, 0x52B3}, + {0x2F993, 0, 1 | DECOMP_INLINE, 0x82B1}, + {0x2F994, 0, 1 | DECOMP_INLINE, 0x82B3}, + {0x2F995, 0, 1 | DECOMP_INLINE, 0x82BD}, + {0x2F996, 0, 1 | DECOMP_INLINE, 0x82E6}, + {0x2F997, 0, 1, 5067}, + {0x2F998, 0, 1 | DECOMP_INLINE, 0x82E5}, + {0x2F999, 0, 1 | DECOMP_INLINE, 0x831D}, + {0x2F99A, 0, 1 | DECOMP_INLINE, 0x8363}, + {0x2F99B, 0, 1 | DECOMP_INLINE, 0x83AD}, + {0x2F99C, 0, 1 | DECOMP_INLINE, 0x8323}, + {0x2F99D, 0, 1 | DECOMP_INLINE, 0x83BD}, + {0x2F99E, 0, 1 | DECOMP_INLINE, 0x83E7}, + {0x2F99F, 0, 1 | DECOMP_INLINE, 0x8457}, + {0x2F9A0, 0, 1 | DECOMP_INLINE, 0x8353}, + {0x2F9A1, 0, 1 | DECOMP_INLINE, 0x83CA}, + {0x2F9A2, 0, 1 | DECOMP_INLINE, 0x83CC}, + {0x2F9A3, 0, 1 | DECOMP_INLINE, 0x83DC}, + {0x2F9A4, 0, 1, 5068}, + {0x2F9A5, 0, 1, 5069}, + {0x2F9A6, 0, 1, 5070}, + {0x2F9A7, 0, 1 | DECOMP_INLINE, 0x452B}, + {0x2F9A8, 0, 1 | DECOMP_INLINE, 0x84F1}, + {0x2F9A9, 0, 1 | DECOMP_INLINE, 0x84F3}, + {0x2F9AA, 0, 1 | DECOMP_INLINE, 0x8516}, + {0x2F9AB, 0, 1, 5071}, + {0x2F9AC, 0, 1 | DECOMP_INLINE, 0x8564}, + {0x2F9AD, 0, 1, 5072}, + {0x2F9AE, 0, 1 | DECOMP_INLINE, 0x455D}, + {0x2F9AF, 0, 1 | DECOMP_INLINE, 0x4561}, + {0x2F9B0, 0, 1, 5073}, + {0x2F9B1, 0, 1, 5074}, + {0x2F9B2, 0, 1 | DECOMP_INLINE, 0x456B}, + {0x2F9B3, 0, 1 | DECOMP_INLINE, 0x8650}, + {0x2F9B4, 0, 1 | DECOMP_INLINE, 0x865C}, + {0x2F9B5, 0, 1 | DECOMP_INLINE, 0x8667}, + {0x2F9B6, 0, 1 | DECOMP_INLINE, 0x8669}, + {0x2F9B7, 0, 1 | DECOMP_INLINE, 0x86A9}, + {0x2F9B8, 0, 1 | DECOMP_INLINE, 0x8688}, + {0x2F9B9, 0, 1 | DECOMP_INLINE, 0x870E}, + {0x2F9BA, 0, 1 | DECOMP_INLINE, 0x86E2}, + {0x2F9BB, 0, 1 | DECOMP_INLINE, 0x8779}, + {0x2F9BC, 0, 1 | DECOMP_INLINE, 0x8728}, + {0x2F9BD, 0, 1 | DECOMP_INLINE, 0x876B}, + {0x2F9BE, 0, 1 | DECOMP_INLINE, 0x8786}, + {0x2F9BF, 0, 1 | DECOMP_INLINE, 0x45D7}, + {0x2F9C0, 0, 1 | DECOMP_INLINE, 0x87E1}, + {0x2F9C1, 0, 1 | DECOMP_INLINE, 0x8801}, + {0x2F9C2, 0, 1 | DECOMP_INLINE, 0x45F9}, + {0x2F9C3, 0, 1 | DECOMP_INLINE, 0x8860}, + {0x2F9C4, 0, 1 | DECOMP_INLINE, 0x8863}, + {0x2F9C5, 0, 1, 5075}, + {0x2F9C6, 0, 1 | DECOMP_INLINE, 0x88D7}, + {0x2F9C7, 0, 1 | DECOMP_INLINE, 0x88DE}, + {0x2F9C8, 0, 1 | DECOMP_INLINE, 0x4635}, + {0x2F9C9, 0, 1 | DECOMP_INLINE, 0x88FA}, + {0x2F9CA, 0, 1 | DECOMP_INLINE, 0x34BB}, + {0x2F9CB, 0, 1, 5076}, + {0x2F9CC, 0, 1, 5077}, + {0x2F9CD, 0, 1 | DECOMP_INLINE, 0x46BE}, + {0x2F9CE, 0, 1 | DECOMP_INLINE, 0x46C7}, + {0x2F9CF, 0, 1 | DECOMP_INLINE, 0x8AA0}, + {0x2F9D0, 0, 1 | DECOMP_INLINE, 0x8AED}, + {0x2F9D1, 0, 1 | DECOMP_INLINE, 0x8B8A}, + {0x2F9D2, 0, 1 | DECOMP_INLINE, 0x8C55}, + {0x2F9D3, 0, 1, 5078}, + {0x2F9D4, 0, 1 | DECOMP_INLINE, 0x8CAB}, + {0x2F9D5, 0, 1 | DECOMP_INLINE, 0x8CC1}, + {0x2F9D6, 0, 1 | DECOMP_INLINE, 0x8D1B}, + {0x2F9D7, 0, 1 | DECOMP_INLINE, 0x8D77}, + {0x2F9D8, 0, 1, 5079}, + {0x2F9D9, 0, 1, 5080}, + {0x2F9DA, 0, 1 | DECOMP_INLINE, 0x8DCB}, + {0x2F9DB, 0, 1 | DECOMP_INLINE, 0x8DBC}, + {0x2F9DC, 0, 1 | DECOMP_INLINE, 0x8DF0}, + {0x2F9DD, 0, 1, 5081}, + {0x2F9DE, 0, 1 | DECOMP_INLINE, 0x8ED4}, + {0x2F9DF, 0, 1 | DECOMP_INLINE, 0x8F38}, + {0x2F9E0, 0, 1, 5082}, + {0x2F9E1, 0, 1, 5083}, + {0x2F9E2, 0, 1 | DECOMP_INLINE, 0x9094}, + {0x2F9E3, 0, 1 | DECOMP_INLINE, 0x90F1}, + {0x2F9E4, 0, 1 | DECOMP_INLINE, 0x9111}, + {0x2F9E5, 0, 1, 5084}, + {0x2F9E6, 0, 1 | DECOMP_INLINE, 0x911B}, + {0x2F9E7, 0, 1 | DECOMP_INLINE, 0x9238}, + {0x2F9E8, 0, 1 | DECOMP_INLINE, 0x92D7}, + {0x2F9E9, 0, 1 | DECOMP_INLINE, 0x92D8}, + {0x2F9EA, 0, 1 | DECOMP_INLINE, 0x927C}, + {0x2F9EB, 0, 1 | DECOMP_INLINE, 0x93F9}, + {0x2F9EC, 0, 1 | DECOMP_INLINE, 0x9415}, + {0x2F9ED, 0, 1, 5085}, + {0x2F9EE, 0, 1 | DECOMP_INLINE, 0x958B}, + {0x2F9EF, 0, 1 | DECOMP_INLINE, 0x4995}, + {0x2F9F0, 0, 1 | DECOMP_INLINE, 0x95B7}, + {0x2F9F1, 0, 1, 5086}, + {0x2F9F2, 0, 1 | DECOMP_INLINE, 0x49E6}, + {0x2F9F3, 0, 1 | DECOMP_INLINE, 0x96C3}, + {0x2F9F4, 0, 1 | DECOMP_INLINE, 0x5DB2}, + {0x2F9F5, 0, 1 | DECOMP_INLINE, 0x9723}, + {0x2F9F6, 0, 1, 5087}, + {0x2F9F7, 0, 1, 5088}, + {0x2F9F8, 0, 1 | DECOMP_INLINE, 0x4A6E}, + {0x2F9F9, 0, 1 | DECOMP_INLINE, 0x4A76}, + {0x2F9FA, 0, 1 | DECOMP_INLINE, 0x97E0}, + {0x2F9FB, 0, 1, 5089}, + {0x2F9FC, 0, 1 | DECOMP_INLINE, 0x4AB2}, + {0x2F9FD, 0, 1, 5090}, + {0x2F9FE, 0, 1 | DECOMP_INLINE, 0x980B}, + {0x2F9FF, 0, 1 | DECOMP_INLINE, 0x980B}, + {0x2FA00, 0, 1 | DECOMP_INLINE, 0x9829}, + {0x2FA01, 0, 1, 5091}, + {0x2FA02, 0, 1 | DECOMP_INLINE, 0x98E2}, + {0x2FA03, 0, 1 | DECOMP_INLINE, 0x4B33}, + {0x2FA04, 0, 1 | DECOMP_INLINE, 0x9929}, + {0x2FA05, 0, 1 | DECOMP_INLINE, 0x99A7}, + {0x2FA06, 0, 1 | DECOMP_INLINE, 0x99C2}, + {0x2FA07, 0, 1 | DECOMP_INLINE, 0x99FE}, + {0x2FA08, 0, 1 | DECOMP_INLINE, 0x4BCE}, + {0x2FA09, 0, 1, 5092}, + {0x2FA0A, 0, 1 | DECOMP_INLINE, 0x9B12}, + {0x2FA0B, 0, 1 | DECOMP_INLINE, 0x9C40}, + {0x2FA0C, 0, 1 | DECOMP_INLINE, 0x9CFD}, + {0x2FA0D, 0, 1 | DECOMP_INLINE, 0x4CCE}, + {0x2FA0E, 0, 1 | DECOMP_INLINE, 0x4CED}, + {0x2FA0F, 0, 1 | DECOMP_INLINE, 0x9D67}, + {0x2FA10, 0, 1, 5093}, + {0x2FA11, 0, 1 | DECOMP_INLINE, 0x4CF8}, + {0x2FA12, 0, 1, 5094}, + {0x2FA13, 0, 1, 5095}, + {0x2FA14, 0, 1, 5096}, + {0x2FA15, 0, 1 | DECOMP_INLINE, 0x9EBB}, + {0x2FA16, 0, 1 | DECOMP_INLINE, 0x4D56}, + {0x2FA17, 0, 1 | DECOMP_INLINE, 0x9EF9}, + {0x2FA18, 0, 1 | DECOMP_INLINE, 0x9EFE}, + {0x2FA19, 0, 1 | DECOMP_INLINE, 0x9F05}, + {0x2FA1A, 0, 1 | DECOMP_INLINE, 0x9F0F}, + {0x2FA1B, 0, 1 | DECOMP_INLINE, 0x9F16}, + {0x2FA1C, 0, 1 | DECOMP_INLINE, 0x9F3B}, + {0x2FA1D, 0, 1, 5097} + +}; + +/* codepoints array */ +static const uint32 UnicodeDecomp_codepoints[5098] = +{ + /* 0 */ 0x0020, 0x0308, + /* 2 */ 0x0020, 0x0304, + /* 4 */ 0x0020, 0x0301, + /* 6 */ 0x0020, 0x0327, + /* 8 */ 0x0031, 0x2044, 0x0034, + /* 11 */ 0x0031, 0x2044, 0x0032, + /* 14 */ 0x0033, 0x2044, 0x0034, + /* 17 */ 0x0041, 0x0300, + /* 19 */ 0x0041, 0x0301, + /* 21 */ 0x0041, 0x0302, + /* 23 */ 0x0041, 0x0303, + /* 25 */ 0x0041, 0x0308, + /* 27 */ 0x0041, 0x030A, + /* 29 */ 0x0043, 0x0327, + /* 31 */ 0x0045, 0x0300, + /* 33 */ 0x0045, 0x0301, + /* 35 */ 0x0045, 0x0302, + /* 37 */ 0x0045, 0x0308, + /* 39 */ 0x0049, 0x0300, + /* 41 */ 0x0049, 0x0301, + /* 43 */ 0x0049, 0x0302, + /* 45 */ 0x0049, 0x0308, + /* 47 */ 0x004E, 0x0303, + /* 49 */ 0x004F, 0x0300, + /* 51 */ 0x004F, 0x0301, + /* 53 */ 0x004F, 0x0302, + /* 55 */ 0x004F, 0x0303, + /* 57 */ 0x004F, 0x0308, + /* 59 */ 0x0055, 0x0300, + /* 61 */ 0x0055, 0x0301, + /* 63 */ 0x0055, 0x0302, + /* 65 */ 0x0055, 0x0308, + /* 67 */ 0x0059, 0x0301, + /* 69 */ 0x0061, 0x0300, + /* 71 */ 0x0061, 0x0301, + /* 73 */ 0x0061, 0x0302, + /* 75 */ 0x0061, 0x0303, + /* 77 */ 0x0061, 0x0308, + /* 79 */ 0x0061, 0x030A, + /* 81 */ 0x0063, 0x0327, + /* 83 */ 0x0065, 0x0300, + /* 85 */ 0x0065, 0x0301, + /* 87 */ 0x0065, 0x0302, + /* 89 */ 0x0065, 0x0308, + /* 91 */ 0x0069, 0x0300, + /* 93 */ 0x0069, 0x0301, + /* 95 */ 0x0069, 0x0302, + /* 97 */ 0x0069, 0x0308, + /* 99 */ 0x006E, 0x0303, + /* 101 */ 0x006F, 0x0300, + /* 103 */ 0x006F, 0x0301, + /* 105 */ 0x006F, 0x0302, + /* 107 */ 0x006F, 0x0303, + /* 109 */ 0x006F, 0x0308, + /* 111 */ 0x0075, 0x0300, + /* 113 */ 0x0075, 0x0301, + /* 115 */ 0x0075, 0x0302, + /* 117 */ 0x0075, 0x0308, + /* 119 */ 0x0079, 0x0301, + /* 121 */ 0x0079, 0x0308, + /* 123 */ 0x0041, 0x0304, + /* 125 */ 0x0061, 0x0304, + /* 127 */ 0x0041, 0x0306, + /* 129 */ 0x0061, 0x0306, + /* 131 */ 0x0041, 0x0328, + /* 133 */ 0x0061, 0x0328, + /* 135 */ 0x0043, 0x0301, + /* 137 */ 0x0063, 0x0301, + /* 139 */ 0x0043, 0x0302, + /* 141 */ 0x0063, 0x0302, + /* 143 */ 0x0043, 0x0307, + /* 145 */ 0x0063, 0x0307, + /* 147 */ 0x0043, 0x030C, + /* 149 */ 0x0063, 0x030C, + /* 151 */ 0x0044, 0x030C, + /* 153 */ 0x0064, 0x030C, + /* 155 */ 0x0045, 0x0304, + /* 157 */ 0x0065, 0x0304, + /* 159 */ 0x0045, 0x0306, + /* 161 */ 0x0065, 0x0306, + /* 163 */ 0x0045, 0x0307, + /* 165 */ 0x0065, 0x0307, + /* 167 */ 0x0045, 0x0328, + /* 169 */ 0x0065, 0x0328, + /* 171 */ 0x0045, 0x030C, + /* 173 */ 0x0065, 0x030C, + /* 175 */ 0x0047, 0x0302, + /* 177 */ 0x0067, 0x0302, + /* 179 */ 0x0047, 0x0306, + /* 181 */ 0x0067, 0x0306, + /* 183 */ 0x0047, 0x0307, + /* 185 */ 0x0067, 0x0307, + /* 187 */ 0x0047, 0x0327, + /* 189 */ 0x0067, 0x0327, + /* 191 */ 0x0048, 0x0302, + /* 193 */ 0x0068, 0x0302, + /* 195 */ 0x0049, 0x0303, + /* 197 */ 0x0069, 0x0303, + /* 199 */ 0x0049, 0x0304, + /* 201 */ 0x0069, 0x0304, + /* 203 */ 0x0049, 0x0306, + /* 205 */ 0x0069, 0x0306, + /* 207 */ 0x0049, 0x0328, + /* 209 */ 0x0069, 0x0328, + /* 211 */ 0x0049, 0x0307, + /* 213 */ 0x0049, 0x004A, + /* 215 */ 0x0069, 0x006A, + /* 217 */ 0x004A, 0x0302, + /* 219 */ 0x006A, 0x0302, + /* 221 */ 0x004B, 0x0327, + /* 223 */ 0x006B, 0x0327, + /* 225 */ 0x004C, 0x0301, + /* 227 */ 0x006C, 0x0301, + /* 229 */ 0x004C, 0x0327, + /* 231 */ 0x006C, 0x0327, + /* 233 */ 0x004C, 0x030C, + /* 235 */ 0x006C, 0x030C, + /* 237 */ 0x004C, 0x00B7, + /* 239 */ 0x006C, 0x00B7, + /* 241 */ 0x004E, 0x0301, + /* 243 */ 0x006E, 0x0301, + /* 245 */ 0x004E, 0x0327, + /* 247 */ 0x006E, 0x0327, + /* 249 */ 0x004E, 0x030C, + /* 251 */ 0x006E, 0x030C, + /* 253 */ 0x02BC, 0x006E, + /* 255 */ 0x004F, 0x0304, + /* 257 */ 0x006F, 0x0304, + /* 259 */ 0x004F, 0x0306, + /* 261 */ 0x006F, 0x0306, + /* 263 */ 0x004F, 0x030B, + /* 265 */ 0x006F, 0x030B, + /* 267 */ 0x0052, 0x0301, + /* 269 */ 0x0072, 0x0301, + /* 271 */ 0x0052, 0x0327, + /* 273 */ 0x0072, 0x0327, + /* 275 */ 0x0052, 0x030C, + /* 277 */ 0x0072, 0x030C, + /* 279 */ 0x0053, 0x0301, + /* 281 */ 0x0073, 0x0301, + /* 283 */ 0x0053, 0x0302, + /* 285 */ 0x0073, 0x0302, + /* 287 */ 0x0053, 0x0327, + /* 289 */ 0x0073, 0x0327, + /* 291 */ 0x0053, 0x030C, + /* 293 */ 0x0073, 0x030C, + /* 295 */ 0x0054, 0x0327, + /* 297 */ 0x0074, 0x0327, + /* 299 */ 0x0054, 0x030C, + /* 301 */ 0x0074, 0x030C, + /* 303 */ 0x0055, 0x0303, + /* 305 */ 0x0075, 0x0303, + /* 307 */ 0x0055, 0x0304, + /* 309 */ 0x0075, 0x0304, + /* 311 */ 0x0055, 0x0306, + /* 313 */ 0x0075, 0x0306, + /* 315 */ 0x0055, 0x030A, + /* 317 */ 0x0075, 0x030A, + /* 319 */ 0x0055, 0x030B, + /* 321 */ 0x0075, 0x030B, + /* 323 */ 0x0055, 0x0328, + /* 325 */ 0x0075, 0x0328, + /* 327 */ 0x0057, 0x0302, + /* 329 */ 0x0077, 0x0302, + /* 331 */ 0x0059, 0x0302, + /* 333 */ 0x0079, 0x0302, + /* 335 */ 0x0059, 0x0308, + /* 337 */ 0x005A, 0x0301, + /* 339 */ 0x007A, 0x0301, + /* 341 */ 0x005A, 0x0307, + /* 343 */ 0x007A, 0x0307, + /* 345 */ 0x005A, 0x030C, + /* 347 */ 0x007A, 0x030C, + /* 349 */ 0x004F, 0x031B, + /* 351 */ 0x006F, 0x031B, + /* 353 */ 0x0055, 0x031B, + /* 355 */ 0x0075, 0x031B, + /* 357 */ 0x0044, 0x017D, + /* 359 */ 0x0044, 0x017E, + /* 361 */ 0x0064, 0x017E, + /* 363 */ 0x004C, 0x004A, + /* 365 */ 0x004C, 0x006A, + /* 367 */ 0x006C, 0x006A, + /* 369 */ 0x004E, 0x004A, + /* 371 */ 0x004E, 0x006A, + /* 373 */ 0x006E, 0x006A, + /* 375 */ 0x0041, 0x030C, + /* 377 */ 0x0061, 0x030C, + /* 379 */ 0x0049, 0x030C, + /* 381 */ 0x0069, 0x030C, + /* 383 */ 0x004F, 0x030C, + /* 385 */ 0x006F, 0x030C, + /* 387 */ 0x0055, 0x030C, + /* 389 */ 0x0075, 0x030C, + /* 391 */ 0x00DC, 0x0304, + /* 393 */ 0x00FC, 0x0304, + /* 395 */ 0x00DC, 0x0301, + /* 397 */ 0x00FC, 0x0301, + /* 399 */ 0x00DC, 0x030C, + /* 401 */ 0x00FC, 0x030C, + /* 403 */ 0x00DC, 0x0300, + /* 405 */ 0x00FC, 0x0300, + /* 407 */ 0x00C4, 0x0304, + /* 409 */ 0x00E4, 0x0304, + /* 411 */ 0x0226, 0x0304, + /* 413 */ 0x0227, 0x0304, + /* 415 */ 0x00C6, 0x0304, + /* 417 */ 0x00E6, 0x0304, + /* 419 */ 0x0047, 0x030C, + /* 421 */ 0x0067, 0x030C, + /* 423 */ 0x004B, 0x030C, + /* 425 */ 0x006B, 0x030C, + /* 427 */ 0x004F, 0x0328, + /* 429 */ 0x006F, 0x0328, + /* 431 */ 0x01EA, 0x0304, + /* 433 */ 0x01EB, 0x0304, + /* 435 */ 0x01B7, 0x030C, + /* 437 */ 0x0292, 0x030C, + /* 439 */ 0x006A, 0x030C, + /* 441 */ 0x0044, 0x005A, + /* 443 */ 0x0044, 0x007A, + /* 445 */ 0x0064, 0x007A, + /* 447 */ 0x0047, 0x0301, + /* 449 */ 0x0067, 0x0301, + /* 451 */ 0x004E, 0x0300, + /* 453 */ 0x006E, 0x0300, + /* 455 */ 0x00C5, 0x0301, + /* 457 */ 0x00E5, 0x0301, + /* 459 */ 0x00C6, 0x0301, + /* 461 */ 0x00E6, 0x0301, + /* 463 */ 0x00D8, 0x0301, + /* 465 */ 0x00F8, 0x0301, + /* 467 */ 0x0041, 0x030F, + /* 469 */ 0x0061, 0x030F, + /* 471 */ 0x0041, 0x0311, + /* 473 */ 0x0061, 0x0311, + /* 475 */ 0x0045, 0x030F, + /* 477 */ 0x0065, 0x030F, + /* 479 */ 0x0045, 0x0311, + /* 481 */ 0x0065, 0x0311, + /* 483 */ 0x0049, 0x030F, + /* 485 */ 0x0069, 0x030F, + /* 487 */ 0x0049, 0x0311, + /* 489 */ 0x0069, 0x0311, + /* 491 */ 0x004F, 0x030F, + /* 493 */ 0x006F, 0x030F, + /* 495 */ 0x004F, 0x0311, + /* 497 */ 0x006F, 0x0311, + /* 499 */ 0x0052, 0x030F, + /* 501 */ 0x0072, 0x030F, + /* 503 */ 0x0052, 0x0311, + /* 505 */ 0x0072, 0x0311, + /* 507 */ 0x0055, 0x030F, + /* 509 */ 0x0075, 0x030F, + /* 511 */ 0x0055, 0x0311, + /* 513 */ 0x0075, 0x0311, + /* 515 */ 0x0053, 0x0326, + /* 517 */ 0x0073, 0x0326, + /* 519 */ 0x0054, 0x0326, + /* 521 */ 0x0074, 0x0326, + /* 523 */ 0x0048, 0x030C, + /* 525 */ 0x0068, 0x030C, + /* 527 */ 0x0041, 0x0307, + /* 529 */ 0x0061, 0x0307, + /* 531 */ 0x0045, 0x0327, + /* 533 */ 0x0065, 0x0327, + /* 535 */ 0x00D6, 0x0304, + /* 537 */ 0x00F6, 0x0304, + /* 539 */ 0x00D5, 0x0304, + /* 541 */ 0x00F5, 0x0304, + /* 543 */ 0x004F, 0x0307, + /* 545 */ 0x006F, 0x0307, + /* 547 */ 0x022E, 0x0304, + /* 549 */ 0x022F, 0x0304, + /* 551 */ 0x0059, 0x0304, + /* 553 */ 0x0079, 0x0304, + /* 555 */ 0x0020, 0x0306, + /* 557 */ 0x0020, 0x0307, + /* 559 */ 0x0020, 0x030A, + /* 561 */ 0x0020, 0x0328, + /* 563 */ 0x0020, 0x0303, + /* 565 */ 0x0020, 0x030B, + /* 567 */ 0x0308, 0x0301, + /* 569 */ 0x0020, 0x0345, + /* 571 */ 0x0020, 0x0301, + /* 573 */ 0x00A8, 0x0301, + /* 575 */ 0x0391, 0x0301, + /* 577 */ 0x0395, 0x0301, + /* 579 */ 0x0397, 0x0301, + /* 581 */ 0x0399, 0x0301, + /* 583 */ 0x039F, 0x0301, + /* 585 */ 0x03A5, 0x0301, + /* 587 */ 0x03A9, 0x0301, + /* 589 */ 0x03CA, 0x0301, + /* 591 */ 0x0399, 0x0308, + /* 593 */ 0x03A5, 0x0308, + /* 595 */ 0x03B1, 0x0301, + /* 597 */ 0x03B5, 0x0301, + /* 599 */ 0x03B7, 0x0301, + /* 601 */ 0x03B9, 0x0301, + /* 603 */ 0x03CB, 0x0301, + /* 605 */ 0x03B9, 0x0308, + /* 607 */ 0x03C5, 0x0308, + /* 609 */ 0x03BF, 0x0301, + /* 611 */ 0x03C5, 0x0301, + /* 613 */ 0x03C9, 0x0301, + /* 615 */ 0x03D2, 0x0301, + /* 617 */ 0x03D2, 0x0308, + /* 619 */ 0x0415, 0x0300, + /* 621 */ 0x0415, 0x0308, + /* 623 */ 0x0413, 0x0301, + /* 625 */ 0x0406, 0x0308, + /* 627 */ 0x041A, 0x0301, + /* 629 */ 0x0418, 0x0300, + /* 631 */ 0x0423, 0x0306, + /* 633 */ 0x0418, 0x0306, + /* 635 */ 0x0438, 0x0306, + /* 637 */ 0x0435, 0x0300, + /* 639 */ 0x0435, 0x0308, + /* 641 */ 0x0433, 0x0301, + /* 643 */ 0x0456, 0x0308, + /* 645 */ 0x043A, 0x0301, + /* 647 */ 0x0438, 0x0300, + /* 649 */ 0x0443, 0x0306, + /* 651 */ 0x0474, 0x030F, + /* 653 */ 0x0475, 0x030F, + /* 655 */ 0x0416, 0x0306, + /* 657 */ 0x0436, 0x0306, + /* 659 */ 0x0410, 0x0306, + /* 661 */ 0x0430, 0x0306, + /* 663 */ 0x0410, 0x0308, + /* 665 */ 0x0430, 0x0308, + /* 667 */ 0x0415, 0x0306, + /* 669 */ 0x0435, 0x0306, + /* 671 */ 0x04D8, 0x0308, + /* 673 */ 0x04D9, 0x0308, + /* 675 */ 0x0416, 0x0308, + /* 677 */ 0x0436, 0x0308, + /* 679 */ 0x0417, 0x0308, + /* 681 */ 0x0437, 0x0308, + /* 683 */ 0x0418, 0x0304, + /* 685 */ 0x0438, 0x0304, + /* 687 */ 0x0418, 0x0308, + /* 689 */ 0x0438, 0x0308, + /* 691 */ 0x041E, 0x0308, + /* 693 */ 0x043E, 0x0308, + /* 695 */ 0x04E8, 0x0308, + /* 697 */ 0x04E9, 0x0308, + /* 699 */ 0x042D, 0x0308, + /* 701 */ 0x044D, 0x0308, + /* 703 */ 0x0423, 0x0304, + /* 705 */ 0x0443, 0x0304, + /* 707 */ 0x0423, 0x0308, + /* 709 */ 0x0443, 0x0308, + /* 711 */ 0x0423, 0x030B, + /* 713 */ 0x0443, 0x030B, + /* 715 */ 0x0427, 0x0308, + /* 717 */ 0x0447, 0x0308, + /* 719 */ 0x042B, 0x0308, + /* 721 */ 0x044B, 0x0308, + /* 723 */ 0x0565, 0x0582, + /* 725 */ 0x0627, 0x0653, + /* 727 */ 0x0627, 0x0654, + /* 729 */ 0x0648, 0x0654, + /* 731 */ 0x0627, 0x0655, + /* 733 */ 0x064A, 0x0654, + /* 735 */ 0x0627, 0x0674, + /* 737 */ 0x0648, 0x0674, + /* 739 */ 0x06C7, 0x0674, + /* 741 */ 0x064A, 0x0674, + /* 743 */ 0x06D5, 0x0654, + /* 745 */ 0x06C1, 0x0654, + /* 747 */ 0x06D2, 0x0654, + /* 749 */ 0x0928, 0x093C, + /* 751 */ 0x0930, 0x093C, + /* 753 */ 0x0933, 0x093C, + /* 755 */ 0x0915, 0x093C, + /* 757 */ 0x0916, 0x093C, + /* 759 */ 0x0917, 0x093C, + /* 761 */ 0x091C, 0x093C, + /* 763 */ 0x0921, 0x093C, + /* 765 */ 0x0922, 0x093C, + /* 767 */ 0x092B, 0x093C, + /* 769 */ 0x092F, 0x093C, + /* 771 */ 0x09C7, 0x09BE, + /* 773 */ 0x09C7, 0x09D7, + /* 775 */ 0x09A1, 0x09BC, + /* 777 */ 0x09A2, 0x09BC, + /* 779 */ 0x09AF, 0x09BC, + /* 781 */ 0x0A32, 0x0A3C, + /* 783 */ 0x0A38, 0x0A3C, + /* 785 */ 0x0A16, 0x0A3C, + /* 787 */ 0x0A17, 0x0A3C, + /* 789 */ 0x0A1C, 0x0A3C, + /* 791 */ 0x0A2B, 0x0A3C, + /* 793 */ 0x0B47, 0x0B56, + /* 795 */ 0x0B47, 0x0B3E, + /* 797 */ 0x0B47, 0x0B57, + /* 799 */ 0x0B21, 0x0B3C, + /* 801 */ 0x0B22, 0x0B3C, + /* 803 */ 0x0B92, 0x0BD7, + /* 805 */ 0x0BC6, 0x0BBE, + /* 807 */ 0x0BC7, 0x0BBE, + /* 809 */ 0x0BC6, 0x0BD7, + /* 811 */ 0x0C46, 0x0C56, + /* 813 */ 0x0CBF, 0x0CD5, + /* 815 */ 0x0CC6, 0x0CD5, + /* 817 */ 0x0CC6, 0x0CD6, + /* 819 */ 0x0CC6, 0x0CC2, + /* 821 */ 0x0CCA, 0x0CD5, + /* 823 */ 0x0D46, 0x0D3E, + /* 825 */ 0x0D47, 0x0D3E, + /* 827 */ 0x0D46, 0x0D57, + /* 829 */ 0x0DD9, 0x0DCA, + /* 831 */ 0x0DD9, 0x0DCF, + /* 833 */ 0x0DDC, 0x0DCA, + /* 835 */ 0x0DD9, 0x0DDF, + /* 837 */ 0x0E4D, 0x0E32, + /* 839 */ 0x0ECD, 0x0EB2, + /* 841 */ 0x0EAB, 0x0E99, + /* 843 */ 0x0EAB, 0x0EA1, + /* 845 */ 0x0F42, 0x0FB7, + /* 847 */ 0x0F4C, 0x0FB7, + /* 849 */ 0x0F51, 0x0FB7, + /* 851 */ 0x0F56, 0x0FB7, + /* 853 */ 0x0F5B, 0x0FB7, + /* 855 */ 0x0F40, 0x0FB5, + /* 857 */ 0x0F71, 0x0F72, + /* 859 */ 0x0F71, 0x0F74, + /* 861 */ 0x0FB2, 0x0F80, + /* 863 */ 0x0FB2, 0x0F81, + /* 865 */ 0x0FB3, 0x0F80, + /* 867 */ 0x0FB3, 0x0F81, + /* 869 */ 0x0F71, 0x0F80, + /* 871 */ 0x0F92, 0x0FB7, + /* 873 */ 0x0F9C, 0x0FB7, + /* 875 */ 0x0FA1, 0x0FB7, + /* 877 */ 0x0FA6, 0x0FB7, + /* 879 */ 0x0FAB, 0x0FB7, + /* 881 */ 0x0F90, 0x0FB5, + /* 883 */ 0x1025, 0x102E, + /* 885 */ 0x1B05, 0x1B35, + /* 887 */ 0x1B07, 0x1B35, + /* 889 */ 0x1B09, 0x1B35, + /* 891 */ 0x1B0B, 0x1B35, + /* 893 */ 0x1B0D, 0x1B35, + /* 895 */ 0x1B11, 0x1B35, + /* 897 */ 0x1B3A, 0x1B35, + /* 899 */ 0x1B3C, 0x1B35, + /* 901 */ 0x1B3E, 0x1B35, + /* 903 */ 0x1B3F, 0x1B35, + /* 905 */ 0x1B42, 0x1B35, + /* 907 */ 0x0041, 0x0325, + /* 909 */ 0x0061, 0x0325, + /* 911 */ 0x0042, 0x0307, + /* 913 */ 0x0062, 0x0307, + /* 915 */ 0x0042, 0x0323, + /* 917 */ 0x0062, 0x0323, + /* 919 */ 0x0042, 0x0331, + /* 921 */ 0x0062, 0x0331, + /* 923 */ 0x00C7, 0x0301, + /* 925 */ 0x00E7, 0x0301, + /* 927 */ 0x0044, 0x0307, + /* 929 */ 0x0064, 0x0307, + /* 931 */ 0x0044, 0x0323, + /* 933 */ 0x0064, 0x0323, + /* 935 */ 0x0044, 0x0331, + /* 937 */ 0x0064, 0x0331, + /* 939 */ 0x0044, 0x0327, + /* 941 */ 0x0064, 0x0327, + /* 943 */ 0x0044, 0x032D, + /* 945 */ 0x0064, 0x032D, + /* 947 */ 0x0112, 0x0300, + /* 949 */ 0x0113, 0x0300, + /* 951 */ 0x0112, 0x0301, + /* 953 */ 0x0113, 0x0301, + /* 955 */ 0x0045, 0x032D, + /* 957 */ 0x0065, 0x032D, + /* 959 */ 0x0045, 0x0330, + /* 961 */ 0x0065, 0x0330, + /* 963 */ 0x0228, 0x0306, + /* 965 */ 0x0229, 0x0306, + /* 967 */ 0x0046, 0x0307, + /* 969 */ 0x0066, 0x0307, + /* 971 */ 0x0047, 0x0304, + /* 973 */ 0x0067, 0x0304, + /* 975 */ 0x0048, 0x0307, + /* 977 */ 0x0068, 0x0307, + /* 979 */ 0x0048, 0x0323, + /* 981 */ 0x0068, 0x0323, + /* 983 */ 0x0048, 0x0308, + /* 985 */ 0x0068, 0x0308, + /* 987 */ 0x0048, 0x0327, + /* 989 */ 0x0068, 0x0327, + /* 991 */ 0x0048, 0x032E, + /* 993 */ 0x0068, 0x032E, + /* 995 */ 0x0049, 0x0330, + /* 997 */ 0x0069, 0x0330, + /* 999 */ 0x00CF, 0x0301, + /* 1001 */ 0x00EF, 0x0301, + /* 1003 */ 0x004B, 0x0301, + /* 1005 */ 0x006B, 0x0301, + /* 1007 */ 0x004B, 0x0323, + /* 1009 */ 0x006B, 0x0323, + /* 1011 */ 0x004B, 0x0331, + /* 1013 */ 0x006B, 0x0331, + /* 1015 */ 0x004C, 0x0323, + /* 1017 */ 0x006C, 0x0323, + /* 1019 */ 0x1E36, 0x0304, + /* 1021 */ 0x1E37, 0x0304, + /* 1023 */ 0x004C, 0x0331, + /* 1025 */ 0x006C, 0x0331, + /* 1027 */ 0x004C, 0x032D, + /* 1029 */ 0x006C, 0x032D, + /* 1031 */ 0x004D, 0x0301, + /* 1033 */ 0x006D, 0x0301, + /* 1035 */ 0x004D, 0x0307, + /* 1037 */ 0x006D, 0x0307, + /* 1039 */ 0x004D, 0x0323, + /* 1041 */ 0x006D, 0x0323, + /* 1043 */ 0x004E, 0x0307, + /* 1045 */ 0x006E, 0x0307, + /* 1047 */ 0x004E, 0x0323, + /* 1049 */ 0x006E, 0x0323, + /* 1051 */ 0x004E, 0x0331, + /* 1053 */ 0x006E, 0x0331, + /* 1055 */ 0x004E, 0x032D, + /* 1057 */ 0x006E, 0x032D, + /* 1059 */ 0x00D5, 0x0301, + /* 1061 */ 0x00F5, 0x0301, + /* 1063 */ 0x00D5, 0x0308, + /* 1065 */ 0x00F5, 0x0308, + /* 1067 */ 0x014C, 0x0300, + /* 1069 */ 0x014D, 0x0300, + /* 1071 */ 0x014C, 0x0301, + /* 1073 */ 0x014D, 0x0301, + /* 1075 */ 0x0050, 0x0301, + /* 1077 */ 0x0070, 0x0301, + /* 1079 */ 0x0050, 0x0307, + /* 1081 */ 0x0070, 0x0307, + /* 1083 */ 0x0052, 0x0307, + /* 1085 */ 0x0072, 0x0307, + /* 1087 */ 0x0052, 0x0323, + /* 1089 */ 0x0072, 0x0323, + /* 1091 */ 0x1E5A, 0x0304, + /* 1093 */ 0x1E5B, 0x0304, + /* 1095 */ 0x0052, 0x0331, + /* 1097 */ 0x0072, 0x0331, + /* 1099 */ 0x0053, 0x0307, + /* 1101 */ 0x0073, 0x0307, + /* 1103 */ 0x0053, 0x0323, + /* 1105 */ 0x0073, 0x0323, + /* 1107 */ 0x015A, 0x0307, + /* 1109 */ 0x015B, 0x0307, + /* 1111 */ 0x0160, 0x0307, + /* 1113 */ 0x0161, 0x0307, + /* 1115 */ 0x1E62, 0x0307, + /* 1117 */ 0x1E63, 0x0307, + /* 1119 */ 0x0054, 0x0307, + /* 1121 */ 0x0074, 0x0307, + /* 1123 */ 0x0054, 0x0323, + /* 1125 */ 0x0074, 0x0323, + /* 1127 */ 0x0054, 0x0331, + /* 1129 */ 0x0074, 0x0331, + /* 1131 */ 0x0054, 0x032D, + /* 1133 */ 0x0074, 0x032D, + /* 1135 */ 0x0055, 0x0324, + /* 1137 */ 0x0075, 0x0324, + /* 1139 */ 0x0055, 0x0330, + /* 1141 */ 0x0075, 0x0330, + /* 1143 */ 0x0055, 0x032D, + /* 1145 */ 0x0075, 0x032D, + /* 1147 */ 0x0168, 0x0301, + /* 1149 */ 0x0169, 0x0301, + /* 1151 */ 0x016A, 0x0308, + /* 1153 */ 0x016B, 0x0308, + /* 1155 */ 0x0056, 0x0303, + /* 1157 */ 0x0076, 0x0303, + /* 1159 */ 0x0056, 0x0323, + /* 1161 */ 0x0076, 0x0323, + /* 1163 */ 0x0057, 0x0300, + /* 1165 */ 0x0077, 0x0300, + /* 1167 */ 0x0057, 0x0301, + /* 1169 */ 0x0077, 0x0301, + /* 1171 */ 0x0057, 0x0308, + /* 1173 */ 0x0077, 0x0308, + /* 1175 */ 0x0057, 0x0307, + /* 1177 */ 0x0077, 0x0307, + /* 1179 */ 0x0057, 0x0323, + /* 1181 */ 0x0077, 0x0323, + /* 1183 */ 0x0058, 0x0307, + /* 1185 */ 0x0078, 0x0307, + /* 1187 */ 0x0058, 0x0308, + /* 1189 */ 0x0078, 0x0308, + /* 1191 */ 0x0059, 0x0307, + /* 1193 */ 0x0079, 0x0307, + /* 1195 */ 0x005A, 0x0302, + /* 1197 */ 0x007A, 0x0302, + /* 1199 */ 0x005A, 0x0323, + /* 1201 */ 0x007A, 0x0323, + /* 1203 */ 0x005A, 0x0331, + /* 1205 */ 0x007A, 0x0331, + /* 1207 */ 0x0068, 0x0331, + /* 1209 */ 0x0074, 0x0308, + /* 1211 */ 0x0077, 0x030A, + /* 1213 */ 0x0079, 0x030A, + /* 1215 */ 0x0061, 0x02BE, + /* 1217 */ 0x017F, 0x0307, + /* 1219 */ 0x0041, 0x0323, + /* 1221 */ 0x0061, 0x0323, + /* 1223 */ 0x0041, 0x0309, + /* 1225 */ 0x0061, 0x0309, + /* 1227 */ 0x00C2, 0x0301, + /* 1229 */ 0x00E2, 0x0301, + /* 1231 */ 0x00C2, 0x0300, + /* 1233 */ 0x00E2, 0x0300, + /* 1235 */ 0x00C2, 0x0309, + /* 1237 */ 0x00E2, 0x0309, + /* 1239 */ 0x00C2, 0x0303, + /* 1241 */ 0x00E2, 0x0303, + /* 1243 */ 0x1EA0, 0x0302, + /* 1245 */ 0x1EA1, 0x0302, + /* 1247 */ 0x0102, 0x0301, + /* 1249 */ 0x0103, 0x0301, + /* 1251 */ 0x0102, 0x0300, + /* 1253 */ 0x0103, 0x0300, + /* 1255 */ 0x0102, 0x0309, + /* 1257 */ 0x0103, 0x0309, + /* 1259 */ 0x0102, 0x0303, + /* 1261 */ 0x0103, 0x0303, + /* 1263 */ 0x1EA0, 0x0306, + /* 1265 */ 0x1EA1, 0x0306, + /* 1267 */ 0x0045, 0x0323, + /* 1269 */ 0x0065, 0x0323, + /* 1271 */ 0x0045, 0x0309, + /* 1273 */ 0x0065, 0x0309, + /* 1275 */ 0x0045, 0x0303, + /* 1277 */ 0x0065, 0x0303, + /* 1279 */ 0x00CA, 0x0301, + /* 1281 */ 0x00EA, 0x0301, + /* 1283 */ 0x00CA, 0x0300, + /* 1285 */ 0x00EA, 0x0300, + /* 1287 */ 0x00CA, 0x0309, + /* 1289 */ 0x00EA, 0x0309, + /* 1291 */ 0x00CA, 0x0303, + /* 1293 */ 0x00EA, 0x0303, + /* 1295 */ 0x1EB8, 0x0302, + /* 1297 */ 0x1EB9, 0x0302, + /* 1299 */ 0x0049, 0x0309, + /* 1301 */ 0x0069, 0x0309, + /* 1303 */ 0x0049, 0x0323, + /* 1305 */ 0x0069, 0x0323, + /* 1307 */ 0x004F, 0x0323, + /* 1309 */ 0x006F, 0x0323, + /* 1311 */ 0x004F, 0x0309, + /* 1313 */ 0x006F, 0x0309, + /* 1315 */ 0x00D4, 0x0301, + /* 1317 */ 0x00F4, 0x0301, + /* 1319 */ 0x00D4, 0x0300, + /* 1321 */ 0x00F4, 0x0300, + /* 1323 */ 0x00D4, 0x0309, + /* 1325 */ 0x00F4, 0x0309, + /* 1327 */ 0x00D4, 0x0303, + /* 1329 */ 0x00F4, 0x0303, + /* 1331 */ 0x1ECC, 0x0302, + /* 1333 */ 0x1ECD, 0x0302, + /* 1335 */ 0x01A0, 0x0301, + /* 1337 */ 0x01A1, 0x0301, + /* 1339 */ 0x01A0, 0x0300, + /* 1341 */ 0x01A1, 0x0300, + /* 1343 */ 0x01A0, 0x0309, + /* 1345 */ 0x01A1, 0x0309, + /* 1347 */ 0x01A0, 0x0303, + /* 1349 */ 0x01A1, 0x0303, + /* 1351 */ 0x01A0, 0x0323, + /* 1353 */ 0x01A1, 0x0323, + /* 1355 */ 0x0055, 0x0323, + /* 1357 */ 0x0075, 0x0323, + /* 1359 */ 0x0055, 0x0309, + /* 1361 */ 0x0075, 0x0309, + /* 1363 */ 0x01AF, 0x0301, + /* 1365 */ 0x01B0, 0x0301, + /* 1367 */ 0x01AF, 0x0300, + /* 1369 */ 0x01B0, 0x0300, + /* 1371 */ 0x01AF, 0x0309, + /* 1373 */ 0x01B0, 0x0309, + /* 1375 */ 0x01AF, 0x0303, + /* 1377 */ 0x01B0, 0x0303, + /* 1379 */ 0x01AF, 0x0323, + /* 1381 */ 0x01B0, 0x0323, + /* 1383 */ 0x0059, 0x0300, + /* 1385 */ 0x0079, 0x0300, + /* 1387 */ 0x0059, 0x0323, + /* 1389 */ 0x0079, 0x0323, + /* 1391 */ 0x0059, 0x0309, + /* 1393 */ 0x0079, 0x0309, + /* 1395 */ 0x0059, 0x0303, + /* 1397 */ 0x0079, 0x0303, + /* 1399 */ 0x03B1, 0x0313, + /* 1401 */ 0x03B1, 0x0314, + /* 1403 */ 0x1F00, 0x0300, + /* 1405 */ 0x1F01, 0x0300, + /* 1407 */ 0x1F00, 0x0301, + /* 1409 */ 0x1F01, 0x0301, + /* 1411 */ 0x1F00, 0x0342, + /* 1413 */ 0x1F01, 0x0342, + /* 1415 */ 0x0391, 0x0313, + /* 1417 */ 0x0391, 0x0314, + /* 1419 */ 0x1F08, 0x0300, + /* 1421 */ 0x1F09, 0x0300, + /* 1423 */ 0x1F08, 0x0301, + /* 1425 */ 0x1F09, 0x0301, + /* 1427 */ 0x1F08, 0x0342, + /* 1429 */ 0x1F09, 0x0342, + /* 1431 */ 0x03B5, 0x0313, + /* 1433 */ 0x03B5, 0x0314, + /* 1435 */ 0x1F10, 0x0300, + /* 1437 */ 0x1F11, 0x0300, + /* 1439 */ 0x1F10, 0x0301, + /* 1441 */ 0x1F11, 0x0301, + /* 1443 */ 0x0395, 0x0313, + /* 1445 */ 0x0395, 0x0314, + /* 1447 */ 0x1F18, 0x0300, + /* 1449 */ 0x1F19, 0x0300, + /* 1451 */ 0x1F18, 0x0301, + /* 1453 */ 0x1F19, 0x0301, + /* 1455 */ 0x03B7, 0x0313, + /* 1457 */ 0x03B7, 0x0314, + /* 1459 */ 0x1F20, 0x0300, + /* 1461 */ 0x1F21, 0x0300, + /* 1463 */ 0x1F20, 0x0301, + /* 1465 */ 0x1F21, 0x0301, + /* 1467 */ 0x1F20, 0x0342, + /* 1469 */ 0x1F21, 0x0342, + /* 1471 */ 0x0397, 0x0313, + /* 1473 */ 0x0397, 0x0314, + /* 1475 */ 0x1F28, 0x0300, + /* 1477 */ 0x1F29, 0x0300, + /* 1479 */ 0x1F28, 0x0301, + /* 1481 */ 0x1F29, 0x0301, + /* 1483 */ 0x1F28, 0x0342, + /* 1485 */ 0x1F29, 0x0342, + /* 1487 */ 0x03B9, 0x0313, + /* 1489 */ 0x03B9, 0x0314, + /* 1491 */ 0x1F30, 0x0300, + /* 1493 */ 0x1F31, 0x0300, + /* 1495 */ 0x1F30, 0x0301, + /* 1497 */ 0x1F31, 0x0301, + /* 1499 */ 0x1F30, 0x0342, + /* 1501 */ 0x1F31, 0x0342, + /* 1503 */ 0x0399, 0x0313, + /* 1505 */ 0x0399, 0x0314, + /* 1507 */ 0x1F38, 0x0300, + /* 1509 */ 0x1F39, 0x0300, + /* 1511 */ 0x1F38, 0x0301, + /* 1513 */ 0x1F39, 0x0301, + /* 1515 */ 0x1F38, 0x0342, + /* 1517 */ 0x1F39, 0x0342, + /* 1519 */ 0x03BF, 0x0313, + /* 1521 */ 0x03BF, 0x0314, + /* 1523 */ 0x1F40, 0x0300, + /* 1525 */ 0x1F41, 0x0300, + /* 1527 */ 0x1F40, 0x0301, + /* 1529 */ 0x1F41, 0x0301, + /* 1531 */ 0x039F, 0x0313, + /* 1533 */ 0x039F, 0x0314, + /* 1535 */ 0x1F48, 0x0300, + /* 1537 */ 0x1F49, 0x0300, + /* 1539 */ 0x1F48, 0x0301, + /* 1541 */ 0x1F49, 0x0301, + /* 1543 */ 0x03C5, 0x0313, + /* 1545 */ 0x03C5, 0x0314, + /* 1547 */ 0x1F50, 0x0300, + /* 1549 */ 0x1F51, 0x0300, + /* 1551 */ 0x1F50, 0x0301, + /* 1553 */ 0x1F51, 0x0301, + /* 1555 */ 0x1F50, 0x0342, + /* 1557 */ 0x1F51, 0x0342, + /* 1559 */ 0x03A5, 0x0314, + /* 1561 */ 0x1F59, 0x0300, + /* 1563 */ 0x1F59, 0x0301, + /* 1565 */ 0x1F59, 0x0342, + /* 1567 */ 0x03C9, 0x0313, + /* 1569 */ 0x03C9, 0x0314, + /* 1571 */ 0x1F60, 0x0300, + /* 1573 */ 0x1F61, 0x0300, + /* 1575 */ 0x1F60, 0x0301, + /* 1577 */ 0x1F61, 0x0301, + /* 1579 */ 0x1F60, 0x0342, + /* 1581 */ 0x1F61, 0x0342, + /* 1583 */ 0x03A9, 0x0313, + /* 1585 */ 0x03A9, 0x0314, + /* 1587 */ 0x1F68, 0x0300, + /* 1589 */ 0x1F69, 0x0300, + /* 1591 */ 0x1F68, 0x0301, + /* 1593 */ 0x1F69, 0x0301, + /* 1595 */ 0x1F68, 0x0342, + /* 1597 */ 0x1F69, 0x0342, + /* 1599 */ 0x03B1, 0x0300, + /* 1601 */ 0x03B5, 0x0300, + /* 1603 */ 0x03B7, 0x0300, + /* 1605 */ 0x03B9, 0x0300, + /* 1607 */ 0x03BF, 0x0300, + /* 1609 */ 0x03C5, 0x0300, + /* 1611 */ 0x03C9, 0x0300, + /* 1613 */ 0x1F00, 0x0345, + /* 1615 */ 0x1F01, 0x0345, + /* 1617 */ 0x1F02, 0x0345, + /* 1619 */ 0x1F03, 0x0345, + /* 1621 */ 0x1F04, 0x0345, + /* 1623 */ 0x1F05, 0x0345, + /* 1625 */ 0x1F06, 0x0345, + /* 1627 */ 0x1F07, 0x0345, + /* 1629 */ 0x1F08, 0x0345, + /* 1631 */ 0x1F09, 0x0345, + /* 1633 */ 0x1F0A, 0x0345, + /* 1635 */ 0x1F0B, 0x0345, + /* 1637 */ 0x1F0C, 0x0345, + /* 1639 */ 0x1F0D, 0x0345, + /* 1641 */ 0x1F0E, 0x0345, + /* 1643 */ 0x1F0F, 0x0345, + /* 1645 */ 0x1F20, 0x0345, + /* 1647 */ 0x1F21, 0x0345, + /* 1649 */ 0x1F22, 0x0345, + /* 1651 */ 0x1F23, 0x0345, + /* 1653 */ 0x1F24, 0x0345, + /* 1655 */ 0x1F25, 0x0345, + /* 1657 */ 0x1F26, 0x0345, + /* 1659 */ 0x1F27, 0x0345, + /* 1661 */ 0x1F28, 0x0345, + /* 1663 */ 0x1F29, 0x0345, + /* 1665 */ 0x1F2A, 0x0345, + /* 1667 */ 0x1F2B, 0x0345, + /* 1669 */ 0x1F2C, 0x0345, + /* 1671 */ 0x1F2D, 0x0345, + /* 1673 */ 0x1F2E, 0x0345, + /* 1675 */ 0x1F2F, 0x0345, + /* 1677 */ 0x1F60, 0x0345, + /* 1679 */ 0x1F61, 0x0345, + /* 1681 */ 0x1F62, 0x0345, + /* 1683 */ 0x1F63, 0x0345, + /* 1685 */ 0x1F64, 0x0345, + /* 1687 */ 0x1F65, 0x0345, + /* 1689 */ 0x1F66, 0x0345, + /* 1691 */ 0x1F67, 0x0345, + /* 1693 */ 0x1F68, 0x0345, + /* 1695 */ 0x1F69, 0x0345, + /* 1697 */ 0x1F6A, 0x0345, + /* 1699 */ 0x1F6B, 0x0345, + /* 1701 */ 0x1F6C, 0x0345, + /* 1703 */ 0x1F6D, 0x0345, + /* 1705 */ 0x1F6E, 0x0345, + /* 1707 */ 0x1F6F, 0x0345, + /* 1709 */ 0x03B1, 0x0306, + /* 1711 */ 0x03B1, 0x0304, + /* 1713 */ 0x1F70, 0x0345, + /* 1715 */ 0x03B1, 0x0345, + /* 1717 */ 0x03AC, 0x0345, + /* 1719 */ 0x03B1, 0x0342, + /* 1721 */ 0x1FB6, 0x0345, + /* 1723 */ 0x0391, 0x0306, + /* 1725 */ 0x0391, 0x0304, + /* 1727 */ 0x0391, 0x0300, + /* 1729 */ 0x0391, 0x0345, + /* 1731 */ 0x0020, 0x0313, + /* 1733 */ 0x0020, 0x0313, + /* 1735 */ 0x0020, 0x0342, + /* 1737 */ 0x00A8, 0x0342, + /* 1739 */ 0x1F74, 0x0345, + /* 1741 */ 0x03B7, 0x0345, + /* 1743 */ 0x03AE, 0x0345, + /* 1745 */ 0x03B7, 0x0342, + /* 1747 */ 0x1FC6, 0x0345, + /* 1749 */ 0x0395, 0x0300, + /* 1751 */ 0x0397, 0x0300, + /* 1753 */ 0x0397, 0x0345, + /* 1755 */ 0x1FBF, 0x0300, + /* 1757 */ 0x1FBF, 0x0301, + /* 1759 */ 0x1FBF, 0x0342, + /* 1761 */ 0x03B9, 0x0306, + /* 1763 */ 0x03B9, 0x0304, + /* 1765 */ 0x03CA, 0x0300, + /* 1767 */ 0x03B9, 0x0342, + /* 1769 */ 0x03CA, 0x0342, + /* 1771 */ 0x0399, 0x0306, + /* 1773 */ 0x0399, 0x0304, + /* 1775 */ 0x0399, 0x0300, + /* 1777 */ 0x1FFE, 0x0300, + /* 1779 */ 0x1FFE, 0x0301, + /* 1781 */ 0x1FFE, 0x0342, + /* 1783 */ 0x03C5, 0x0306, + /* 1785 */ 0x03C5, 0x0304, + /* 1787 */ 0x03CB, 0x0300, + /* 1789 */ 0x03C1, 0x0313, + /* 1791 */ 0x03C1, 0x0314, + /* 1793 */ 0x03C5, 0x0342, + /* 1795 */ 0x03CB, 0x0342, + /* 1797 */ 0x03A5, 0x0306, + /* 1799 */ 0x03A5, 0x0304, + /* 1801 */ 0x03A5, 0x0300, + /* 1803 */ 0x03A1, 0x0314, + /* 1805 */ 0x00A8, 0x0300, + /* 1807 */ 0x1F7C, 0x0345, + /* 1809 */ 0x03C9, 0x0345, + /* 1811 */ 0x03CE, 0x0345, + /* 1813 */ 0x03C9, 0x0342, + /* 1815 */ 0x1FF6, 0x0345, + /* 1817 */ 0x039F, 0x0300, + /* 1819 */ 0x03A9, 0x0300, + /* 1821 */ 0x03A9, 0x0345, + /* 1823 */ 0x0020, 0x0314, + /* 1825 */ 0x0020, 0x0333, + /* 1827 */ 0x002E, 0x002E, + /* 1829 */ 0x002E, 0x002E, 0x002E, + /* 1832 */ 0x2032, 0x2032, + /* 1834 */ 0x2032, 0x2032, 0x2032, + /* 1837 */ 0x2035, 0x2035, + /* 1839 */ 0x2035, 0x2035, 0x2035, + /* 1842 */ 0x0021, 0x0021, + /* 1844 */ 0x0020, 0x0305, + /* 1846 */ 0x003F, 0x003F, + /* 1848 */ 0x003F, 0x0021, + /* 1850 */ 0x0021, 0x003F, + /* 1852 */ 0x2032, 0x2032, 0x2032, 0x2032, + /* 1856 */ 0x0052, 0x0073, + /* 1858 */ 0x0061, 0x002F, 0x0063, + /* 1861 */ 0x0061, 0x002F, 0x0073, + /* 1864 */ 0x00B0, 0x0043, + /* 1866 */ 0x0063, 0x002F, 0x006F, + /* 1869 */ 0x0063, 0x002F, 0x0075, + /* 1872 */ 0x00B0, 0x0046, + /* 1874 */ 0x004E, 0x006F, + /* 1876 */ 0x0053, 0x004D, + /* 1878 */ 0x0054, 0x0045, 0x004C, + /* 1881 */ 0x0054, 0x004D, + /* 1883 */ 0x0046, 0x0041, 0x0058, + /* 1886 */ 0x0031, 0x2044, 0x0037, + /* 1889 */ 0x0031, 0x2044, 0x0039, + /* 1892 */ 0x0031, 0x2044, 0x0031, 0x0030, + /* 1896 */ 0x0031, 0x2044, 0x0033, + /* 1899 */ 0x0032, 0x2044, 0x0033, + /* 1902 */ 0x0031, 0x2044, 0x0035, + /* 1905 */ 0x0032, 0x2044, 0x0035, + /* 1908 */ 0x0033, 0x2044, 0x0035, + /* 1911 */ 0x0034, 0x2044, 0x0035, + /* 1914 */ 0x0031, 0x2044, 0x0036, + /* 1917 */ 0x0035, 0x2044, 0x0036, + /* 1920 */ 0x0031, 0x2044, 0x0038, + /* 1923 */ 0x0033, 0x2044, 0x0038, + /* 1926 */ 0x0035, 0x2044, 0x0038, + /* 1929 */ 0x0037, 0x2044, 0x0038, + /* 1932 */ 0x0031, 0x2044, + /* 1934 */ 0x0049, 0x0049, + /* 1936 */ 0x0049, 0x0049, 0x0049, + /* 1939 */ 0x0049, 0x0056, + /* 1941 */ 0x0056, 0x0049, + /* 1943 */ 0x0056, 0x0049, 0x0049, + /* 1946 */ 0x0056, 0x0049, 0x0049, 0x0049, + /* 1950 */ 0x0049, 0x0058, + /* 1952 */ 0x0058, 0x0049, + /* 1954 */ 0x0058, 0x0049, 0x0049, + /* 1957 */ 0x0069, 0x0069, + /* 1959 */ 0x0069, 0x0069, 0x0069, + /* 1962 */ 0x0069, 0x0076, + /* 1964 */ 0x0076, 0x0069, + /* 1966 */ 0x0076, 0x0069, 0x0069, + /* 1969 */ 0x0076, 0x0069, 0x0069, 0x0069, + /* 1973 */ 0x0069, 0x0078, + /* 1975 */ 0x0078, 0x0069, + /* 1977 */ 0x0078, 0x0069, 0x0069, + /* 1980 */ 0x0030, 0x2044, 0x0033, + /* 1983 */ 0x2190, 0x0338, + /* 1985 */ 0x2192, 0x0338, + /* 1987 */ 0x2194, 0x0338, + /* 1989 */ 0x21D0, 0x0338, + /* 1991 */ 0x21D4, 0x0338, + /* 1993 */ 0x21D2, 0x0338, + /* 1995 */ 0x2203, 0x0338, + /* 1997 */ 0x2208, 0x0338, + /* 1999 */ 0x220B, 0x0338, + /* 2001 */ 0x2223, 0x0338, + /* 2003 */ 0x2225, 0x0338, + /* 2005 */ 0x222B, 0x222B, + /* 2007 */ 0x222B, 0x222B, 0x222B, + /* 2010 */ 0x222E, 0x222E, + /* 2012 */ 0x222E, 0x222E, 0x222E, + /* 2015 */ 0x223C, 0x0338, + /* 2017 */ 0x2243, 0x0338, + /* 2019 */ 0x2245, 0x0338, + /* 2021 */ 0x2248, 0x0338, + /* 2023 */ 0x003D, 0x0338, + /* 2025 */ 0x2261, 0x0338, + /* 2027 */ 0x224D, 0x0338, + /* 2029 */ 0x003C, 0x0338, + /* 2031 */ 0x003E, 0x0338, + /* 2033 */ 0x2264, 0x0338, + /* 2035 */ 0x2265, 0x0338, + /* 2037 */ 0x2272, 0x0338, + /* 2039 */ 0x2273, 0x0338, + /* 2041 */ 0x2276, 0x0338, + /* 2043 */ 0x2277, 0x0338, + /* 2045 */ 0x227A, 0x0338, + /* 2047 */ 0x227B, 0x0338, + /* 2049 */ 0x2282, 0x0338, + /* 2051 */ 0x2283, 0x0338, + /* 2053 */ 0x2286, 0x0338, + /* 2055 */ 0x2287, 0x0338, + /* 2057 */ 0x22A2, 0x0338, + /* 2059 */ 0x22A8, 0x0338, + /* 2061 */ 0x22A9, 0x0338, + /* 2063 */ 0x22AB, 0x0338, + /* 2065 */ 0x227C, 0x0338, + /* 2067 */ 0x227D, 0x0338, + /* 2069 */ 0x2291, 0x0338, + /* 2071 */ 0x2292, 0x0338, + /* 2073 */ 0x22B2, 0x0338, + /* 2075 */ 0x22B3, 0x0338, + /* 2077 */ 0x22B4, 0x0338, + /* 2079 */ 0x22B5, 0x0338, + /* 2081 */ 0x0031, 0x0030, + /* 2083 */ 0x0031, 0x0031, + /* 2085 */ 0x0031, 0x0032, + /* 2087 */ 0x0031, 0x0033, + /* 2089 */ 0x0031, 0x0034, + /* 2091 */ 0x0031, 0x0035, + /* 2093 */ 0x0031, 0x0036, + /* 2095 */ 0x0031, 0x0037, + /* 2097 */ 0x0031, 0x0038, + /* 2099 */ 0x0031, 0x0039, + /* 2101 */ 0x0032, 0x0030, + /* 2103 */ 0x0028, 0x0031, 0x0029, + /* 2106 */ 0x0028, 0x0032, 0x0029, + /* 2109 */ 0x0028, 0x0033, 0x0029, + /* 2112 */ 0x0028, 0x0034, 0x0029, + /* 2115 */ 0x0028, 0x0035, 0x0029, + /* 2118 */ 0x0028, 0x0036, 0x0029, + /* 2121 */ 0x0028, 0x0037, 0x0029, + /* 2124 */ 0x0028, 0x0038, 0x0029, + /* 2127 */ 0x0028, 0x0039, 0x0029, + /* 2130 */ 0x0028, 0x0031, 0x0030, 0x0029, + /* 2134 */ 0x0028, 0x0031, 0x0031, 0x0029, + /* 2138 */ 0x0028, 0x0031, 0x0032, 0x0029, + /* 2142 */ 0x0028, 0x0031, 0x0033, 0x0029, + /* 2146 */ 0x0028, 0x0031, 0x0034, 0x0029, + /* 2150 */ 0x0028, 0x0031, 0x0035, 0x0029, + /* 2154 */ 0x0028, 0x0031, 0x0036, 0x0029, + /* 2158 */ 0x0028, 0x0031, 0x0037, 0x0029, + /* 2162 */ 0x0028, 0x0031, 0x0038, 0x0029, + /* 2166 */ 0x0028, 0x0031, 0x0039, 0x0029, + /* 2170 */ 0x0028, 0x0032, 0x0030, 0x0029, + /* 2174 */ 0x0031, 0x002E, + /* 2176 */ 0x0032, 0x002E, + /* 2178 */ 0x0033, 0x002E, + /* 2180 */ 0x0034, 0x002E, + /* 2182 */ 0x0035, 0x002E, + /* 2184 */ 0x0036, 0x002E, + /* 2186 */ 0x0037, 0x002E, + /* 2188 */ 0x0038, 0x002E, + /* 2190 */ 0x0039, 0x002E, + /* 2192 */ 0x0031, 0x0030, 0x002E, + /* 2195 */ 0x0031, 0x0031, 0x002E, + /* 2198 */ 0x0031, 0x0032, 0x002E, + /* 2201 */ 0x0031, 0x0033, 0x002E, + /* 2204 */ 0x0031, 0x0034, 0x002E, + /* 2207 */ 0x0031, 0x0035, 0x002E, + /* 2210 */ 0x0031, 0x0036, 0x002E, + /* 2213 */ 0x0031, 0x0037, 0x002E, + /* 2216 */ 0x0031, 0x0038, 0x002E, + /* 2219 */ 0x0031, 0x0039, 0x002E, + /* 2222 */ 0x0032, 0x0030, 0x002E, + /* 2225 */ 0x0028, 0x0061, 0x0029, + /* 2228 */ 0x0028, 0x0062, 0x0029, + /* 2231 */ 0x0028, 0x0063, 0x0029, + /* 2234 */ 0x0028, 0x0064, 0x0029, + /* 2237 */ 0x0028, 0x0065, 0x0029, + /* 2240 */ 0x0028, 0x0066, 0x0029, + /* 2243 */ 0x0028, 0x0067, 0x0029, + /* 2246 */ 0x0028, 0x0068, 0x0029, + /* 2249 */ 0x0028, 0x0069, 0x0029, + /* 2252 */ 0x0028, 0x006A, 0x0029, + /* 2255 */ 0x0028, 0x006B, 0x0029, + /* 2258 */ 0x0028, 0x006C, 0x0029, + /* 2261 */ 0x0028, 0x006D, 0x0029, + /* 2264 */ 0x0028, 0x006E, 0x0029, + /* 2267 */ 0x0028, 0x006F, 0x0029, + /* 2270 */ 0x0028, 0x0070, 0x0029, + /* 2273 */ 0x0028, 0x0071, 0x0029, + /* 2276 */ 0x0028, 0x0072, 0x0029, + /* 2279 */ 0x0028, 0x0073, 0x0029, + /* 2282 */ 0x0028, 0x0074, 0x0029, + /* 2285 */ 0x0028, 0x0075, 0x0029, + /* 2288 */ 0x0028, 0x0076, 0x0029, + /* 2291 */ 0x0028, 0x0077, 0x0029, + /* 2294 */ 0x0028, 0x0078, 0x0029, + /* 2297 */ 0x0028, 0x0079, 0x0029, + /* 2300 */ 0x0028, 0x007A, 0x0029, + /* 2303 */ 0x222B, 0x222B, 0x222B, 0x222B, + /* 2307 */ 0x003A, 0x003A, 0x003D, + /* 2310 */ 0x003D, 0x003D, + /* 2312 */ 0x003D, 0x003D, 0x003D, + /* 2315 */ 0x2ADD, 0x0338, + /* 2317 */ 0x304B, 0x3099, + /* 2319 */ 0x304D, 0x3099, + /* 2321 */ 0x304F, 0x3099, + /* 2323 */ 0x3051, 0x3099, + /* 2325 */ 0x3053, 0x3099, + /* 2327 */ 0x3055, 0x3099, + /* 2329 */ 0x3057, 0x3099, + /* 2331 */ 0x3059, 0x3099, + /* 2333 */ 0x305B, 0x3099, + /* 2335 */ 0x305D, 0x3099, + /* 2337 */ 0x305F, 0x3099, + /* 2339 */ 0x3061, 0x3099, + /* 2341 */ 0x3064, 0x3099, + /* 2343 */ 0x3066, 0x3099, + /* 2345 */ 0x3068, 0x3099, + /* 2347 */ 0x306F, 0x3099, + /* 2349 */ 0x306F, 0x309A, + /* 2351 */ 0x3072, 0x3099, + /* 2353 */ 0x3072, 0x309A, + /* 2355 */ 0x3075, 0x3099, + /* 2357 */ 0x3075, 0x309A, + /* 2359 */ 0x3078, 0x3099, + /* 2361 */ 0x3078, 0x309A, + /* 2363 */ 0x307B, 0x3099, + /* 2365 */ 0x307B, 0x309A, + /* 2367 */ 0x3046, 0x3099, + /* 2369 */ 0x0020, 0x3099, + /* 2371 */ 0x0020, 0x309A, + /* 2373 */ 0x309D, 0x3099, + /* 2375 */ 0x3088, 0x308A, + /* 2377 */ 0x30AB, 0x3099, + /* 2379 */ 0x30AD, 0x3099, + /* 2381 */ 0x30AF, 0x3099, + /* 2383 */ 0x30B1, 0x3099, + /* 2385 */ 0x30B3, 0x3099, + /* 2387 */ 0x30B5, 0x3099, + /* 2389 */ 0x30B7, 0x3099, + /* 2391 */ 0x30B9, 0x3099, + /* 2393 */ 0x30BB, 0x3099, + /* 2395 */ 0x30BD, 0x3099, + /* 2397 */ 0x30BF, 0x3099, + /* 2399 */ 0x30C1, 0x3099, + /* 2401 */ 0x30C4, 0x3099, + /* 2403 */ 0x30C6, 0x3099, + /* 2405 */ 0x30C8, 0x3099, + /* 2407 */ 0x30CF, 0x3099, + /* 2409 */ 0x30CF, 0x309A, + /* 2411 */ 0x30D2, 0x3099, + /* 2413 */ 0x30D2, 0x309A, + /* 2415 */ 0x30D5, 0x3099, + /* 2417 */ 0x30D5, 0x309A, + /* 2419 */ 0x30D8, 0x3099, + /* 2421 */ 0x30D8, 0x309A, + /* 2423 */ 0x30DB, 0x3099, + /* 2425 */ 0x30DB, 0x309A, + /* 2427 */ 0x30A6, 0x3099, + /* 2429 */ 0x30EF, 0x3099, + /* 2431 */ 0x30F0, 0x3099, + /* 2433 */ 0x30F1, 0x3099, + /* 2435 */ 0x30F2, 0x3099, + /* 2437 */ 0x30FD, 0x3099, + /* 2439 */ 0x30B3, 0x30C8, + /* 2441 */ 0x0028, 0x1100, 0x0029, + /* 2444 */ 0x0028, 0x1102, 0x0029, + /* 2447 */ 0x0028, 0x1103, 0x0029, + /* 2450 */ 0x0028, 0x1105, 0x0029, + /* 2453 */ 0x0028, 0x1106, 0x0029, + /* 2456 */ 0x0028, 0x1107, 0x0029, + /* 2459 */ 0x0028, 0x1109, 0x0029, + /* 2462 */ 0x0028, 0x110B, 0x0029, + /* 2465 */ 0x0028, 0x110C, 0x0029, + /* 2468 */ 0x0028, 0x110E, 0x0029, + /* 2471 */ 0x0028, 0x110F, 0x0029, + /* 2474 */ 0x0028, 0x1110, 0x0029, + /* 2477 */ 0x0028, 0x1111, 0x0029, + /* 2480 */ 0x0028, 0x1112, 0x0029, + /* 2483 */ 0x0028, 0x1100, 0x1161, 0x0029, + /* 2487 */ 0x0028, 0x1102, 0x1161, 0x0029, + /* 2491 */ 0x0028, 0x1103, 0x1161, 0x0029, + /* 2495 */ 0x0028, 0x1105, 0x1161, 0x0029, + /* 2499 */ 0x0028, 0x1106, 0x1161, 0x0029, + /* 2503 */ 0x0028, 0x1107, 0x1161, 0x0029, + /* 2507 */ 0x0028, 0x1109, 0x1161, 0x0029, + /* 2511 */ 0x0028, 0x110B, 0x1161, 0x0029, + /* 2515 */ 0x0028, 0x110C, 0x1161, 0x0029, + /* 2519 */ 0x0028, 0x110E, 0x1161, 0x0029, + /* 2523 */ 0x0028, 0x110F, 0x1161, 0x0029, + /* 2527 */ 0x0028, 0x1110, 0x1161, 0x0029, + /* 2531 */ 0x0028, 0x1111, 0x1161, 0x0029, + /* 2535 */ 0x0028, 0x1112, 0x1161, 0x0029, + /* 2539 */ 0x0028, 0x110C, 0x116E, 0x0029, + /* 2543 */ 0x0028, 0x110B, 0x1169, 0x110C, 0x1165, 0x11AB, 0x0029, + /* 2550 */ 0x0028, 0x110B, 0x1169, 0x1112, 0x116E, 0x0029, + /* 2556 */ 0x0028, 0x4E00, 0x0029, + /* 2559 */ 0x0028, 0x4E8C, 0x0029, + /* 2562 */ 0x0028, 0x4E09, 0x0029, + /* 2565 */ 0x0028, 0x56DB, 0x0029, + /* 2568 */ 0x0028, 0x4E94, 0x0029, + /* 2571 */ 0x0028, 0x516D, 0x0029, + /* 2574 */ 0x0028, 0x4E03, 0x0029, + /* 2577 */ 0x0028, 0x516B, 0x0029, + /* 2580 */ 0x0028, 0x4E5D, 0x0029, + /* 2583 */ 0x0028, 0x5341, 0x0029, + /* 2586 */ 0x0028, 0x6708, 0x0029, + /* 2589 */ 0x0028, 0x706B, 0x0029, + /* 2592 */ 0x0028, 0x6C34, 0x0029, + /* 2595 */ 0x0028, 0x6728, 0x0029, + /* 2598 */ 0x0028, 0x91D1, 0x0029, + /* 2601 */ 0x0028, 0x571F, 0x0029, + /* 2604 */ 0x0028, 0x65E5, 0x0029, + /* 2607 */ 0x0028, 0x682A, 0x0029, + /* 2610 */ 0x0028, 0x6709, 0x0029, + /* 2613 */ 0x0028, 0x793E, 0x0029, + /* 2616 */ 0x0028, 0x540D, 0x0029, + /* 2619 */ 0x0028, 0x7279, 0x0029, + /* 2622 */ 0x0028, 0x8CA1, 0x0029, + /* 2625 */ 0x0028, 0x795D, 0x0029, + /* 2628 */ 0x0028, 0x52B4, 0x0029, + /* 2631 */ 0x0028, 0x4EE3, 0x0029, + /* 2634 */ 0x0028, 0x547C, 0x0029, + /* 2637 */ 0x0028, 0x5B66, 0x0029, + /* 2640 */ 0x0028, 0x76E3, 0x0029, + /* 2643 */ 0x0028, 0x4F01, 0x0029, + /* 2646 */ 0x0028, 0x8CC7, 0x0029, + /* 2649 */ 0x0028, 0x5354, 0x0029, + /* 2652 */ 0x0028, 0x796D, 0x0029, + /* 2655 */ 0x0028, 0x4F11, 0x0029, + /* 2658 */ 0x0028, 0x81EA, 0x0029, + /* 2661 */ 0x0028, 0x81F3, 0x0029, + /* 2664 */ 0x0050, 0x0054, 0x0045, + /* 2667 */ 0x0032, 0x0031, + /* 2669 */ 0x0032, 0x0032, + /* 2671 */ 0x0032, 0x0033, + /* 2673 */ 0x0032, 0x0034, + /* 2675 */ 0x0032, 0x0035, + /* 2677 */ 0x0032, 0x0036, + /* 2679 */ 0x0032, 0x0037, + /* 2681 */ 0x0032, 0x0038, + /* 2683 */ 0x0032, 0x0039, + /* 2685 */ 0x0033, 0x0030, + /* 2687 */ 0x0033, 0x0031, + /* 2689 */ 0x0033, 0x0032, + /* 2691 */ 0x0033, 0x0033, + /* 2693 */ 0x0033, 0x0034, + /* 2695 */ 0x0033, 0x0035, + /* 2697 */ 0x1100, 0x1161, + /* 2699 */ 0x1102, 0x1161, + /* 2701 */ 0x1103, 0x1161, + /* 2703 */ 0x1105, 0x1161, + /* 2705 */ 0x1106, 0x1161, + /* 2707 */ 0x1107, 0x1161, + /* 2709 */ 0x1109, 0x1161, + /* 2711 */ 0x110B, 0x1161, + /* 2713 */ 0x110C, 0x1161, + /* 2715 */ 0x110E, 0x1161, + /* 2717 */ 0x110F, 0x1161, + /* 2719 */ 0x1110, 0x1161, + /* 2721 */ 0x1111, 0x1161, + /* 2723 */ 0x1112, 0x1161, + /* 2725 */ 0x110E, 0x1161, 0x11B7, 0x1100, 0x1169, + /* 2730 */ 0x110C, 0x116E, 0x110B, 0x1174, + /* 2734 */ 0x110B, 0x116E, + /* 2736 */ 0x0033, 0x0036, + /* 2738 */ 0x0033, 0x0037, + /* 2740 */ 0x0033, 0x0038, + /* 2742 */ 0x0033, 0x0039, + /* 2744 */ 0x0034, 0x0030, + /* 2746 */ 0x0034, 0x0031, + /* 2748 */ 0x0034, 0x0032, + /* 2750 */ 0x0034, 0x0033, + /* 2752 */ 0x0034, 0x0034, + /* 2754 */ 0x0034, 0x0035, + /* 2756 */ 0x0034, 0x0036, + /* 2758 */ 0x0034, 0x0037, + /* 2760 */ 0x0034, 0x0038, + /* 2762 */ 0x0034, 0x0039, + /* 2764 */ 0x0035, 0x0030, + /* 2766 */ 0x0031, 0x6708, + /* 2768 */ 0x0032, 0x6708, + /* 2770 */ 0x0033, 0x6708, + /* 2772 */ 0x0034, 0x6708, + /* 2774 */ 0x0035, 0x6708, + /* 2776 */ 0x0036, 0x6708, + /* 2778 */ 0x0037, 0x6708, + /* 2780 */ 0x0038, 0x6708, + /* 2782 */ 0x0039, 0x6708, + /* 2784 */ 0x0031, 0x0030, 0x6708, + /* 2787 */ 0x0031, 0x0031, 0x6708, + /* 2790 */ 0x0031, 0x0032, 0x6708, + /* 2793 */ 0x0048, 0x0067, + /* 2795 */ 0x0065, 0x0072, 0x0067, + /* 2798 */ 0x0065, 0x0056, + /* 2800 */ 0x004C, 0x0054, 0x0044, + /* 2803 */ 0x4EE4, 0x548C, + /* 2805 */ 0x30A2, 0x30D1, 0x30FC, 0x30C8, + /* 2809 */ 0x30A2, 0x30EB, 0x30D5, 0x30A1, + /* 2813 */ 0x30A2, 0x30F3, 0x30DA, 0x30A2, + /* 2817 */ 0x30A2, 0x30FC, 0x30EB, + /* 2820 */ 0x30A4, 0x30CB, 0x30F3, 0x30B0, + /* 2824 */ 0x30A4, 0x30F3, 0x30C1, + /* 2827 */ 0x30A6, 0x30A9, 0x30F3, + /* 2830 */ 0x30A8, 0x30B9, 0x30AF, 0x30FC, 0x30C9, + /* 2835 */ 0x30A8, 0x30FC, 0x30AB, 0x30FC, + /* 2839 */ 0x30AA, 0x30F3, 0x30B9, + /* 2842 */ 0x30AA, 0x30FC, 0x30E0, + /* 2845 */ 0x30AB, 0x30A4, 0x30EA, + /* 2848 */ 0x30AB, 0x30E9, 0x30C3, 0x30C8, + /* 2852 */ 0x30AB, 0x30ED, 0x30EA, 0x30FC, + /* 2856 */ 0x30AC, 0x30ED, 0x30F3, + /* 2859 */ 0x30AC, 0x30F3, 0x30DE, + /* 2862 */ 0x30AE, 0x30AC, + /* 2864 */ 0x30AE, 0x30CB, 0x30FC, + /* 2867 */ 0x30AD, 0x30E5, 0x30EA, 0x30FC, + /* 2871 */ 0x30AE, 0x30EB, 0x30C0, 0x30FC, + /* 2875 */ 0x30AD, 0x30ED, + /* 2877 */ 0x30AD, 0x30ED, 0x30B0, 0x30E9, 0x30E0, + /* 2882 */ 0x30AD, 0x30ED, 0x30E1, 0x30FC, 0x30C8, 0x30EB, + /* 2888 */ 0x30AD, 0x30ED, 0x30EF, 0x30C3, 0x30C8, + /* 2893 */ 0x30B0, 0x30E9, 0x30E0, + /* 2896 */ 0x30B0, 0x30E9, 0x30E0, 0x30C8, 0x30F3, + /* 2901 */ 0x30AF, 0x30EB, 0x30BC, 0x30A4, 0x30ED, + /* 2906 */ 0x30AF, 0x30ED, 0x30FC, 0x30CD, + /* 2910 */ 0x30B1, 0x30FC, 0x30B9, + /* 2913 */ 0x30B3, 0x30EB, 0x30CA, + /* 2916 */ 0x30B3, 0x30FC, 0x30DD, + /* 2919 */ 0x30B5, 0x30A4, 0x30AF, 0x30EB, + /* 2923 */ 0x30B5, 0x30F3, 0x30C1, 0x30FC, 0x30E0, + /* 2928 */ 0x30B7, 0x30EA, 0x30F3, 0x30B0, + /* 2932 */ 0x30BB, 0x30F3, 0x30C1, + /* 2935 */ 0x30BB, 0x30F3, 0x30C8, + /* 2938 */ 0x30C0, 0x30FC, 0x30B9, + /* 2941 */ 0x30C7, 0x30B7, + /* 2943 */ 0x30C9, 0x30EB, + /* 2945 */ 0x30C8, 0x30F3, + /* 2947 */ 0x30CA, 0x30CE, + /* 2949 */ 0x30CE, 0x30C3, 0x30C8, + /* 2952 */ 0x30CF, 0x30A4, 0x30C4, + /* 2955 */ 0x30D1, 0x30FC, 0x30BB, 0x30F3, 0x30C8, + /* 2960 */ 0x30D1, 0x30FC, 0x30C4, + /* 2963 */ 0x30D0, 0x30FC, 0x30EC, 0x30EB, + /* 2967 */ 0x30D4, 0x30A2, 0x30B9, 0x30C8, 0x30EB, + /* 2972 */ 0x30D4, 0x30AF, 0x30EB, + /* 2975 */ 0x30D4, 0x30B3, + /* 2977 */ 0x30D3, 0x30EB, + /* 2979 */ 0x30D5, 0x30A1, 0x30E9, 0x30C3, 0x30C9, + /* 2984 */ 0x30D5, 0x30A3, 0x30FC, 0x30C8, + /* 2988 */ 0x30D6, 0x30C3, 0x30B7, 0x30A7, 0x30EB, + /* 2993 */ 0x30D5, 0x30E9, 0x30F3, + /* 2996 */ 0x30D8, 0x30AF, 0x30BF, 0x30FC, 0x30EB, + /* 3001 */ 0x30DA, 0x30BD, + /* 3003 */ 0x30DA, 0x30CB, 0x30D2, + /* 3006 */ 0x30D8, 0x30EB, 0x30C4, + /* 3009 */ 0x30DA, 0x30F3, 0x30B9, + /* 3012 */ 0x30DA, 0x30FC, 0x30B8, + /* 3015 */ 0x30D9, 0x30FC, 0x30BF, + /* 3018 */ 0x30DD, 0x30A4, 0x30F3, 0x30C8, + /* 3022 */ 0x30DC, 0x30EB, 0x30C8, + /* 3025 */ 0x30DB, 0x30F3, + /* 3027 */ 0x30DD, 0x30F3, 0x30C9, + /* 3030 */ 0x30DB, 0x30FC, 0x30EB, + /* 3033 */ 0x30DB, 0x30FC, 0x30F3, + /* 3036 */ 0x30DE, 0x30A4, 0x30AF, 0x30ED, + /* 3040 */ 0x30DE, 0x30A4, 0x30EB, + /* 3043 */ 0x30DE, 0x30C3, 0x30CF, + /* 3046 */ 0x30DE, 0x30EB, 0x30AF, + /* 3049 */ 0x30DE, 0x30F3, 0x30B7, 0x30E7, 0x30F3, + /* 3054 */ 0x30DF, 0x30AF, 0x30ED, 0x30F3, + /* 3058 */ 0x30DF, 0x30EA, + /* 3060 */ 0x30DF, 0x30EA, 0x30D0, 0x30FC, 0x30EB, + /* 3065 */ 0x30E1, 0x30AC, + /* 3067 */ 0x30E1, 0x30AC, 0x30C8, 0x30F3, + /* 3071 */ 0x30E1, 0x30FC, 0x30C8, 0x30EB, + /* 3075 */ 0x30E4, 0x30FC, 0x30C9, + /* 3078 */ 0x30E4, 0x30FC, 0x30EB, + /* 3081 */ 0x30E6, 0x30A2, 0x30F3, + /* 3084 */ 0x30EA, 0x30C3, 0x30C8, 0x30EB, + /* 3088 */ 0x30EA, 0x30E9, + /* 3090 */ 0x30EB, 0x30D4, 0x30FC, + /* 3093 */ 0x30EB, 0x30FC, 0x30D6, 0x30EB, + /* 3097 */ 0x30EC, 0x30E0, + /* 3099 */ 0x30EC, 0x30F3, 0x30C8, 0x30B2, 0x30F3, + /* 3104 */ 0x30EF, 0x30C3, 0x30C8, + /* 3107 */ 0x0030, 0x70B9, + /* 3109 */ 0x0031, 0x70B9, + /* 3111 */ 0x0032, 0x70B9, + /* 3113 */ 0x0033, 0x70B9, + /* 3115 */ 0x0034, 0x70B9, + /* 3117 */ 0x0035, 0x70B9, + /* 3119 */ 0x0036, 0x70B9, + /* 3121 */ 0x0037, 0x70B9, + /* 3123 */ 0x0038, 0x70B9, + /* 3125 */ 0x0039, 0x70B9, + /* 3127 */ 0x0031, 0x0030, 0x70B9, + /* 3130 */ 0x0031, 0x0031, 0x70B9, + /* 3133 */ 0x0031, 0x0032, 0x70B9, + /* 3136 */ 0x0031, 0x0033, 0x70B9, + /* 3139 */ 0x0031, 0x0034, 0x70B9, + /* 3142 */ 0x0031, 0x0035, 0x70B9, + /* 3145 */ 0x0031, 0x0036, 0x70B9, + /* 3148 */ 0x0031, 0x0037, 0x70B9, + /* 3151 */ 0x0031, 0x0038, 0x70B9, + /* 3154 */ 0x0031, 0x0039, 0x70B9, + /* 3157 */ 0x0032, 0x0030, 0x70B9, + /* 3160 */ 0x0032, 0x0031, 0x70B9, + /* 3163 */ 0x0032, 0x0032, 0x70B9, + /* 3166 */ 0x0032, 0x0033, 0x70B9, + /* 3169 */ 0x0032, 0x0034, 0x70B9, + /* 3172 */ 0x0068, 0x0050, 0x0061, + /* 3175 */ 0x0064, 0x0061, + /* 3177 */ 0x0041, 0x0055, + /* 3179 */ 0x0062, 0x0061, 0x0072, + /* 3182 */ 0x006F, 0x0056, + /* 3184 */ 0x0070, 0x0063, + /* 3186 */ 0x0064, 0x006D, + /* 3188 */ 0x0064, 0x006D, 0x00B2, + /* 3191 */ 0x0064, 0x006D, 0x00B3, + /* 3194 */ 0x0049, 0x0055, + /* 3196 */ 0x5E73, 0x6210, + /* 3198 */ 0x662D, 0x548C, + /* 3200 */ 0x5927, 0x6B63, + /* 3202 */ 0x660E, 0x6CBB, + /* 3204 */ 0x682A, 0x5F0F, 0x4F1A, 0x793E, + /* 3208 */ 0x0070, 0x0041, + /* 3210 */ 0x006E, 0x0041, + /* 3212 */ 0x03BC, 0x0041, + /* 3214 */ 0x006D, 0x0041, + /* 3216 */ 0x006B, 0x0041, + /* 3218 */ 0x004B, 0x0042, + /* 3220 */ 0x004D, 0x0042, + /* 3222 */ 0x0047, 0x0042, + /* 3224 */ 0x0063, 0x0061, 0x006C, + /* 3227 */ 0x006B, 0x0063, 0x0061, 0x006C, + /* 3231 */ 0x0070, 0x0046, + /* 3233 */ 0x006E, 0x0046, + /* 3235 */ 0x03BC, 0x0046, + /* 3237 */ 0x03BC, 0x0067, + /* 3239 */ 0x006D, 0x0067, + /* 3241 */ 0x006B, 0x0067, + /* 3243 */ 0x0048, 0x007A, + /* 3245 */ 0x006B, 0x0048, 0x007A, + /* 3248 */ 0x004D, 0x0048, 0x007A, + /* 3251 */ 0x0047, 0x0048, 0x007A, + /* 3254 */ 0x0054, 0x0048, 0x007A, + /* 3257 */ 0x03BC, 0x2113, + /* 3259 */ 0x006D, 0x2113, + /* 3261 */ 0x0064, 0x2113, + /* 3263 */ 0x006B, 0x2113, + /* 3265 */ 0x0066, 0x006D, + /* 3267 */ 0x006E, 0x006D, + /* 3269 */ 0x03BC, 0x006D, + /* 3271 */ 0x006D, 0x006D, + /* 3273 */ 0x0063, 0x006D, + /* 3275 */ 0x006B, 0x006D, + /* 3277 */ 0x006D, 0x006D, 0x00B2, + /* 3280 */ 0x0063, 0x006D, 0x00B2, + /* 3283 */ 0x006D, 0x00B2, + /* 3285 */ 0x006B, 0x006D, 0x00B2, + /* 3288 */ 0x006D, 0x006D, 0x00B3, + /* 3291 */ 0x0063, 0x006D, 0x00B3, + /* 3294 */ 0x006D, 0x00B3, + /* 3296 */ 0x006B, 0x006D, 0x00B3, + /* 3299 */ 0x006D, 0x2215, 0x0073, + /* 3302 */ 0x006D, 0x2215, 0x0073, 0x00B2, + /* 3306 */ 0x0050, 0x0061, + /* 3308 */ 0x006B, 0x0050, 0x0061, + /* 3311 */ 0x004D, 0x0050, 0x0061, + /* 3314 */ 0x0047, 0x0050, 0x0061, + /* 3317 */ 0x0072, 0x0061, 0x0064, + /* 3320 */ 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, + /* 3325 */ 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0x00B2, + /* 3331 */ 0x0070, 0x0073, + /* 3333 */ 0x006E, 0x0073, + /* 3335 */ 0x03BC, 0x0073, + /* 3337 */ 0x006D, 0x0073, + /* 3339 */ 0x0070, 0x0056, + /* 3341 */ 0x006E, 0x0056, + /* 3343 */ 0x03BC, 0x0056, + /* 3345 */ 0x006D, 0x0056, + /* 3347 */ 0x006B, 0x0056, + /* 3349 */ 0x004D, 0x0056, + /* 3351 */ 0x0070, 0x0057, + /* 3353 */ 0x006E, 0x0057, + /* 3355 */ 0x03BC, 0x0057, + /* 3357 */ 0x006D, 0x0057, + /* 3359 */ 0x006B, 0x0057, + /* 3361 */ 0x004D, 0x0057, + /* 3363 */ 0x006B, 0x03A9, + /* 3365 */ 0x004D, 0x03A9, + /* 3367 */ 0x0061, 0x002E, 0x006D, 0x002E, + /* 3371 */ 0x0042, 0x0071, + /* 3373 */ 0x0063, 0x0063, + /* 3375 */ 0x0063, 0x0064, + /* 3377 */ 0x0043, 0x2215, 0x006B, 0x0067, + /* 3381 */ 0x0043, 0x006F, 0x002E, + /* 3384 */ 0x0064, 0x0042, + /* 3386 */ 0x0047, 0x0079, + /* 3388 */ 0x0068, 0x0061, + /* 3390 */ 0x0048, 0x0050, + /* 3392 */ 0x0069, 0x006E, + /* 3394 */ 0x004B, 0x004B, + /* 3396 */ 0x004B, 0x004D, + /* 3398 */ 0x006B, 0x0074, + /* 3400 */ 0x006C, 0x006D, + /* 3402 */ 0x006C, 0x006E, + /* 3404 */ 0x006C, 0x006F, 0x0067, + /* 3407 */ 0x006C, 0x0078, + /* 3409 */ 0x006D, 0x0062, + /* 3411 */ 0x006D, 0x0069, 0x006C, + /* 3414 */ 0x006D, 0x006F, 0x006C, + /* 3417 */ 0x0050, 0x0048, + /* 3419 */ 0x0070, 0x002E, 0x006D, 0x002E, + /* 3423 */ 0x0050, 0x0050, 0x004D, + /* 3426 */ 0x0050, 0x0052, + /* 3428 */ 0x0073, 0x0072, + /* 3430 */ 0x0053, 0x0076, + /* 3432 */ 0x0057, 0x0062, + /* 3434 */ 0x0056, 0x2215, 0x006D, + /* 3437 */ 0x0041, 0x2215, 0x006D, + /* 3440 */ 0x0031, 0x65E5, + /* 3442 */ 0x0032, 0x65E5, + /* 3444 */ 0x0033, 0x65E5, + /* 3446 */ 0x0034, 0x65E5, + /* 3448 */ 0x0035, 0x65E5, + /* 3450 */ 0x0036, 0x65E5, + /* 3452 */ 0x0037, 0x65E5, + /* 3454 */ 0x0038, 0x65E5, + /* 3456 */ 0x0039, 0x65E5, + /* 3458 */ 0x0031, 0x0030, 0x65E5, + /* 3461 */ 0x0031, 0x0031, 0x65E5, + /* 3464 */ 0x0031, 0x0032, 0x65E5, + /* 3467 */ 0x0031, 0x0033, 0x65E5, + /* 3470 */ 0x0031, 0x0034, 0x65E5, + /* 3473 */ 0x0031, 0x0035, 0x65E5, + /* 3476 */ 0x0031, 0x0036, 0x65E5, + /* 3479 */ 0x0031, 0x0037, 0x65E5, + /* 3482 */ 0x0031, 0x0038, 0x65E5, + /* 3485 */ 0x0031, 0x0039, 0x65E5, + /* 3488 */ 0x0032, 0x0030, 0x65E5, + /* 3491 */ 0x0032, 0x0031, 0x65E5, + /* 3494 */ 0x0032, 0x0032, 0x65E5, + /* 3497 */ 0x0032, 0x0033, 0x65E5, + /* 3500 */ 0x0032, 0x0034, 0x65E5, + /* 3503 */ 0x0032, 0x0035, 0x65E5, + /* 3506 */ 0x0032, 0x0036, 0x65E5, + /* 3509 */ 0x0032, 0x0037, 0x65E5, + /* 3512 */ 0x0032, 0x0038, 0x65E5, + /* 3515 */ 0x0032, 0x0039, 0x65E5, + /* 3518 */ 0x0033, 0x0030, 0x65E5, + /* 3521 */ 0x0033, 0x0031, 0x65E5, + /* 3524 */ 0x0067, 0x0061, 0x006C, + /* 3527 */ 0x242EE, + /* 3528 */ 0x2284A, + /* 3529 */ 0x22844, + /* 3530 */ 0x233D5, + /* 3531 */ 0x25249, + /* 3532 */ 0x25CD0, + /* 3533 */ 0x27ED3, + /* 3534 */ 0x0066, 0x0066, + /* 3536 */ 0x0066, 0x0069, + /* 3538 */ 0x0066, 0x006C, + /* 3540 */ 0x0066, 0x0066, 0x0069, + /* 3543 */ 0x0066, 0x0066, 0x006C, + /* 3546 */ 0x017F, 0x0074, + /* 3548 */ 0x0073, 0x0074, + /* 3550 */ 0x0574, 0x0576, + /* 3552 */ 0x0574, 0x0565, + /* 3554 */ 0x0574, 0x056B, + /* 3556 */ 0x057E, 0x0576, + /* 3558 */ 0x0574, 0x056D, + /* 3560 */ 0x05D9, 0x05B4, + /* 3562 */ 0x05F2, 0x05B7, + /* 3564 */ 0x05E9, 0x05C1, + /* 3566 */ 0x05E9, 0x05C2, + /* 3568 */ 0xFB49, 0x05C1, + /* 3570 */ 0xFB49, 0x05C2, + /* 3572 */ 0x05D0, 0x05B7, + /* 3574 */ 0x05D0, 0x05B8, + /* 3576 */ 0x05D0, 0x05BC, + /* 3578 */ 0x05D1, 0x05BC, + /* 3580 */ 0x05D2, 0x05BC, + /* 3582 */ 0x05D3, 0x05BC, + /* 3584 */ 0x05D4, 0x05BC, + /* 3586 */ 0x05D5, 0x05BC, + /* 3588 */ 0x05D6, 0x05BC, + /* 3590 */ 0x05D8, 0x05BC, + /* 3592 */ 0x05D9, 0x05BC, + /* 3594 */ 0x05DA, 0x05BC, + /* 3596 */ 0x05DB, 0x05BC, + /* 3598 */ 0x05DC, 0x05BC, + /* 3600 */ 0x05DE, 0x05BC, + /* 3602 */ 0x05E0, 0x05BC, + /* 3604 */ 0x05E1, 0x05BC, + /* 3606 */ 0x05E3, 0x05BC, + /* 3608 */ 0x05E4, 0x05BC, + /* 3610 */ 0x05E6, 0x05BC, + /* 3612 */ 0x05E7, 0x05BC, + /* 3614 */ 0x05E8, 0x05BC, + /* 3616 */ 0x05E9, 0x05BC, + /* 3618 */ 0x05EA, 0x05BC, + /* 3620 */ 0x05D5, 0x05B9, + /* 3622 */ 0x05D1, 0x05BF, + /* 3624 */ 0x05DB, 0x05BF, + /* 3626 */ 0x05E4, 0x05BF, + /* 3628 */ 0x05D0, 0x05DC, + /* 3630 */ 0x0626, 0x0627, + /* 3632 */ 0x0626, 0x0627, + /* 3634 */ 0x0626, 0x06D5, + /* 3636 */ 0x0626, 0x06D5, + /* 3638 */ 0x0626, 0x0648, + /* 3640 */ 0x0626, 0x0648, + /* 3642 */ 0x0626, 0x06C7, + /* 3644 */ 0x0626, 0x06C7, + /* 3646 */ 0x0626, 0x06C6, + /* 3648 */ 0x0626, 0x06C6, + /* 3650 */ 0x0626, 0x06C8, + /* 3652 */ 0x0626, 0x06C8, + /* 3654 */ 0x0626, 0x06D0, + /* 3656 */ 0x0626, 0x06D0, + /* 3658 */ 0x0626, 0x06D0, + /* 3660 */ 0x0626, 0x0649, + /* 3662 */ 0x0626, 0x0649, + /* 3664 */ 0x0626, 0x0649, + /* 3666 */ 0x0626, 0x062C, + /* 3668 */ 0x0626, 0x062D, + /* 3670 */ 0x0626, 0x0645, + /* 3672 */ 0x0626, 0x0649, + /* 3674 */ 0x0626, 0x064A, + /* 3676 */ 0x0628, 0x062C, + /* 3678 */ 0x0628, 0x062D, + /* 3680 */ 0x0628, 0x062E, + /* 3682 */ 0x0628, 0x0645, + /* 3684 */ 0x0628, 0x0649, + /* 3686 */ 0x0628, 0x064A, + /* 3688 */ 0x062A, 0x062C, + /* 3690 */ 0x062A, 0x062D, + /* 3692 */ 0x062A, 0x062E, + /* 3694 */ 0x062A, 0x0645, + /* 3696 */ 0x062A, 0x0649, + /* 3698 */ 0x062A, 0x064A, + /* 3700 */ 0x062B, 0x062C, + /* 3702 */ 0x062B, 0x0645, + /* 3704 */ 0x062B, 0x0649, + /* 3706 */ 0x062B, 0x064A, + /* 3708 */ 0x062C, 0x062D, + /* 3710 */ 0x062C, 0x0645, + /* 3712 */ 0x062D, 0x062C, + /* 3714 */ 0x062D, 0x0645, + /* 3716 */ 0x062E, 0x062C, + /* 3718 */ 0x062E, 0x062D, + /* 3720 */ 0x062E, 0x0645, + /* 3722 */ 0x0633, 0x062C, + /* 3724 */ 0x0633, 0x062D, + /* 3726 */ 0x0633, 0x062E, + /* 3728 */ 0x0633, 0x0645, + /* 3730 */ 0x0635, 0x062D, + /* 3732 */ 0x0635, 0x0645, + /* 3734 */ 0x0636, 0x062C, + /* 3736 */ 0x0636, 0x062D, + /* 3738 */ 0x0636, 0x062E, + /* 3740 */ 0x0636, 0x0645, + /* 3742 */ 0x0637, 0x062D, + /* 3744 */ 0x0637, 0x0645, + /* 3746 */ 0x0638, 0x0645, + /* 3748 */ 0x0639, 0x062C, + /* 3750 */ 0x0639, 0x0645, + /* 3752 */ 0x063A, 0x062C, + /* 3754 */ 0x063A, 0x0645, + /* 3756 */ 0x0641, 0x062C, + /* 3758 */ 0x0641, 0x062D, + /* 3760 */ 0x0641, 0x062E, + /* 3762 */ 0x0641, 0x0645, + /* 3764 */ 0x0641, 0x0649, + /* 3766 */ 0x0641, 0x064A, + /* 3768 */ 0x0642, 0x062D, + /* 3770 */ 0x0642, 0x0645, + /* 3772 */ 0x0642, 0x0649, + /* 3774 */ 0x0642, 0x064A, + /* 3776 */ 0x0643, 0x0627, + /* 3778 */ 0x0643, 0x062C, + /* 3780 */ 0x0643, 0x062D, + /* 3782 */ 0x0643, 0x062E, + /* 3784 */ 0x0643, 0x0644, + /* 3786 */ 0x0643, 0x0645, + /* 3788 */ 0x0643, 0x0649, + /* 3790 */ 0x0643, 0x064A, + /* 3792 */ 0x0644, 0x062C, + /* 3794 */ 0x0644, 0x062D, + /* 3796 */ 0x0644, 0x062E, + /* 3798 */ 0x0644, 0x0645, + /* 3800 */ 0x0644, 0x0649, + /* 3802 */ 0x0644, 0x064A, + /* 3804 */ 0x0645, 0x062C, + /* 3806 */ 0x0645, 0x062D, + /* 3808 */ 0x0645, 0x062E, + /* 3810 */ 0x0645, 0x0645, + /* 3812 */ 0x0645, 0x0649, + /* 3814 */ 0x0645, 0x064A, + /* 3816 */ 0x0646, 0x062C, + /* 3818 */ 0x0646, 0x062D, + /* 3820 */ 0x0646, 0x062E, + /* 3822 */ 0x0646, 0x0645, + /* 3824 */ 0x0646, 0x0649, + /* 3826 */ 0x0646, 0x064A, + /* 3828 */ 0x0647, 0x062C, + /* 3830 */ 0x0647, 0x0645, + /* 3832 */ 0x0647, 0x0649, + /* 3834 */ 0x0647, 0x064A, + /* 3836 */ 0x064A, 0x062C, + /* 3838 */ 0x064A, 0x062D, + /* 3840 */ 0x064A, 0x062E, + /* 3842 */ 0x064A, 0x0645, + /* 3844 */ 0x064A, 0x0649, + /* 3846 */ 0x064A, 0x064A, + /* 3848 */ 0x0630, 0x0670, + /* 3850 */ 0x0631, 0x0670, + /* 3852 */ 0x0649, 0x0670, + /* 3854 */ 0x0020, 0x064C, 0x0651, + /* 3857 */ 0x0020, 0x064D, 0x0651, + /* 3860 */ 0x0020, 0x064E, 0x0651, + /* 3863 */ 0x0020, 0x064F, 0x0651, + /* 3866 */ 0x0020, 0x0650, 0x0651, + /* 3869 */ 0x0020, 0x0651, 0x0670, + /* 3872 */ 0x0626, 0x0631, + /* 3874 */ 0x0626, 0x0632, + /* 3876 */ 0x0626, 0x0645, + /* 3878 */ 0x0626, 0x0646, + /* 3880 */ 0x0626, 0x0649, + /* 3882 */ 0x0626, 0x064A, + /* 3884 */ 0x0628, 0x0631, + /* 3886 */ 0x0628, 0x0632, + /* 3888 */ 0x0628, 0x0645, + /* 3890 */ 0x0628, 0x0646, + /* 3892 */ 0x0628, 0x0649, + /* 3894 */ 0x0628, 0x064A, + /* 3896 */ 0x062A, 0x0631, + /* 3898 */ 0x062A, 0x0632, + /* 3900 */ 0x062A, 0x0645, + /* 3902 */ 0x062A, 0x0646, + /* 3904 */ 0x062A, 0x0649, + /* 3906 */ 0x062A, 0x064A, + /* 3908 */ 0x062B, 0x0631, + /* 3910 */ 0x062B, 0x0632, + /* 3912 */ 0x062B, 0x0645, + /* 3914 */ 0x062B, 0x0646, + /* 3916 */ 0x062B, 0x0649, + /* 3918 */ 0x062B, 0x064A, + /* 3920 */ 0x0641, 0x0649, + /* 3922 */ 0x0641, 0x064A, + /* 3924 */ 0x0642, 0x0649, + /* 3926 */ 0x0642, 0x064A, + /* 3928 */ 0x0643, 0x0627, + /* 3930 */ 0x0643, 0x0644, + /* 3932 */ 0x0643, 0x0645, + /* 3934 */ 0x0643, 0x0649, + /* 3936 */ 0x0643, 0x064A, + /* 3938 */ 0x0644, 0x0645, + /* 3940 */ 0x0644, 0x0649, + /* 3942 */ 0x0644, 0x064A, + /* 3944 */ 0x0645, 0x0627, + /* 3946 */ 0x0645, 0x0645, + /* 3948 */ 0x0646, 0x0631, + /* 3950 */ 0x0646, 0x0632, + /* 3952 */ 0x0646, 0x0645, + /* 3954 */ 0x0646, 0x0646, + /* 3956 */ 0x0646, 0x0649, + /* 3958 */ 0x0646, 0x064A, + /* 3960 */ 0x0649, 0x0670, + /* 3962 */ 0x064A, 0x0631, + /* 3964 */ 0x064A, 0x0632, + /* 3966 */ 0x064A, 0x0645, + /* 3968 */ 0x064A, 0x0646, + /* 3970 */ 0x064A, 0x0649, + /* 3972 */ 0x064A, 0x064A, + /* 3974 */ 0x0626, 0x062C, + /* 3976 */ 0x0626, 0x062D, + /* 3978 */ 0x0626, 0x062E, + /* 3980 */ 0x0626, 0x0645, + /* 3982 */ 0x0626, 0x0647, + /* 3984 */ 0x0628, 0x062C, + /* 3986 */ 0x0628, 0x062D, + /* 3988 */ 0x0628, 0x062E, + /* 3990 */ 0x0628, 0x0645, + /* 3992 */ 0x0628, 0x0647, + /* 3994 */ 0x062A, 0x062C, + /* 3996 */ 0x062A, 0x062D, + /* 3998 */ 0x062A, 0x062E, + /* 4000 */ 0x062A, 0x0645, + /* 4002 */ 0x062A, 0x0647, + /* 4004 */ 0x062B, 0x0645, + /* 4006 */ 0x062C, 0x062D, + /* 4008 */ 0x062C, 0x0645, + /* 4010 */ 0x062D, 0x062C, + /* 4012 */ 0x062D, 0x0645, + /* 4014 */ 0x062E, 0x062C, + /* 4016 */ 0x062E, 0x0645, + /* 4018 */ 0x0633, 0x062C, + /* 4020 */ 0x0633, 0x062D, + /* 4022 */ 0x0633, 0x062E, + /* 4024 */ 0x0633, 0x0645, + /* 4026 */ 0x0635, 0x062D, + /* 4028 */ 0x0635, 0x062E, + /* 4030 */ 0x0635, 0x0645, + /* 4032 */ 0x0636, 0x062C, + /* 4034 */ 0x0636, 0x062D, + /* 4036 */ 0x0636, 0x062E, + /* 4038 */ 0x0636, 0x0645, + /* 4040 */ 0x0637, 0x062D, + /* 4042 */ 0x0638, 0x0645, + /* 4044 */ 0x0639, 0x062C, + /* 4046 */ 0x0639, 0x0645, + /* 4048 */ 0x063A, 0x062C, + /* 4050 */ 0x063A, 0x0645, + /* 4052 */ 0x0641, 0x062C, + /* 4054 */ 0x0641, 0x062D, + /* 4056 */ 0x0641, 0x062E, + /* 4058 */ 0x0641, 0x0645, + /* 4060 */ 0x0642, 0x062D, + /* 4062 */ 0x0642, 0x0645, + /* 4064 */ 0x0643, 0x062C, + /* 4066 */ 0x0643, 0x062D, + /* 4068 */ 0x0643, 0x062E, + /* 4070 */ 0x0643, 0x0644, + /* 4072 */ 0x0643, 0x0645, + /* 4074 */ 0x0644, 0x062C, + /* 4076 */ 0x0644, 0x062D, + /* 4078 */ 0x0644, 0x062E, + /* 4080 */ 0x0644, 0x0645, + /* 4082 */ 0x0644, 0x0647, + /* 4084 */ 0x0645, 0x062C, + /* 4086 */ 0x0645, 0x062D, + /* 4088 */ 0x0645, 0x062E, + /* 4090 */ 0x0645, 0x0645, + /* 4092 */ 0x0646, 0x062C, + /* 4094 */ 0x0646, 0x062D, + /* 4096 */ 0x0646, 0x062E, + /* 4098 */ 0x0646, 0x0645, + /* 4100 */ 0x0646, 0x0647, + /* 4102 */ 0x0647, 0x062C, + /* 4104 */ 0x0647, 0x0645, + /* 4106 */ 0x0647, 0x0670, + /* 4108 */ 0x064A, 0x062C, + /* 4110 */ 0x064A, 0x062D, + /* 4112 */ 0x064A, 0x062E, + /* 4114 */ 0x064A, 0x0645, + /* 4116 */ 0x064A, 0x0647, + /* 4118 */ 0x0626, 0x0645, + /* 4120 */ 0x0626, 0x0647, + /* 4122 */ 0x0628, 0x0645, + /* 4124 */ 0x0628, 0x0647, + /* 4126 */ 0x062A, 0x0645, + /* 4128 */ 0x062A, 0x0647, + /* 4130 */ 0x062B, 0x0645, + /* 4132 */ 0x062B, 0x0647, + /* 4134 */ 0x0633, 0x0645, + /* 4136 */ 0x0633, 0x0647, + /* 4138 */ 0x0634, 0x0645, + /* 4140 */ 0x0634, 0x0647, + /* 4142 */ 0x0643, 0x0644, + /* 4144 */ 0x0643, 0x0645, + /* 4146 */ 0x0644, 0x0645, + /* 4148 */ 0x0646, 0x0645, + /* 4150 */ 0x0646, 0x0647, + /* 4152 */ 0x064A, 0x0645, + /* 4154 */ 0x064A, 0x0647, + /* 4156 */ 0x0640, 0x064E, 0x0651, + /* 4159 */ 0x0640, 0x064F, 0x0651, + /* 4162 */ 0x0640, 0x0650, 0x0651, + /* 4165 */ 0x0637, 0x0649, + /* 4167 */ 0x0637, 0x064A, + /* 4169 */ 0x0639, 0x0649, + /* 4171 */ 0x0639, 0x064A, + /* 4173 */ 0x063A, 0x0649, + /* 4175 */ 0x063A, 0x064A, + /* 4177 */ 0x0633, 0x0649, + /* 4179 */ 0x0633, 0x064A, + /* 4181 */ 0x0634, 0x0649, + /* 4183 */ 0x0634, 0x064A, + /* 4185 */ 0x062D, 0x0649, + /* 4187 */ 0x062D, 0x064A, + /* 4189 */ 0x062C, 0x0649, + /* 4191 */ 0x062C, 0x064A, + /* 4193 */ 0x062E, 0x0649, + /* 4195 */ 0x062E, 0x064A, + /* 4197 */ 0x0635, 0x0649, + /* 4199 */ 0x0635, 0x064A, + /* 4201 */ 0x0636, 0x0649, + /* 4203 */ 0x0636, 0x064A, + /* 4205 */ 0x0634, 0x062C, + /* 4207 */ 0x0634, 0x062D, + /* 4209 */ 0x0634, 0x062E, + /* 4211 */ 0x0634, 0x0645, + /* 4213 */ 0x0634, 0x0631, + /* 4215 */ 0x0633, 0x0631, + /* 4217 */ 0x0635, 0x0631, + /* 4219 */ 0x0636, 0x0631, + /* 4221 */ 0x0637, 0x0649, + /* 4223 */ 0x0637, 0x064A, + /* 4225 */ 0x0639, 0x0649, + /* 4227 */ 0x0639, 0x064A, + /* 4229 */ 0x063A, 0x0649, + /* 4231 */ 0x063A, 0x064A, + /* 4233 */ 0x0633, 0x0649, + /* 4235 */ 0x0633, 0x064A, + /* 4237 */ 0x0634, 0x0649, + /* 4239 */ 0x0634, 0x064A, + /* 4241 */ 0x062D, 0x0649, + /* 4243 */ 0x062D, 0x064A, + /* 4245 */ 0x062C, 0x0649, + /* 4247 */ 0x062C, 0x064A, + /* 4249 */ 0x062E, 0x0649, + /* 4251 */ 0x062E, 0x064A, + /* 4253 */ 0x0635, 0x0649, + /* 4255 */ 0x0635, 0x064A, + /* 4257 */ 0x0636, 0x0649, + /* 4259 */ 0x0636, 0x064A, + /* 4261 */ 0x0634, 0x062C, + /* 4263 */ 0x0634, 0x062D, + /* 4265 */ 0x0634, 0x062E, + /* 4267 */ 0x0634, 0x0645, + /* 4269 */ 0x0634, 0x0631, + /* 4271 */ 0x0633, 0x0631, + /* 4273 */ 0x0635, 0x0631, + /* 4275 */ 0x0636, 0x0631, + /* 4277 */ 0x0634, 0x062C, + /* 4279 */ 0x0634, 0x062D, + /* 4281 */ 0x0634, 0x062E, + /* 4283 */ 0x0634, 0x0645, + /* 4285 */ 0x0633, 0x0647, + /* 4287 */ 0x0634, 0x0647, + /* 4289 */ 0x0637, 0x0645, + /* 4291 */ 0x0633, 0x062C, + /* 4293 */ 0x0633, 0x062D, + /* 4295 */ 0x0633, 0x062E, + /* 4297 */ 0x0634, 0x062C, + /* 4299 */ 0x0634, 0x062D, + /* 4301 */ 0x0634, 0x062E, + /* 4303 */ 0x0637, 0x0645, + /* 4305 */ 0x0638, 0x0645, + /* 4307 */ 0x0627, 0x064B, + /* 4309 */ 0x0627, 0x064B, + /* 4311 */ 0x062A, 0x062C, 0x0645, + /* 4314 */ 0x062A, 0x062D, 0x062C, + /* 4317 */ 0x062A, 0x062D, 0x062C, + /* 4320 */ 0x062A, 0x062D, 0x0645, + /* 4323 */ 0x062A, 0x062E, 0x0645, + /* 4326 */ 0x062A, 0x0645, 0x062C, + /* 4329 */ 0x062A, 0x0645, 0x062D, + /* 4332 */ 0x062A, 0x0645, 0x062E, + /* 4335 */ 0x062C, 0x0645, 0x062D, + /* 4338 */ 0x062C, 0x0645, 0x062D, + /* 4341 */ 0x062D, 0x0645, 0x064A, + /* 4344 */ 0x062D, 0x0645, 0x0649, + /* 4347 */ 0x0633, 0x062D, 0x062C, + /* 4350 */ 0x0633, 0x062C, 0x062D, + /* 4353 */ 0x0633, 0x062C, 0x0649, + /* 4356 */ 0x0633, 0x0645, 0x062D, + /* 4359 */ 0x0633, 0x0645, 0x062D, + /* 4362 */ 0x0633, 0x0645, 0x062C, + /* 4365 */ 0x0633, 0x0645, 0x0645, + /* 4368 */ 0x0633, 0x0645, 0x0645, + /* 4371 */ 0x0635, 0x062D, 0x062D, + /* 4374 */ 0x0635, 0x062D, 0x062D, + /* 4377 */ 0x0635, 0x0645, 0x0645, + /* 4380 */ 0x0634, 0x062D, 0x0645, + /* 4383 */ 0x0634, 0x062D, 0x0645, + /* 4386 */ 0x0634, 0x062C, 0x064A, + /* 4389 */ 0x0634, 0x0645, 0x062E, + /* 4392 */ 0x0634, 0x0645, 0x062E, + /* 4395 */ 0x0634, 0x0645, 0x0645, + /* 4398 */ 0x0634, 0x0645, 0x0645, + /* 4401 */ 0x0636, 0x062D, 0x0649, + /* 4404 */ 0x0636, 0x062E, 0x0645, + /* 4407 */ 0x0636, 0x062E, 0x0645, + /* 4410 */ 0x0637, 0x0645, 0x062D, + /* 4413 */ 0x0637, 0x0645, 0x062D, + /* 4416 */ 0x0637, 0x0645, 0x0645, + /* 4419 */ 0x0637, 0x0645, 0x064A, + /* 4422 */ 0x0639, 0x062C, 0x0645, + /* 4425 */ 0x0639, 0x0645, 0x0645, + /* 4428 */ 0x0639, 0x0645, 0x0645, + /* 4431 */ 0x0639, 0x0645, 0x0649, + /* 4434 */ 0x063A, 0x0645, 0x0645, + /* 4437 */ 0x063A, 0x0645, 0x064A, + /* 4440 */ 0x063A, 0x0645, 0x0649, + /* 4443 */ 0x0641, 0x062E, 0x0645, + /* 4446 */ 0x0641, 0x062E, 0x0645, + /* 4449 */ 0x0642, 0x0645, 0x062D, + /* 4452 */ 0x0642, 0x0645, 0x0645, + /* 4455 */ 0x0644, 0x062D, 0x0645, + /* 4458 */ 0x0644, 0x062D, 0x064A, + /* 4461 */ 0x0644, 0x062D, 0x0649, + /* 4464 */ 0x0644, 0x062C, 0x062C, + /* 4467 */ 0x0644, 0x062C, 0x062C, + /* 4470 */ 0x0644, 0x062E, 0x0645, + /* 4473 */ 0x0644, 0x062E, 0x0645, + /* 4476 */ 0x0644, 0x0645, 0x062D, + /* 4479 */ 0x0644, 0x0645, 0x062D, + /* 4482 */ 0x0645, 0x062D, 0x062C, + /* 4485 */ 0x0645, 0x062D, 0x0645, + /* 4488 */ 0x0645, 0x062D, 0x064A, + /* 4491 */ 0x0645, 0x062C, 0x062D, + /* 4494 */ 0x0645, 0x062C, 0x0645, + /* 4497 */ 0x0645, 0x062E, 0x062C, + /* 4500 */ 0x0645, 0x062E, 0x0645, + /* 4503 */ 0x0645, 0x062C, 0x062E, + /* 4506 */ 0x0647, 0x0645, 0x062C, + /* 4509 */ 0x0647, 0x0645, 0x0645, + /* 4512 */ 0x0646, 0x062D, 0x0645, + /* 4515 */ 0x0646, 0x062D, 0x0649, + /* 4518 */ 0x0646, 0x062C, 0x0645, + /* 4521 */ 0x0646, 0x062C, 0x0645, + /* 4524 */ 0x0646, 0x062C, 0x0649, + /* 4527 */ 0x0646, 0x0645, 0x064A, + /* 4530 */ 0x0646, 0x0645, 0x0649, + /* 4533 */ 0x064A, 0x0645, 0x0645, + /* 4536 */ 0x064A, 0x0645, 0x0645, + /* 4539 */ 0x0628, 0x062E, 0x064A, + /* 4542 */ 0x062A, 0x062C, 0x064A, + /* 4545 */ 0x062A, 0x062C, 0x0649, + /* 4548 */ 0x062A, 0x062E, 0x064A, + /* 4551 */ 0x062A, 0x062E, 0x0649, + /* 4554 */ 0x062A, 0x0645, 0x064A, + /* 4557 */ 0x062A, 0x0645, 0x0649, + /* 4560 */ 0x062C, 0x0645, 0x064A, + /* 4563 */ 0x062C, 0x062D, 0x0649, + /* 4566 */ 0x062C, 0x0645, 0x0649, + /* 4569 */ 0x0633, 0x062E, 0x0649, + /* 4572 */ 0x0635, 0x062D, 0x064A, + /* 4575 */ 0x0634, 0x062D, 0x064A, + /* 4578 */ 0x0636, 0x062D, 0x064A, + /* 4581 */ 0x0644, 0x062C, 0x064A, + /* 4584 */ 0x0644, 0x0645, 0x064A, + /* 4587 */ 0x064A, 0x062D, 0x064A, + /* 4590 */ 0x064A, 0x062C, 0x064A, + /* 4593 */ 0x064A, 0x0645, 0x064A, + /* 4596 */ 0x0645, 0x0645, 0x064A, + /* 4599 */ 0x0642, 0x0645, 0x064A, + /* 4602 */ 0x0646, 0x062D, 0x064A, + /* 4605 */ 0x0642, 0x0645, 0x062D, + /* 4608 */ 0x0644, 0x062D, 0x0645, + /* 4611 */ 0x0639, 0x0645, 0x064A, + /* 4614 */ 0x0643, 0x0645, 0x064A, + /* 4617 */ 0x0646, 0x062C, 0x062D, + /* 4620 */ 0x0645, 0x062E, 0x064A, + /* 4623 */ 0x0644, 0x062C, 0x0645, + /* 4626 */ 0x0643, 0x0645, 0x0645, + /* 4629 */ 0x0644, 0x062C, 0x0645, + /* 4632 */ 0x0646, 0x062C, 0x062D, + /* 4635 */ 0x062C, 0x062D, 0x064A, + /* 4638 */ 0x062D, 0x062C, 0x064A, + /* 4641 */ 0x0645, 0x062C, 0x064A, + /* 4644 */ 0x0641, 0x0645, 0x064A, + /* 4647 */ 0x0628, 0x062D, 0x064A, + /* 4650 */ 0x0643, 0x0645, 0x0645, + /* 4653 */ 0x0639, 0x062C, 0x0645, + /* 4656 */ 0x0635, 0x0645, 0x0645, + /* 4659 */ 0x0633, 0x062E, 0x064A, + /* 4662 */ 0x0646, 0x062C, 0x064A, + /* 4665 */ 0x0635, 0x0644, 0x06D2, + /* 4668 */ 0x0642, 0x0644, 0x06D2, + /* 4671 */ 0x0627, 0x0644, 0x0644, 0x0647, + /* 4675 */ 0x0627, 0x0643, 0x0628, 0x0631, + /* 4679 */ 0x0645, 0x062D, 0x0645, 0x062F, + /* 4683 */ 0x0635, 0x0644, 0x0639, 0x0645, + /* 4687 */ 0x0631, 0x0633, 0x0648, 0x0644, + /* 4691 */ 0x0639, 0x0644, 0x064A, 0x0647, + /* 4695 */ 0x0648, 0x0633, 0x0644, 0x0645, + /* 4699 */ 0x0635, 0x0644, 0x0649, + /* 4702 */ 0x0635, 0x0644, 0x0649, 0x0020, 0x0627, 0x0644, 0x0644, 0x0647, 0x0020, 0x0639, 0x0644, 0x064A, 0x0647, 0x0020, 0x0648, 0x0633, 0x0644, 0x0645, + /* 4720 */ 0x062C, 0x0644, 0x0020, 0x062C, 0x0644, 0x0627, 0x0644, 0x0647, + /* 4728 */ 0x0631, 0x06CC, 0x0627, 0x0644, + /* 4732 */ 0x0020, 0x064B, + /* 4734 */ 0x0640, 0x064B, + /* 4736 */ 0x0020, 0x064C, + /* 4738 */ 0x0020, 0x064D, + /* 4740 */ 0x0020, 0x064E, + /* 4742 */ 0x0640, 0x064E, + /* 4744 */ 0x0020, 0x064F, + /* 4746 */ 0x0640, 0x064F, + /* 4748 */ 0x0020, 0x0650, + /* 4750 */ 0x0640, 0x0650, + /* 4752 */ 0x0020, 0x0651, + /* 4754 */ 0x0640, 0x0651, + /* 4756 */ 0x0020, 0x0652, + /* 4758 */ 0x0640, 0x0652, + /* 4760 */ 0x0644, 0x0622, + /* 4762 */ 0x0644, 0x0622, + /* 4764 */ 0x0644, 0x0623, + /* 4766 */ 0x0644, 0x0623, + /* 4768 */ 0x0644, 0x0625, + /* 4770 */ 0x0644, 0x0625, + /* 4772 */ 0x0644, 0x0627, + /* 4774 */ 0x0644, 0x0627, + /* 4776 */ 0x1DF04, + /* 4777 */ 0x1DF05, + /* 4778 */ 0x1DF06, + /* 4779 */ 0x1DF08, + /* 4780 */ 0x1DF0A, + /* 4781 */ 0x1DF1E, + /* 4782 */ 0x11099, 0x110BA, + /* 4784 */ 0x1109B, 0x110BA, + /* 4786 */ 0x110A5, 0x110BA, + /* 4788 */ 0x11131, 0x11127, + /* 4790 */ 0x11132, 0x11127, + /* 4792 */ 0x11347, 0x1133E, + /* 4794 */ 0x11347, 0x11357, + /* 4796 */ 0x114B9, 0x114BA, + /* 4798 */ 0x114B9, 0x114B0, + /* 4800 */ 0x114B9, 0x114BD, + /* 4802 */ 0x115B8, 0x115AF, + /* 4804 */ 0x115B9, 0x115AF, + /* 4806 */ 0x11935, 0x11930, + /* 4808 */ 0x1D157, 0x1D165, + /* 4810 */ 0x1D158, 0x1D165, + /* 4812 */ 0x1D15F, 0x1D16E, + /* 4814 */ 0x1D15F, 0x1D16F, + /* 4816 */ 0x1D15F, 0x1D170, + /* 4818 */ 0x1D15F, 0x1D171, + /* 4820 */ 0x1D15F, 0x1D172, + /* 4822 */ 0x1D1B9, 0x1D165, + /* 4824 */ 0x1D1BA, 0x1D165, + /* 4826 */ 0x1D1BB, 0x1D16E, + /* 4828 */ 0x1D1BC, 0x1D16E, + /* 4830 */ 0x1D1BB, 0x1D16F, + /* 4832 */ 0x1D1BC, 0x1D16F, + /* 4834 */ 0x0030, 0x002E, + /* 4836 */ 0x0030, 0x002C, + /* 4838 */ 0x0031, 0x002C, + /* 4840 */ 0x0032, 0x002C, + /* 4842 */ 0x0033, 0x002C, + /* 4844 */ 0x0034, 0x002C, + /* 4846 */ 0x0035, 0x002C, + /* 4848 */ 0x0036, 0x002C, + /* 4850 */ 0x0037, 0x002C, + /* 4852 */ 0x0038, 0x002C, + /* 4854 */ 0x0039, 0x002C, + /* 4856 */ 0x0028, 0x0041, 0x0029, + /* 4859 */ 0x0028, 0x0042, 0x0029, + /* 4862 */ 0x0028, 0x0043, 0x0029, + /* 4865 */ 0x0028, 0x0044, 0x0029, + /* 4868 */ 0x0028, 0x0045, 0x0029, + /* 4871 */ 0x0028, 0x0046, 0x0029, + /* 4874 */ 0x0028, 0x0047, 0x0029, + /* 4877 */ 0x0028, 0x0048, 0x0029, + /* 4880 */ 0x0028, 0x0049, 0x0029, + /* 4883 */ 0x0028, 0x004A, 0x0029, + /* 4886 */ 0x0028, 0x004B, 0x0029, + /* 4889 */ 0x0028, 0x004C, 0x0029, + /* 4892 */ 0x0028, 0x004D, 0x0029, + /* 4895 */ 0x0028, 0x004E, 0x0029, + /* 4898 */ 0x0028, 0x004F, 0x0029, + /* 4901 */ 0x0028, 0x0050, 0x0029, + /* 4904 */ 0x0028, 0x0051, 0x0029, + /* 4907 */ 0x0028, 0x0052, 0x0029, + /* 4910 */ 0x0028, 0x0053, 0x0029, + /* 4913 */ 0x0028, 0x0054, 0x0029, + /* 4916 */ 0x0028, 0x0055, 0x0029, + /* 4919 */ 0x0028, 0x0056, 0x0029, + /* 4922 */ 0x0028, 0x0057, 0x0029, + /* 4925 */ 0x0028, 0x0058, 0x0029, + /* 4928 */ 0x0028, 0x0059, 0x0029, + /* 4931 */ 0x0028, 0x005A, 0x0029, + /* 4934 */ 0x3014, 0x0053, 0x3015, + /* 4937 */ 0x0043, 0x0044, + /* 4939 */ 0x0057, 0x005A, + /* 4941 */ 0x0048, 0x0056, + /* 4943 */ 0x004D, 0x0056, + /* 4945 */ 0x0053, 0x0044, + /* 4947 */ 0x0053, 0x0053, + /* 4949 */ 0x0050, 0x0050, 0x0056, + /* 4952 */ 0x0057, 0x0043, + /* 4954 */ 0x004D, 0x0043, + /* 4956 */ 0x004D, 0x0044, + /* 4958 */ 0x004D, 0x0052, + /* 4960 */ 0x0044, 0x004A, + /* 4962 */ 0x307B, 0x304B, + /* 4964 */ 0x30B3, 0x30B3, + /* 4966 */ 0x3014, 0x672C, 0x3015, + /* 4969 */ 0x3014, 0x4E09, 0x3015, + /* 4972 */ 0x3014, 0x4E8C, 0x3015, + /* 4975 */ 0x3014, 0x5B89, 0x3015, + /* 4978 */ 0x3014, 0x70B9, 0x3015, + /* 4981 */ 0x3014, 0x6253, 0x3015, + /* 4984 */ 0x3014, 0x76D7, 0x3015, + /* 4987 */ 0x3014, 0x52DD, 0x3015, + /* 4990 */ 0x3014, 0x6557, 0x3015, + /* 4993 */ 0x20122, + /* 4994 */ 0x2063A, + /* 4995 */ 0x2051C, + /* 4996 */ 0x2054B, + /* 4997 */ 0x291DF, + /* 4998 */ 0x20A2C, + /* 4999 */ 0x20B63, + /* 5000 */ 0x214E4, + /* 5001 */ 0x216A8, + /* 5002 */ 0x216EA, + /* 5003 */ 0x219C8, + /* 5004 */ 0x21B18, + /* 5005 */ 0x21DE4, + /* 5006 */ 0x21DE6, + /* 5007 */ 0x22183, + /* 5008 */ 0x2A392, + /* 5009 */ 0x22331, + /* 5010 */ 0x22331, + /* 5011 */ 0x232B8, + /* 5012 */ 0x261DA, + /* 5013 */ 0x226D4, + /* 5014 */ 0x22B0C, + /* 5015 */ 0x22BF1, + /* 5016 */ 0x2300A, + /* 5017 */ 0x233C3, + /* 5018 */ 0x2346D, + /* 5019 */ 0x236A3, + /* 5020 */ 0x238A7, + /* 5021 */ 0x23A8D, + /* 5022 */ 0x21D0B, + /* 5023 */ 0x23AFA, + /* 5024 */ 0x23CBC, + /* 5025 */ 0x23D1E, + /* 5026 */ 0x23ED1, + /* 5027 */ 0x23F5E, + /* 5028 */ 0x23F8E, + /* 5029 */ 0x20525, + /* 5030 */ 0x24263, + /* 5031 */ 0x243AB, + /* 5032 */ 0x24608, + /* 5033 */ 0x24735, + /* 5034 */ 0x24814, + /* 5035 */ 0x24C36, + /* 5036 */ 0x24C92, + /* 5037 */ 0x2219F, + /* 5038 */ 0x24FA1, + /* 5039 */ 0x24FB8, + /* 5040 */ 0x25044, + /* 5041 */ 0x250F3, + /* 5042 */ 0x250F2, + /* 5043 */ 0x25119, + /* 5044 */ 0x25133, + /* 5045 */ 0x2541D, + /* 5046 */ 0x25626, + /* 5047 */ 0x2569A, + /* 5048 */ 0x256C5, + /* 5049 */ 0x2597C, + /* 5050 */ 0x25AA7, + /* 5051 */ 0x25AA7, + /* 5052 */ 0x25BAB, + /* 5053 */ 0x25C80, + /* 5054 */ 0x25F86, + /* 5055 */ 0x26228, + /* 5056 */ 0x26247, + /* 5057 */ 0x262D9, + /* 5058 */ 0x2633E, + /* 5059 */ 0x264DA, + /* 5060 */ 0x26523, + /* 5061 */ 0x265A8, + /* 5062 */ 0x2335F, + /* 5063 */ 0x267A7, + /* 5064 */ 0x267B5, + /* 5065 */ 0x23393, + /* 5066 */ 0x2339C, + /* 5067 */ 0x26B3C, + /* 5068 */ 0x26C36, + /* 5069 */ 0x26D6B, + /* 5070 */ 0x26CD5, + /* 5071 */ 0x273CA, + /* 5072 */ 0x26F2C, + /* 5073 */ 0x26FB1, + /* 5074 */ 0x270D2, + /* 5075 */ 0x27667, + /* 5076 */ 0x278AE, + /* 5077 */ 0x27966, + /* 5078 */ 0x27CA8, + /* 5079 */ 0x27F2F, + /* 5080 */ 0x20804, + /* 5081 */ 0x208DE, + /* 5082 */ 0x285D2, + /* 5083 */ 0x285ED, + /* 5084 */ 0x2872E, + /* 5085 */ 0x28BFA, + /* 5086 */ 0x28D77, + /* 5087 */ 0x29145, + /* 5088 */ 0x2921A, + /* 5089 */ 0x2940A, + /* 5090 */ 0x29496, + /* 5091 */ 0x295B6, + /* 5092 */ 0x29B30, + /* 5093 */ 0x2A0CE, + /* 5094 */ 0x2A105, + /* 5095 */ 0x2A20E, + /* 5096 */ 0x2A291, + /* 5097 */ 0x2A600 +}; diff --git a/src/include/common/unicode_normprops_table.h b/src/include/common/unicode_normprops_table.h new file mode 100644 index 0000000..2b421cb --- /dev/null +++ b/src/include/common/unicode_normprops_table.h @@ -0,0 +1,7849 @@ +/* generated by src/common/unicode/generate-unicode_normprops_table.pl, do not edit */ + +#include "common/unicode_norm.h" + +/* + * Normalization quick check entry for codepoint. We use a bit field + * here to save space. + */ +typedef struct +{ + unsigned int codepoint:21; + signed int quickcheck:4; /* really UnicodeNormalizationQC */ +} pg_unicode_normprops; + +/* Typedef for hash function on quick check table */ +typedef int (*qc_hash_func) (const void *key); + +/* Information for quick check lookup with perfect hash function */ +typedef struct +{ + const pg_unicode_normprops *normprops; + qc_hash_func hash; + int num_normprops; +} pg_unicode_norminfo; + +static const pg_unicode_normprops UnicodeNormProps_NFC_QC[] = { + {0x0300, UNICODE_NORM_QC_MAYBE}, + {0x0301, UNICODE_NORM_QC_MAYBE}, + {0x0302, UNICODE_NORM_QC_MAYBE}, + {0x0303, UNICODE_NORM_QC_MAYBE}, + {0x0304, UNICODE_NORM_QC_MAYBE}, + {0x0306, UNICODE_NORM_QC_MAYBE}, + {0x0307, UNICODE_NORM_QC_MAYBE}, + {0x0308, UNICODE_NORM_QC_MAYBE}, + {0x0309, UNICODE_NORM_QC_MAYBE}, + {0x030A, UNICODE_NORM_QC_MAYBE}, + {0x030B, UNICODE_NORM_QC_MAYBE}, + {0x030C, UNICODE_NORM_QC_MAYBE}, + {0x030F, UNICODE_NORM_QC_MAYBE}, + {0x0311, UNICODE_NORM_QC_MAYBE}, + {0x0313, UNICODE_NORM_QC_MAYBE}, + {0x0314, UNICODE_NORM_QC_MAYBE}, + {0x031B, UNICODE_NORM_QC_MAYBE}, + {0x0323, UNICODE_NORM_QC_MAYBE}, + {0x0324, UNICODE_NORM_QC_MAYBE}, + {0x0325, UNICODE_NORM_QC_MAYBE}, + {0x0326, UNICODE_NORM_QC_MAYBE}, + {0x0327, UNICODE_NORM_QC_MAYBE}, + {0x0328, UNICODE_NORM_QC_MAYBE}, + {0x032D, UNICODE_NORM_QC_MAYBE}, + {0x032E, UNICODE_NORM_QC_MAYBE}, + {0x0330, UNICODE_NORM_QC_MAYBE}, + {0x0331, UNICODE_NORM_QC_MAYBE}, + {0x0338, UNICODE_NORM_QC_MAYBE}, + {0x0340, UNICODE_NORM_QC_NO}, + {0x0341, UNICODE_NORM_QC_NO}, + {0x0342, UNICODE_NORM_QC_MAYBE}, + {0x0343, UNICODE_NORM_QC_NO}, + {0x0344, UNICODE_NORM_QC_NO}, + {0x0345, UNICODE_NORM_QC_MAYBE}, + {0x0374, UNICODE_NORM_QC_NO}, + {0x037E, UNICODE_NORM_QC_NO}, + {0x0387, UNICODE_NORM_QC_NO}, + {0x0653, UNICODE_NORM_QC_MAYBE}, + {0x0654, UNICODE_NORM_QC_MAYBE}, + {0x0655, UNICODE_NORM_QC_MAYBE}, + {0x093C, UNICODE_NORM_QC_MAYBE}, + {0x0958, UNICODE_NORM_QC_NO}, + {0x0959, UNICODE_NORM_QC_NO}, + {0x095A, UNICODE_NORM_QC_NO}, + {0x095B, UNICODE_NORM_QC_NO}, + {0x095C, UNICODE_NORM_QC_NO}, + {0x095D, UNICODE_NORM_QC_NO}, + {0x095E, UNICODE_NORM_QC_NO}, + {0x095F, UNICODE_NORM_QC_NO}, + {0x09BE, UNICODE_NORM_QC_MAYBE}, + {0x09D7, UNICODE_NORM_QC_MAYBE}, + {0x09DC, UNICODE_NORM_QC_NO}, + {0x09DD, UNICODE_NORM_QC_NO}, + {0x09DF, UNICODE_NORM_QC_NO}, + {0x0A33, UNICODE_NORM_QC_NO}, + {0x0A36, UNICODE_NORM_QC_NO}, + {0x0A59, UNICODE_NORM_QC_NO}, + {0x0A5A, UNICODE_NORM_QC_NO}, + {0x0A5B, UNICODE_NORM_QC_NO}, + {0x0A5E, UNICODE_NORM_QC_NO}, + {0x0B3E, UNICODE_NORM_QC_MAYBE}, + {0x0B56, UNICODE_NORM_QC_MAYBE}, + {0x0B57, UNICODE_NORM_QC_MAYBE}, + {0x0B5C, UNICODE_NORM_QC_NO}, + {0x0B5D, UNICODE_NORM_QC_NO}, + {0x0BBE, UNICODE_NORM_QC_MAYBE}, + {0x0BD7, UNICODE_NORM_QC_MAYBE}, + {0x0C56, UNICODE_NORM_QC_MAYBE}, + {0x0CC2, UNICODE_NORM_QC_MAYBE}, + {0x0CD5, UNICODE_NORM_QC_MAYBE}, + {0x0CD6, UNICODE_NORM_QC_MAYBE}, + {0x0D3E, UNICODE_NORM_QC_MAYBE}, + {0x0D57, UNICODE_NORM_QC_MAYBE}, + {0x0DCA, UNICODE_NORM_QC_MAYBE}, + {0x0DCF, UNICODE_NORM_QC_MAYBE}, + {0x0DDF, UNICODE_NORM_QC_MAYBE}, + {0x0F43, UNICODE_NORM_QC_NO}, + {0x0F4D, UNICODE_NORM_QC_NO}, + {0x0F52, UNICODE_NORM_QC_NO}, + {0x0F57, UNICODE_NORM_QC_NO}, + {0x0F5C, UNICODE_NORM_QC_NO}, + {0x0F69, UNICODE_NORM_QC_NO}, + {0x0F73, UNICODE_NORM_QC_NO}, + {0x0F75, UNICODE_NORM_QC_NO}, + {0x0F76, UNICODE_NORM_QC_NO}, + {0x0F78, UNICODE_NORM_QC_NO}, + {0x0F81, UNICODE_NORM_QC_NO}, + {0x0F93, UNICODE_NORM_QC_NO}, + {0x0F9D, UNICODE_NORM_QC_NO}, + {0x0FA2, UNICODE_NORM_QC_NO}, + {0x0FA7, UNICODE_NORM_QC_NO}, + {0x0FAC, UNICODE_NORM_QC_NO}, + {0x0FB9, UNICODE_NORM_QC_NO}, + {0x102E, UNICODE_NORM_QC_MAYBE}, + {0x1161, UNICODE_NORM_QC_MAYBE}, + {0x1162, UNICODE_NORM_QC_MAYBE}, + {0x1163, UNICODE_NORM_QC_MAYBE}, + {0x1164, UNICODE_NORM_QC_MAYBE}, + {0x1165, UNICODE_NORM_QC_MAYBE}, + {0x1166, UNICODE_NORM_QC_MAYBE}, + {0x1167, UNICODE_NORM_QC_MAYBE}, + {0x1168, UNICODE_NORM_QC_MAYBE}, + {0x1169, UNICODE_NORM_QC_MAYBE}, + {0x116A, UNICODE_NORM_QC_MAYBE}, + {0x116B, UNICODE_NORM_QC_MAYBE}, + {0x116C, UNICODE_NORM_QC_MAYBE}, + {0x116D, UNICODE_NORM_QC_MAYBE}, + {0x116E, UNICODE_NORM_QC_MAYBE}, + {0x116F, UNICODE_NORM_QC_MAYBE}, + {0x1170, UNICODE_NORM_QC_MAYBE}, + {0x1171, UNICODE_NORM_QC_MAYBE}, + {0x1172, UNICODE_NORM_QC_MAYBE}, + {0x1173, UNICODE_NORM_QC_MAYBE}, + {0x1174, UNICODE_NORM_QC_MAYBE}, + {0x1175, UNICODE_NORM_QC_MAYBE}, + {0x11A8, UNICODE_NORM_QC_MAYBE}, + {0x11A9, UNICODE_NORM_QC_MAYBE}, + {0x11AA, UNICODE_NORM_QC_MAYBE}, + {0x11AB, UNICODE_NORM_QC_MAYBE}, + {0x11AC, UNICODE_NORM_QC_MAYBE}, + {0x11AD, UNICODE_NORM_QC_MAYBE}, + {0x11AE, UNICODE_NORM_QC_MAYBE}, + {0x11AF, UNICODE_NORM_QC_MAYBE}, + {0x11B0, UNICODE_NORM_QC_MAYBE}, + {0x11B1, UNICODE_NORM_QC_MAYBE}, + {0x11B2, UNICODE_NORM_QC_MAYBE}, + {0x11B3, UNICODE_NORM_QC_MAYBE}, + {0x11B4, UNICODE_NORM_QC_MAYBE}, + {0x11B5, UNICODE_NORM_QC_MAYBE}, + {0x11B6, UNICODE_NORM_QC_MAYBE}, + {0x11B7, UNICODE_NORM_QC_MAYBE}, + {0x11B8, UNICODE_NORM_QC_MAYBE}, + {0x11B9, UNICODE_NORM_QC_MAYBE}, + {0x11BA, UNICODE_NORM_QC_MAYBE}, + {0x11BB, UNICODE_NORM_QC_MAYBE}, + {0x11BC, UNICODE_NORM_QC_MAYBE}, + {0x11BD, UNICODE_NORM_QC_MAYBE}, + {0x11BE, UNICODE_NORM_QC_MAYBE}, + {0x11BF, UNICODE_NORM_QC_MAYBE}, + {0x11C0, UNICODE_NORM_QC_MAYBE}, + {0x11C1, UNICODE_NORM_QC_MAYBE}, + {0x11C2, UNICODE_NORM_QC_MAYBE}, + {0x1B35, UNICODE_NORM_QC_MAYBE}, + {0x1F71, UNICODE_NORM_QC_NO}, + {0x1F73, UNICODE_NORM_QC_NO}, + {0x1F75, UNICODE_NORM_QC_NO}, + {0x1F77, UNICODE_NORM_QC_NO}, + {0x1F79, UNICODE_NORM_QC_NO}, + {0x1F7B, UNICODE_NORM_QC_NO}, + {0x1F7D, UNICODE_NORM_QC_NO}, + {0x1FBB, UNICODE_NORM_QC_NO}, + {0x1FBE, UNICODE_NORM_QC_NO}, + {0x1FC9, UNICODE_NORM_QC_NO}, + {0x1FCB, UNICODE_NORM_QC_NO}, + {0x1FD3, UNICODE_NORM_QC_NO}, + {0x1FDB, UNICODE_NORM_QC_NO}, + {0x1FE3, UNICODE_NORM_QC_NO}, + {0x1FEB, UNICODE_NORM_QC_NO}, + {0x1FEE, UNICODE_NORM_QC_NO}, + {0x1FEF, UNICODE_NORM_QC_NO}, + {0x1FF9, UNICODE_NORM_QC_NO}, + {0x1FFB, UNICODE_NORM_QC_NO}, + {0x1FFD, UNICODE_NORM_QC_NO}, + {0x2000, UNICODE_NORM_QC_NO}, + {0x2001, UNICODE_NORM_QC_NO}, + {0x2126, UNICODE_NORM_QC_NO}, + {0x212A, UNICODE_NORM_QC_NO}, + {0x212B, UNICODE_NORM_QC_NO}, + {0x2329, UNICODE_NORM_QC_NO}, + {0x232A, UNICODE_NORM_QC_NO}, + {0x2ADC, UNICODE_NORM_QC_NO}, + {0x3099, UNICODE_NORM_QC_MAYBE}, + {0x309A, UNICODE_NORM_QC_MAYBE}, + {0xF900, UNICODE_NORM_QC_NO}, + {0xF901, UNICODE_NORM_QC_NO}, + {0xF902, UNICODE_NORM_QC_NO}, + {0xF903, UNICODE_NORM_QC_NO}, + {0xF904, UNICODE_NORM_QC_NO}, + {0xF905, UNICODE_NORM_QC_NO}, + {0xF906, UNICODE_NORM_QC_NO}, + {0xF907, UNICODE_NORM_QC_NO}, + {0xF908, UNICODE_NORM_QC_NO}, + {0xF909, UNICODE_NORM_QC_NO}, + {0xF90A, UNICODE_NORM_QC_NO}, + {0xF90B, UNICODE_NORM_QC_NO}, + {0xF90C, UNICODE_NORM_QC_NO}, + {0xF90D, UNICODE_NORM_QC_NO}, + {0xF90E, UNICODE_NORM_QC_NO}, + {0xF90F, UNICODE_NORM_QC_NO}, + {0xF910, UNICODE_NORM_QC_NO}, + {0xF911, UNICODE_NORM_QC_NO}, + {0xF912, UNICODE_NORM_QC_NO}, + {0xF913, UNICODE_NORM_QC_NO}, + {0xF914, UNICODE_NORM_QC_NO}, + {0xF915, UNICODE_NORM_QC_NO}, + {0xF916, UNICODE_NORM_QC_NO}, + {0xF917, UNICODE_NORM_QC_NO}, + {0xF918, UNICODE_NORM_QC_NO}, + {0xF919, UNICODE_NORM_QC_NO}, + {0xF91A, UNICODE_NORM_QC_NO}, + {0xF91B, UNICODE_NORM_QC_NO}, + {0xF91C, UNICODE_NORM_QC_NO}, + {0xF91D, UNICODE_NORM_QC_NO}, + {0xF91E, UNICODE_NORM_QC_NO}, + {0xF91F, UNICODE_NORM_QC_NO}, + {0xF920, UNICODE_NORM_QC_NO}, + {0xF921, UNICODE_NORM_QC_NO}, + {0xF922, UNICODE_NORM_QC_NO}, + {0xF923, UNICODE_NORM_QC_NO}, + {0xF924, UNICODE_NORM_QC_NO}, + {0xF925, UNICODE_NORM_QC_NO}, + {0xF926, UNICODE_NORM_QC_NO}, + {0xF927, UNICODE_NORM_QC_NO}, + {0xF928, UNICODE_NORM_QC_NO}, + {0xF929, UNICODE_NORM_QC_NO}, + {0xF92A, UNICODE_NORM_QC_NO}, + {0xF92B, UNICODE_NORM_QC_NO}, + {0xF92C, UNICODE_NORM_QC_NO}, + {0xF92D, UNICODE_NORM_QC_NO}, + {0xF92E, UNICODE_NORM_QC_NO}, + {0xF92F, UNICODE_NORM_QC_NO}, + {0xF930, UNICODE_NORM_QC_NO}, + {0xF931, UNICODE_NORM_QC_NO}, + {0xF932, UNICODE_NORM_QC_NO}, + {0xF933, UNICODE_NORM_QC_NO}, + {0xF934, UNICODE_NORM_QC_NO}, + {0xF935, UNICODE_NORM_QC_NO}, + {0xF936, UNICODE_NORM_QC_NO}, + {0xF937, UNICODE_NORM_QC_NO}, + {0xF938, UNICODE_NORM_QC_NO}, + {0xF939, UNICODE_NORM_QC_NO}, + {0xF93A, UNICODE_NORM_QC_NO}, + {0xF93B, UNICODE_NORM_QC_NO}, + {0xF93C, UNICODE_NORM_QC_NO}, + {0xF93D, UNICODE_NORM_QC_NO}, + {0xF93E, UNICODE_NORM_QC_NO}, + {0xF93F, UNICODE_NORM_QC_NO}, + {0xF940, UNICODE_NORM_QC_NO}, + {0xF941, UNICODE_NORM_QC_NO}, + {0xF942, UNICODE_NORM_QC_NO}, + {0xF943, UNICODE_NORM_QC_NO}, + {0xF944, UNICODE_NORM_QC_NO}, + {0xF945, UNICODE_NORM_QC_NO}, + {0xF946, UNICODE_NORM_QC_NO}, + {0xF947, UNICODE_NORM_QC_NO}, + {0xF948, UNICODE_NORM_QC_NO}, + {0xF949, UNICODE_NORM_QC_NO}, + {0xF94A, UNICODE_NORM_QC_NO}, + {0xF94B, UNICODE_NORM_QC_NO}, + {0xF94C, UNICODE_NORM_QC_NO}, + {0xF94D, UNICODE_NORM_QC_NO}, + {0xF94E, UNICODE_NORM_QC_NO}, + {0xF94F, UNICODE_NORM_QC_NO}, + {0xF950, UNICODE_NORM_QC_NO}, + {0xF951, UNICODE_NORM_QC_NO}, + {0xF952, UNICODE_NORM_QC_NO}, + {0xF953, UNICODE_NORM_QC_NO}, + {0xF954, UNICODE_NORM_QC_NO}, + {0xF955, UNICODE_NORM_QC_NO}, + {0xF956, UNICODE_NORM_QC_NO}, + {0xF957, UNICODE_NORM_QC_NO}, + {0xF958, UNICODE_NORM_QC_NO}, + {0xF959, UNICODE_NORM_QC_NO}, + {0xF95A, UNICODE_NORM_QC_NO}, + {0xF95B, UNICODE_NORM_QC_NO}, + {0xF95C, UNICODE_NORM_QC_NO}, + {0xF95D, UNICODE_NORM_QC_NO}, + {0xF95E, UNICODE_NORM_QC_NO}, + {0xF95F, UNICODE_NORM_QC_NO}, + {0xF960, UNICODE_NORM_QC_NO}, + {0xF961, UNICODE_NORM_QC_NO}, + {0xF962, UNICODE_NORM_QC_NO}, + {0xF963, UNICODE_NORM_QC_NO}, + {0xF964, UNICODE_NORM_QC_NO}, + {0xF965, UNICODE_NORM_QC_NO}, + {0xF966, UNICODE_NORM_QC_NO}, + {0xF967, UNICODE_NORM_QC_NO}, + {0xF968, UNICODE_NORM_QC_NO}, + {0xF969, UNICODE_NORM_QC_NO}, + {0xF96A, UNICODE_NORM_QC_NO}, + {0xF96B, UNICODE_NORM_QC_NO}, + {0xF96C, UNICODE_NORM_QC_NO}, + {0xF96D, UNICODE_NORM_QC_NO}, + {0xF96E, UNICODE_NORM_QC_NO}, + {0xF96F, UNICODE_NORM_QC_NO}, + {0xF970, UNICODE_NORM_QC_NO}, + {0xF971, UNICODE_NORM_QC_NO}, + {0xF972, UNICODE_NORM_QC_NO}, + {0xF973, UNICODE_NORM_QC_NO}, + {0xF974, UNICODE_NORM_QC_NO}, + {0xF975, UNICODE_NORM_QC_NO}, + {0xF976, UNICODE_NORM_QC_NO}, + {0xF977, UNICODE_NORM_QC_NO}, + {0xF978, UNICODE_NORM_QC_NO}, + {0xF979, UNICODE_NORM_QC_NO}, + {0xF97A, UNICODE_NORM_QC_NO}, + {0xF97B, UNICODE_NORM_QC_NO}, + {0xF97C, UNICODE_NORM_QC_NO}, + {0xF97D, UNICODE_NORM_QC_NO}, + {0xF97E, UNICODE_NORM_QC_NO}, + {0xF97F, UNICODE_NORM_QC_NO}, + {0xF980, UNICODE_NORM_QC_NO}, + {0xF981, UNICODE_NORM_QC_NO}, + {0xF982, UNICODE_NORM_QC_NO}, + {0xF983, UNICODE_NORM_QC_NO}, + {0xF984, UNICODE_NORM_QC_NO}, + {0xF985, UNICODE_NORM_QC_NO}, + {0xF986, UNICODE_NORM_QC_NO}, + {0xF987, UNICODE_NORM_QC_NO}, + {0xF988, UNICODE_NORM_QC_NO}, + {0xF989, UNICODE_NORM_QC_NO}, + {0xF98A, UNICODE_NORM_QC_NO}, + {0xF98B, UNICODE_NORM_QC_NO}, + {0xF98C, UNICODE_NORM_QC_NO}, + {0xF98D, UNICODE_NORM_QC_NO}, + {0xF98E, UNICODE_NORM_QC_NO}, + {0xF98F, UNICODE_NORM_QC_NO}, + {0xF990, UNICODE_NORM_QC_NO}, + {0xF991, UNICODE_NORM_QC_NO}, + {0xF992, UNICODE_NORM_QC_NO}, + {0xF993, UNICODE_NORM_QC_NO}, + {0xF994, UNICODE_NORM_QC_NO}, + {0xF995, UNICODE_NORM_QC_NO}, + {0xF996, UNICODE_NORM_QC_NO}, + {0xF997, UNICODE_NORM_QC_NO}, + {0xF998, UNICODE_NORM_QC_NO}, + {0xF999, UNICODE_NORM_QC_NO}, + {0xF99A, UNICODE_NORM_QC_NO}, + {0xF99B, UNICODE_NORM_QC_NO}, + {0xF99C, UNICODE_NORM_QC_NO}, + {0xF99D, UNICODE_NORM_QC_NO}, + {0xF99E, UNICODE_NORM_QC_NO}, + {0xF99F, UNICODE_NORM_QC_NO}, + {0xF9A0, UNICODE_NORM_QC_NO}, + {0xF9A1, UNICODE_NORM_QC_NO}, + {0xF9A2, UNICODE_NORM_QC_NO}, + {0xF9A3, UNICODE_NORM_QC_NO}, + {0xF9A4, UNICODE_NORM_QC_NO}, + {0xF9A5, UNICODE_NORM_QC_NO}, + {0xF9A6, UNICODE_NORM_QC_NO}, + {0xF9A7, UNICODE_NORM_QC_NO}, + {0xF9A8, UNICODE_NORM_QC_NO}, + {0xF9A9, UNICODE_NORM_QC_NO}, + {0xF9AA, UNICODE_NORM_QC_NO}, + {0xF9AB, UNICODE_NORM_QC_NO}, + {0xF9AC, UNICODE_NORM_QC_NO}, + {0xF9AD, UNICODE_NORM_QC_NO}, + {0xF9AE, UNICODE_NORM_QC_NO}, + {0xF9AF, UNICODE_NORM_QC_NO}, + {0xF9B0, UNICODE_NORM_QC_NO}, + {0xF9B1, UNICODE_NORM_QC_NO}, + {0xF9B2, UNICODE_NORM_QC_NO}, + {0xF9B3, UNICODE_NORM_QC_NO}, + {0xF9B4, UNICODE_NORM_QC_NO}, + {0xF9B5, UNICODE_NORM_QC_NO}, + {0xF9B6, UNICODE_NORM_QC_NO}, + {0xF9B7, UNICODE_NORM_QC_NO}, + {0xF9B8, UNICODE_NORM_QC_NO}, + {0xF9B9, UNICODE_NORM_QC_NO}, + {0xF9BA, UNICODE_NORM_QC_NO}, + {0xF9BB, UNICODE_NORM_QC_NO}, + {0xF9BC, UNICODE_NORM_QC_NO}, + {0xF9BD, UNICODE_NORM_QC_NO}, + {0xF9BE, UNICODE_NORM_QC_NO}, + {0xF9BF, UNICODE_NORM_QC_NO}, + {0xF9C0, UNICODE_NORM_QC_NO}, + {0xF9C1, UNICODE_NORM_QC_NO}, + {0xF9C2, UNICODE_NORM_QC_NO}, + {0xF9C3, UNICODE_NORM_QC_NO}, + {0xF9C4, UNICODE_NORM_QC_NO}, + {0xF9C5, UNICODE_NORM_QC_NO}, + {0xF9C6, UNICODE_NORM_QC_NO}, + {0xF9C7, UNICODE_NORM_QC_NO}, + {0xF9C8, UNICODE_NORM_QC_NO}, + {0xF9C9, UNICODE_NORM_QC_NO}, + {0xF9CA, UNICODE_NORM_QC_NO}, + {0xF9CB, UNICODE_NORM_QC_NO}, + {0xF9CC, UNICODE_NORM_QC_NO}, + {0xF9CD, UNICODE_NORM_QC_NO}, + {0xF9CE, UNICODE_NORM_QC_NO}, + {0xF9CF, UNICODE_NORM_QC_NO}, + {0xF9D0, UNICODE_NORM_QC_NO}, + {0xF9D1, UNICODE_NORM_QC_NO}, + {0xF9D2, UNICODE_NORM_QC_NO}, + {0xF9D3, UNICODE_NORM_QC_NO}, + {0xF9D4, UNICODE_NORM_QC_NO}, + {0xF9D5, UNICODE_NORM_QC_NO}, + {0xF9D6, UNICODE_NORM_QC_NO}, + {0xF9D7, UNICODE_NORM_QC_NO}, + {0xF9D8, UNICODE_NORM_QC_NO}, + {0xF9D9, UNICODE_NORM_QC_NO}, + {0xF9DA, UNICODE_NORM_QC_NO}, + {0xF9DB, UNICODE_NORM_QC_NO}, + {0xF9DC, UNICODE_NORM_QC_NO}, + {0xF9DD, UNICODE_NORM_QC_NO}, + {0xF9DE, UNICODE_NORM_QC_NO}, + {0xF9DF, UNICODE_NORM_QC_NO}, + {0xF9E0, UNICODE_NORM_QC_NO}, + {0xF9E1, UNICODE_NORM_QC_NO}, + {0xF9E2, UNICODE_NORM_QC_NO}, + {0xF9E3, UNICODE_NORM_QC_NO}, + {0xF9E4, UNICODE_NORM_QC_NO}, + {0xF9E5, UNICODE_NORM_QC_NO}, + {0xF9E6, UNICODE_NORM_QC_NO}, + {0xF9E7, UNICODE_NORM_QC_NO}, + {0xF9E8, UNICODE_NORM_QC_NO}, + {0xF9E9, UNICODE_NORM_QC_NO}, + {0xF9EA, UNICODE_NORM_QC_NO}, + {0xF9EB, UNICODE_NORM_QC_NO}, + {0xF9EC, UNICODE_NORM_QC_NO}, + {0xF9ED, UNICODE_NORM_QC_NO}, + {0xF9EE, UNICODE_NORM_QC_NO}, + {0xF9EF, UNICODE_NORM_QC_NO}, + {0xF9F0, UNICODE_NORM_QC_NO}, + {0xF9F1, UNICODE_NORM_QC_NO}, + {0xF9F2, UNICODE_NORM_QC_NO}, + {0xF9F3, UNICODE_NORM_QC_NO}, + {0xF9F4, UNICODE_NORM_QC_NO}, + {0xF9F5, UNICODE_NORM_QC_NO}, + {0xF9F6, UNICODE_NORM_QC_NO}, + {0xF9F7, UNICODE_NORM_QC_NO}, + {0xF9F8, UNICODE_NORM_QC_NO}, + {0xF9F9, UNICODE_NORM_QC_NO}, + {0xF9FA, UNICODE_NORM_QC_NO}, + {0xF9FB, UNICODE_NORM_QC_NO}, + {0xF9FC, UNICODE_NORM_QC_NO}, + {0xF9FD, UNICODE_NORM_QC_NO}, + {0xF9FE, UNICODE_NORM_QC_NO}, + {0xF9FF, UNICODE_NORM_QC_NO}, + {0xFA00, UNICODE_NORM_QC_NO}, + {0xFA01, UNICODE_NORM_QC_NO}, + {0xFA02, UNICODE_NORM_QC_NO}, + {0xFA03, UNICODE_NORM_QC_NO}, + {0xFA04, UNICODE_NORM_QC_NO}, + {0xFA05, UNICODE_NORM_QC_NO}, + {0xFA06, UNICODE_NORM_QC_NO}, + {0xFA07, UNICODE_NORM_QC_NO}, + {0xFA08, UNICODE_NORM_QC_NO}, + {0xFA09, UNICODE_NORM_QC_NO}, + {0xFA0A, UNICODE_NORM_QC_NO}, + {0xFA0B, UNICODE_NORM_QC_NO}, + {0xFA0C, UNICODE_NORM_QC_NO}, + {0xFA0D, UNICODE_NORM_QC_NO}, + {0xFA10, UNICODE_NORM_QC_NO}, + {0xFA12, UNICODE_NORM_QC_NO}, + {0xFA15, UNICODE_NORM_QC_NO}, + {0xFA16, UNICODE_NORM_QC_NO}, + {0xFA17, UNICODE_NORM_QC_NO}, + {0xFA18, UNICODE_NORM_QC_NO}, + {0xFA19, UNICODE_NORM_QC_NO}, + {0xFA1A, UNICODE_NORM_QC_NO}, + {0xFA1B, UNICODE_NORM_QC_NO}, + {0xFA1C, UNICODE_NORM_QC_NO}, + {0xFA1D, UNICODE_NORM_QC_NO}, + {0xFA1E, UNICODE_NORM_QC_NO}, + {0xFA20, UNICODE_NORM_QC_NO}, + {0xFA22, UNICODE_NORM_QC_NO}, + {0xFA25, UNICODE_NORM_QC_NO}, + {0xFA26, UNICODE_NORM_QC_NO}, + {0xFA2A, UNICODE_NORM_QC_NO}, + {0xFA2B, UNICODE_NORM_QC_NO}, + {0xFA2C, UNICODE_NORM_QC_NO}, + {0xFA2D, UNICODE_NORM_QC_NO}, + {0xFA2E, UNICODE_NORM_QC_NO}, + {0xFA2F, UNICODE_NORM_QC_NO}, + {0xFA30, UNICODE_NORM_QC_NO}, + {0xFA31, UNICODE_NORM_QC_NO}, + {0xFA32, UNICODE_NORM_QC_NO}, + {0xFA33, UNICODE_NORM_QC_NO}, + {0xFA34, UNICODE_NORM_QC_NO}, + {0xFA35, UNICODE_NORM_QC_NO}, + {0xFA36, UNICODE_NORM_QC_NO}, + {0xFA37, UNICODE_NORM_QC_NO}, + {0xFA38, UNICODE_NORM_QC_NO}, + {0xFA39, UNICODE_NORM_QC_NO}, + {0xFA3A, UNICODE_NORM_QC_NO}, + {0xFA3B, UNICODE_NORM_QC_NO}, + {0xFA3C, UNICODE_NORM_QC_NO}, + {0xFA3D, UNICODE_NORM_QC_NO}, + {0xFA3E, UNICODE_NORM_QC_NO}, + {0xFA3F, UNICODE_NORM_QC_NO}, + {0xFA40, UNICODE_NORM_QC_NO}, + {0xFA41, UNICODE_NORM_QC_NO}, + {0xFA42, UNICODE_NORM_QC_NO}, + {0xFA43, UNICODE_NORM_QC_NO}, + {0xFA44, UNICODE_NORM_QC_NO}, + {0xFA45, UNICODE_NORM_QC_NO}, + {0xFA46, UNICODE_NORM_QC_NO}, + {0xFA47, UNICODE_NORM_QC_NO}, + {0xFA48, UNICODE_NORM_QC_NO}, + {0xFA49, UNICODE_NORM_QC_NO}, + {0xFA4A, UNICODE_NORM_QC_NO}, + {0xFA4B, UNICODE_NORM_QC_NO}, + {0xFA4C, UNICODE_NORM_QC_NO}, + {0xFA4D, UNICODE_NORM_QC_NO}, + {0xFA4E, UNICODE_NORM_QC_NO}, + {0xFA4F, UNICODE_NORM_QC_NO}, + {0xFA50, UNICODE_NORM_QC_NO}, + {0xFA51, UNICODE_NORM_QC_NO}, + {0xFA52, UNICODE_NORM_QC_NO}, + {0xFA53, UNICODE_NORM_QC_NO}, + {0xFA54, UNICODE_NORM_QC_NO}, + {0xFA55, UNICODE_NORM_QC_NO}, + {0xFA56, UNICODE_NORM_QC_NO}, + {0xFA57, UNICODE_NORM_QC_NO}, + {0xFA58, UNICODE_NORM_QC_NO}, + {0xFA59, UNICODE_NORM_QC_NO}, + {0xFA5A, UNICODE_NORM_QC_NO}, + {0xFA5B, UNICODE_NORM_QC_NO}, + {0xFA5C, UNICODE_NORM_QC_NO}, + {0xFA5D, UNICODE_NORM_QC_NO}, + {0xFA5E, UNICODE_NORM_QC_NO}, + {0xFA5F, UNICODE_NORM_QC_NO}, + {0xFA60, UNICODE_NORM_QC_NO}, + {0xFA61, UNICODE_NORM_QC_NO}, + {0xFA62, UNICODE_NORM_QC_NO}, + {0xFA63, UNICODE_NORM_QC_NO}, + {0xFA64, UNICODE_NORM_QC_NO}, + {0xFA65, UNICODE_NORM_QC_NO}, + {0xFA66, UNICODE_NORM_QC_NO}, + {0xFA67, UNICODE_NORM_QC_NO}, + {0xFA68, UNICODE_NORM_QC_NO}, + {0xFA69, UNICODE_NORM_QC_NO}, + {0xFA6A, UNICODE_NORM_QC_NO}, + {0xFA6B, UNICODE_NORM_QC_NO}, + {0xFA6C, UNICODE_NORM_QC_NO}, + {0xFA6D, UNICODE_NORM_QC_NO}, + {0xFA70, UNICODE_NORM_QC_NO}, + {0xFA71, UNICODE_NORM_QC_NO}, + {0xFA72, UNICODE_NORM_QC_NO}, + {0xFA73, UNICODE_NORM_QC_NO}, + {0xFA74, UNICODE_NORM_QC_NO}, + {0xFA75, UNICODE_NORM_QC_NO}, + {0xFA76, UNICODE_NORM_QC_NO}, + {0xFA77, UNICODE_NORM_QC_NO}, + {0xFA78, UNICODE_NORM_QC_NO}, + {0xFA79, UNICODE_NORM_QC_NO}, + {0xFA7A, UNICODE_NORM_QC_NO}, + {0xFA7B, UNICODE_NORM_QC_NO}, + {0xFA7C, UNICODE_NORM_QC_NO}, + {0xFA7D, UNICODE_NORM_QC_NO}, + {0xFA7E, UNICODE_NORM_QC_NO}, + {0xFA7F, UNICODE_NORM_QC_NO}, + {0xFA80, UNICODE_NORM_QC_NO}, + {0xFA81, UNICODE_NORM_QC_NO}, + {0xFA82, UNICODE_NORM_QC_NO}, + {0xFA83, UNICODE_NORM_QC_NO}, + {0xFA84, UNICODE_NORM_QC_NO}, + {0xFA85, UNICODE_NORM_QC_NO}, + {0xFA86, UNICODE_NORM_QC_NO}, + {0xFA87, UNICODE_NORM_QC_NO}, + {0xFA88, UNICODE_NORM_QC_NO}, + {0xFA89, UNICODE_NORM_QC_NO}, + {0xFA8A, UNICODE_NORM_QC_NO}, + {0xFA8B, UNICODE_NORM_QC_NO}, + {0xFA8C, UNICODE_NORM_QC_NO}, + {0xFA8D, UNICODE_NORM_QC_NO}, + {0xFA8E, UNICODE_NORM_QC_NO}, + {0xFA8F, UNICODE_NORM_QC_NO}, + {0xFA90, UNICODE_NORM_QC_NO}, + {0xFA91, UNICODE_NORM_QC_NO}, + {0xFA92, UNICODE_NORM_QC_NO}, + {0xFA93, UNICODE_NORM_QC_NO}, + {0xFA94, UNICODE_NORM_QC_NO}, + {0xFA95, UNICODE_NORM_QC_NO}, + {0xFA96, UNICODE_NORM_QC_NO}, + {0xFA97, UNICODE_NORM_QC_NO}, + {0xFA98, UNICODE_NORM_QC_NO}, + {0xFA99, UNICODE_NORM_QC_NO}, + {0xFA9A, UNICODE_NORM_QC_NO}, + {0xFA9B, UNICODE_NORM_QC_NO}, + {0xFA9C, UNICODE_NORM_QC_NO}, + {0xFA9D, UNICODE_NORM_QC_NO}, + {0xFA9E, UNICODE_NORM_QC_NO}, + {0xFA9F, UNICODE_NORM_QC_NO}, + {0xFAA0, UNICODE_NORM_QC_NO}, + {0xFAA1, UNICODE_NORM_QC_NO}, + {0xFAA2, UNICODE_NORM_QC_NO}, + {0xFAA3, UNICODE_NORM_QC_NO}, + {0xFAA4, UNICODE_NORM_QC_NO}, + {0xFAA5, UNICODE_NORM_QC_NO}, + {0xFAA6, UNICODE_NORM_QC_NO}, + {0xFAA7, UNICODE_NORM_QC_NO}, + {0xFAA8, UNICODE_NORM_QC_NO}, + {0xFAA9, UNICODE_NORM_QC_NO}, + {0xFAAA, UNICODE_NORM_QC_NO}, + {0xFAAB, UNICODE_NORM_QC_NO}, + {0xFAAC, UNICODE_NORM_QC_NO}, + {0xFAAD, UNICODE_NORM_QC_NO}, + {0xFAAE, UNICODE_NORM_QC_NO}, + {0xFAAF, UNICODE_NORM_QC_NO}, + {0xFAB0, UNICODE_NORM_QC_NO}, + {0xFAB1, UNICODE_NORM_QC_NO}, + {0xFAB2, UNICODE_NORM_QC_NO}, + {0xFAB3, UNICODE_NORM_QC_NO}, + {0xFAB4, UNICODE_NORM_QC_NO}, + {0xFAB5, UNICODE_NORM_QC_NO}, + {0xFAB6, UNICODE_NORM_QC_NO}, + {0xFAB7, UNICODE_NORM_QC_NO}, + {0xFAB8, UNICODE_NORM_QC_NO}, + {0xFAB9, UNICODE_NORM_QC_NO}, + {0xFABA, UNICODE_NORM_QC_NO}, + {0xFABB, UNICODE_NORM_QC_NO}, + {0xFABC, UNICODE_NORM_QC_NO}, + {0xFABD, UNICODE_NORM_QC_NO}, + {0xFABE, UNICODE_NORM_QC_NO}, + {0xFABF, UNICODE_NORM_QC_NO}, + {0xFAC0, UNICODE_NORM_QC_NO}, + {0xFAC1, UNICODE_NORM_QC_NO}, + {0xFAC2, UNICODE_NORM_QC_NO}, + {0xFAC3, UNICODE_NORM_QC_NO}, + {0xFAC4, UNICODE_NORM_QC_NO}, + {0xFAC5, UNICODE_NORM_QC_NO}, + {0xFAC6, UNICODE_NORM_QC_NO}, + {0xFAC7, UNICODE_NORM_QC_NO}, + {0xFAC8, UNICODE_NORM_QC_NO}, + {0xFAC9, UNICODE_NORM_QC_NO}, + {0xFACA, UNICODE_NORM_QC_NO}, + {0xFACB, UNICODE_NORM_QC_NO}, + {0xFACC, UNICODE_NORM_QC_NO}, + {0xFACD, UNICODE_NORM_QC_NO}, + {0xFACE, UNICODE_NORM_QC_NO}, + {0xFACF, UNICODE_NORM_QC_NO}, + {0xFAD0, UNICODE_NORM_QC_NO}, + {0xFAD1, UNICODE_NORM_QC_NO}, + {0xFAD2, UNICODE_NORM_QC_NO}, + {0xFAD3, UNICODE_NORM_QC_NO}, + {0xFAD4, UNICODE_NORM_QC_NO}, + {0xFAD5, UNICODE_NORM_QC_NO}, + {0xFAD6, UNICODE_NORM_QC_NO}, + {0xFAD7, UNICODE_NORM_QC_NO}, + {0xFAD8, UNICODE_NORM_QC_NO}, + {0xFAD9, UNICODE_NORM_QC_NO}, + {0xFB1D, UNICODE_NORM_QC_NO}, + {0xFB1F, UNICODE_NORM_QC_NO}, + {0xFB2A, UNICODE_NORM_QC_NO}, + {0xFB2B, UNICODE_NORM_QC_NO}, + {0xFB2C, UNICODE_NORM_QC_NO}, + {0xFB2D, UNICODE_NORM_QC_NO}, + {0xFB2E, UNICODE_NORM_QC_NO}, + {0xFB2F, UNICODE_NORM_QC_NO}, + {0xFB30, UNICODE_NORM_QC_NO}, + {0xFB31, UNICODE_NORM_QC_NO}, + {0xFB32, UNICODE_NORM_QC_NO}, + {0xFB33, UNICODE_NORM_QC_NO}, + {0xFB34, UNICODE_NORM_QC_NO}, + {0xFB35, UNICODE_NORM_QC_NO}, + {0xFB36, UNICODE_NORM_QC_NO}, + {0xFB38, UNICODE_NORM_QC_NO}, + {0xFB39, UNICODE_NORM_QC_NO}, + {0xFB3A, UNICODE_NORM_QC_NO}, + {0xFB3B, UNICODE_NORM_QC_NO}, + {0xFB3C, UNICODE_NORM_QC_NO}, + {0xFB3E, UNICODE_NORM_QC_NO}, + {0xFB40, UNICODE_NORM_QC_NO}, + {0xFB41, UNICODE_NORM_QC_NO}, + {0xFB43, UNICODE_NORM_QC_NO}, + {0xFB44, UNICODE_NORM_QC_NO}, + {0xFB46, UNICODE_NORM_QC_NO}, + {0xFB47, UNICODE_NORM_QC_NO}, + {0xFB48, UNICODE_NORM_QC_NO}, + {0xFB49, UNICODE_NORM_QC_NO}, + {0xFB4A, UNICODE_NORM_QC_NO}, + {0xFB4B, UNICODE_NORM_QC_NO}, + {0xFB4C, UNICODE_NORM_QC_NO}, + {0xFB4D, UNICODE_NORM_QC_NO}, + {0xFB4E, UNICODE_NORM_QC_NO}, + {0x110BA, UNICODE_NORM_QC_MAYBE}, + {0x11127, UNICODE_NORM_QC_MAYBE}, + {0x1133E, UNICODE_NORM_QC_MAYBE}, + {0x11357, UNICODE_NORM_QC_MAYBE}, + {0x114B0, UNICODE_NORM_QC_MAYBE}, + {0x114BA, UNICODE_NORM_QC_MAYBE}, + {0x114BD, UNICODE_NORM_QC_MAYBE}, + {0x115AF, UNICODE_NORM_QC_MAYBE}, + {0x11930, UNICODE_NORM_QC_MAYBE}, + {0x1D15E, UNICODE_NORM_QC_NO}, + {0x1D15F, UNICODE_NORM_QC_NO}, + {0x1D160, UNICODE_NORM_QC_NO}, + {0x1D161, UNICODE_NORM_QC_NO}, + {0x1D162, UNICODE_NORM_QC_NO}, + {0x1D163, UNICODE_NORM_QC_NO}, + {0x1D164, UNICODE_NORM_QC_NO}, + {0x1D1BB, UNICODE_NORM_QC_NO}, + {0x1D1BC, UNICODE_NORM_QC_NO}, + {0x1D1BD, UNICODE_NORM_QC_NO}, + {0x1D1BE, UNICODE_NORM_QC_NO}, + {0x1D1BF, UNICODE_NORM_QC_NO}, + {0x1D1C0, UNICODE_NORM_QC_NO}, + {0x2F800, UNICODE_NORM_QC_NO}, + {0x2F801, UNICODE_NORM_QC_NO}, + {0x2F802, UNICODE_NORM_QC_NO}, + {0x2F803, UNICODE_NORM_QC_NO}, + {0x2F804, UNICODE_NORM_QC_NO}, + {0x2F805, UNICODE_NORM_QC_NO}, + {0x2F806, UNICODE_NORM_QC_NO}, + {0x2F807, UNICODE_NORM_QC_NO}, + {0x2F808, UNICODE_NORM_QC_NO}, + {0x2F809, UNICODE_NORM_QC_NO}, + {0x2F80A, UNICODE_NORM_QC_NO}, + {0x2F80B, UNICODE_NORM_QC_NO}, + {0x2F80C, UNICODE_NORM_QC_NO}, + {0x2F80D, UNICODE_NORM_QC_NO}, + {0x2F80E, UNICODE_NORM_QC_NO}, + {0x2F80F, UNICODE_NORM_QC_NO}, + {0x2F810, UNICODE_NORM_QC_NO}, + {0x2F811, UNICODE_NORM_QC_NO}, + {0x2F812, UNICODE_NORM_QC_NO}, + {0x2F813, UNICODE_NORM_QC_NO}, + {0x2F814, UNICODE_NORM_QC_NO}, + {0x2F815, UNICODE_NORM_QC_NO}, + {0x2F816, UNICODE_NORM_QC_NO}, + {0x2F817, UNICODE_NORM_QC_NO}, + {0x2F818, UNICODE_NORM_QC_NO}, + {0x2F819, UNICODE_NORM_QC_NO}, + {0x2F81A, UNICODE_NORM_QC_NO}, + {0x2F81B, UNICODE_NORM_QC_NO}, + {0x2F81C, UNICODE_NORM_QC_NO}, + {0x2F81D, UNICODE_NORM_QC_NO}, + {0x2F81E, UNICODE_NORM_QC_NO}, + {0x2F81F, UNICODE_NORM_QC_NO}, + {0x2F820, UNICODE_NORM_QC_NO}, + {0x2F821, UNICODE_NORM_QC_NO}, + {0x2F822, UNICODE_NORM_QC_NO}, + {0x2F823, UNICODE_NORM_QC_NO}, + {0x2F824, UNICODE_NORM_QC_NO}, + {0x2F825, UNICODE_NORM_QC_NO}, + {0x2F826, UNICODE_NORM_QC_NO}, + {0x2F827, UNICODE_NORM_QC_NO}, + {0x2F828, UNICODE_NORM_QC_NO}, + {0x2F829, UNICODE_NORM_QC_NO}, + {0x2F82A, UNICODE_NORM_QC_NO}, + {0x2F82B, UNICODE_NORM_QC_NO}, + {0x2F82C, UNICODE_NORM_QC_NO}, + {0x2F82D, UNICODE_NORM_QC_NO}, + {0x2F82E, UNICODE_NORM_QC_NO}, + {0x2F82F, UNICODE_NORM_QC_NO}, + {0x2F830, UNICODE_NORM_QC_NO}, + {0x2F831, UNICODE_NORM_QC_NO}, + {0x2F832, UNICODE_NORM_QC_NO}, + {0x2F833, UNICODE_NORM_QC_NO}, + {0x2F834, UNICODE_NORM_QC_NO}, + {0x2F835, UNICODE_NORM_QC_NO}, + {0x2F836, UNICODE_NORM_QC_NO}, + {0x2F837, UNICODE_NORM_QC_NO}, + {0x2F838, UNICODE_NORM_QC_NO}, + {0x2F839, UNICODE_NORM_QC_NO}, + {0x2F83A, UNICODE_NORM_QC_NO}, + {0x2F83B, UNICODE_NORM_QC_NO}, + {0x2F83C, UNICODE_NORM_QC_NO}, + {0x2F83D, UNICODE_NORM_QC_NO}, + {0x2F83E, UNICODE_NORM_QC_NO}, + {0x2F83F, UNICODE_NORM_QC_NO}, + {0x2F840, UNICODE_NORM_QC_NO}, + {0x2F841, UNICODE_NORM_QC_NO}, + {0x2F842, UNICODE_NORM_QC_NO}, + {0x2F843, UNICODE_NORM_QC_NO}, + {0x2F844, UNICODE_NORM_QC_NO}, + {0x2F845, UNICODE_NORM_QC_NO}, + {0x2F846, UNICODE_NORM_QC_NO}, + {0x2F847, UNICODE_NORM_QC_NO}, + {0x2F848, UNICODE_NORM_QC_NO}, + {0x2F849, UNICODE_NORM_QC_NO}, + {0x2F84A, UNICODE_NORM_QC_NO}, + {0x2F84B, UNICODE_NORM_QC_NO}, + {0x2F84C, UNICODE_NORM_QC_NO}, + {0x2F84D, UNICODE_NORM_QC_NO}, + {0x2F84E, UNICODE_NORM_QC_NO}, + {0x2F84F, UNICODE_NORM_QC_NO}, + {0x2F850, UNICODE_NORM_QC_NO}, + {0x2F851, UNICODE_NORM_QC_NO}, + {0x2F852, UNICODE_NORM_QC_NO}, + {0x2F853, UNICODE_NORM_QC_NO}, + {0x2F854, UNICODE_NORM_QC_NO}, + {0x2F855, UNICODE_NORM_QC_NO}, + {0x2F856, UNICODE_NORM_QC_NO}, + {0x2F857, UNICODE_NORM_QC_NO}, + {0x2F858, UNICODE_NORM_QC_NO}, + {0x2F859, UNICODE_NORM_QC_NO}, + {0x2F85A, UNICODE_NORM_QC_NO}, + {0x2F85B, UNICODE_NORM_QC_NO}, + {0x2F85C, UNICODE_NORM_QC_NO}, + {0x2F85D, UNICODE_NORM_QC_NO}, + {0x2F85E, UNICODE_NORM_QC_NO}, + {0x2F85F, UNICODE_NORM_QC_NO}, + {0x2F860, UNICODE_NORM_QC_NO}, + {0x2F861, UNICODE_NORM_QC_NO}, + {0x2F862, UNICODE_NORM_QC_NO}, + {0x2F863, UNICODE_NORM_QC_NO}, + {0x2F864, UNICODE_NORM_QC_NO}, + {0x2F865, UNICODE_NORM_QC_NO}, + {0x2F866, UNICODE_NORM_QC_NO}, + {0x2F867, UNICODE_NORM_QC_NO}, + {0x2F868, UNICODE_NORM_QC_NO}, + {0x2F869, UNICODE_NORM_QC_NO}, + {0x2F86A, UNICODE_NORM_QC_NO}, + {0x2F86B, UNICODE_NORM_QC_NO}, + {0x2F86C, UNICODE_NORM_QC_NO}, + {0x2F86D, UNICODE_NORM_QC_NO}, + {0x2F86E, UNICODE_NORM_QC_NO}, + {0x2F86F, UNICODE_NORM_QC_NO}, + {0x2F870, UNICODE_NORM_QC_NO}, + {0x2F871, UNICODE_NORM_QC_NO}, + {0x2F872, UNICODE_NORM_QC_NO}, + {0x2F873, UNICODE_NORM_QC_NO}, + {0x2F874, UNICODE_NORM_QC_NO}, + {0x2F875, UNICODE_NORM_QC_NO}, + {0x2F876, UNICODE_NORM_QC_NO}, + {0x2F877, UNICODE_NORM_QC_NO}, + {0x2F878, UNICODE_NORM_QC_NO}, + {0x2F879, UNICODE_NORM_QC_NO}, + {0x2F87A, UNICODE_NORM_QC_NO}, + {0x2F87B, UNICODE_NORM_QC_NO}, + {0x2F87C, UNICODE_NORM_QC_NO}, + {0x2F87D, UNICODE_NORM_QC_NO}, + {0x2F87E, UNICODE_NORM_QC_NO}, + {0x2F87F, UNICODE_NORM_QC_NO}, + {0x2F880, UNICODE_NORM_QC_NO}, + {0x2F881, UNICODE_NORM_QC_NO}, + {0x2F882, UNICODE_NORM_QC_NO}, + {0x2F883, UNICODE_NORM_QC_NO}, + {0x2F884, UNICODE_NORM_QC_NO}, + {0x2F885, UNICODE_NORM_QC_NO}, + {0x2F886, UNICODE_NORM_QC_NO}, + {0x2F887, UNICODE_NORM_QC_NO}, + {0x2F888, UNICODE_NORM_QC_NO}, + {0x2F889, UNICODE_NORM_QC_NO}, + {0x2F88A, UNICODE_NORM_QC_NO}, + {0x2F88B, UNICODE_NORM_QC_NO}, + {0x2F88C, UNICODE_NORM_QC_NO}, + {0x2F88D, UNICODE_NORM_QC_NO}, + {0x2F88E, UNICODE_NORM_QC_NO}, + {0x2F88F, UNICODE_NORM_QC_NO}, + {0x2F890, UNICODE_NORM_QC_NO}, + {0x2F891, UNICODE_NORM_QC_NO}, + {0x2F892, UNICODE_NORM_QC_NO}, + {0x2F893, UNICODE_NORM_QC_NO}, + {0x2F894, UNICODE_NORM_QC_NO}, + {0x2F895, UNICODE_NORM_QC_NO}, + {0x2F896, UNICODE_NORM_QC_NO}, + {0x2F897, UNICODE_NORM_QC_NO}, + {0x2F898, UNICODE_NORM_QC_NO}, + {0x2F899, UNICODE_NORM_QC_NO}, + {0x2F89A, UNICODE_NORM_QC_NO}, + {0x2F89B, UNICODE_NORM_QC_NO}, + {0x2F89C, UNICODE_NORM_QC_NO}, + {0x2F89D, UNICODE_NORM_QC_NO}, + {0x2F89E, UNICODE_NORM_QC_NO}, + {0x2F89F, UNICODE_NORM_QC_NO}, + {0x2F8A0, UNICODE_NORM_QC_NO}, + {0x2F8A1, UNICODE_NORM_QC_NO}, + {0x2F8A2, UNICODE_NORM_QC_NO}, + {0x2F8A3, UNICODE_NORM_QC_NO}, + {0x2F8A4, UNICODE_NORM_QC_NO}, + {0x2F8A5, UNICODE_NORM_QC_NO}, + {0x2F8A6, UNICODE_NORM_QC_NO}, + {0x2F8A7, UNICODE_NORM_QC_NO}, + {0x2F8A8, UNICODE_NORM_QC_NO}, + {0x2F8A9, UNICODE_NORM_QC_NO}, + {0x2F8AA, UNICODE_NORM_QC_NO}, + {0x2F8AB, UNICODE_NORM_QC_NO}, + {0x2F8AC, UNICODE_NORM_QC_NO}, + {0x2F8AD, UNICODE_NORM_QC_NO}, + {0x2F8AE, UNICODE_NORM_QC_NO}, + {0x2F8AF, UNICODE_NORM_QC_NO}, + {0x2F8B0, UNICODE_NORM_QC_NO}, + {0x2F8B1, UNICODE_NORM_QC_NO}, + {0x2F8B2, UNICODE_NORM_QC_NO}, + {0x2F8B3, UNICODE_NORM_QC_NO}, + {0x2F8B4, UNICODE_NORM_QC_NO}, + {0x2F8B5, UNICODE_NORM_QC_NO}, + {0x2F8B6, UNICODE_NORM_QC_NO}, + {0x2F8B7, UNICODE_NORM_QC_NO}, + {0x2F8B8, UNICODE_NORM_QC_NO}, + {0x2F8B9, UNICODE_NORM_QC_NO}, + {0x2F8BA, UNICODE_NORM_QC_NO}, + {0x2F8BB, UNICODE_NORM_QC_NO}, + {0x2F8BC, UNICODE_NORM_QC_NO}, + {0x2F8BD, UNICODE_NORM_QC_NO}, + {0x2F8BE, UNICODE_NORM_QC_NO}, + {0x2F8BF, UNICODE_NORM_QC_NO}, + {0x2F8C0, UNICODE_NORM_QC_NO}, + {0x2F8C1, UNICODE_NORM_QC_NO}, + {0x2F8C2, UNICODE_NORM_QC_NO}, + {0x2F8C3, UNICODE_NORM_QC_NO}, + {0x2F8C4, UNICODE_NORM_QC_NO}, + {0x2F8C5, UNICODE_NORM_QC_NO}, + {0x2F8C6, UNICODE_NORM_QC_NO}, + {0x2F8C7, UNICODE_NORM_QC_NO}, + {0x2F8C8, UNICODE_NORM_QC_NO}, + {0x2F8C9, UNICODE_NORM_QC_NO}, + {0x2F8CA, UNICODE_NORM_QC_NO}, + {0x2F8CB, UNICODE_NORM_QC_NO}, + {0x2F8CC, UNICODE_NORM_QC_NO}, + {0x2F8CD, UNICODE_NORM_QC_NO}, + {0x2F8CE, UNICODE_NORM_QC_NO}, + {0x2F8CF, UNICODE_NORM_QC_NO}, + {0x2F8D0, UNICODE_NORM_QC_NO}, + {0x2F8D1, UNICODE_NORM_QC_NO}, + {0x2F8D2, UNICODE_NORM_QC_NO}, + {0x2F8D3, UNICODE_NORM_QC_NO}, + {0x2F8D4, UNICODE_NORM_QC_NO}, + {0x2F8D5, UNICODE_NORM_QC_NO}, + {0x2F8D6, UNICODE_NORM_QC_NO}, + {0x2F8D7, UNICODE_NORM_QC_NO}, + {0x2F8D8, UNICODE_NORM_QC_NO}, + {0x2F8D9, UNICODE_NORM_QC_NO}, + {0x2F8DA, UNICODE_NORM_QC_NO}, + {0x2F8DB, UNICODE_NORM_QC_NO}, + {0x2F8DC, UNICODE_NORM_QC_NO}, + {0x2F8DD, UNICODE_NORM_QC_NO}, + {0x2F8DE, UNICODE_NORM_QC_NO}, + {0x2F8DF, UNICODE_NORM_QC_NO}, + {0x2F8E0, UNICODE_NORM_QC_NO}, + {0x2F8E1, UNICODE_NORM_QC_NO}, + {0x2F8E2, UNICODE_NORM_QC_NO}, + {0x2F8E3, UNICODE_NORM_QC_NO}, + {0x2F8E4, UNICODE_NORM_QC_NO}, + {0x2F8E5, UNICODE_NORM_QC_NO}, + {0x2F8E6, UNICODE_NORM_QC_NO}, + {0x2F8E7, UNICODE_NORM_QC_NO}, + {0x2F8E8, UNICODE_NORM_QC_NO}, + {0x2F8E9, UNICODE_NORM_QC_NO}, + {0x2F8EA, UNICODE_NORM_QC_NO}, + {0x2F8EB, UNICODE_NORM_QC_NO}, + {0x2F8EC, UNICODE_NORM_QC_NO}, + {0x2F8ED, UNICODE_NORM_QC_NO}, + {0x2F8EE, UNICODE_NORM_QC_NO}, + {0x2F8EF, UNICODE_NORM_QC_NO}, + {0x2F8F0, UNICODE_NORM_QC_NO}, + {0x2F8F1, UNICODE_NORM_QC_NO}, + {0x2F8F2, UNICODE_NORM_QC_NO}, + {0x2F8F3, UNICODE_NORM_QC_NO}, + {0x2F8F4, UNICODE_NORM_QC_NO}, + {0x2F8F5, UNICODE_NORM_QC_NO}, + {0x2F8F6, UNICODE_NORM_QC_NO}, + {0x2F8F7, UNICODE_NORM_QC_NO}, + {0x2F8F8, UNICODE_NORM_QC_NO}, + {0x2F8F9, UNICODE_NORM_QC_NO}, + {0x2F8FA, UNICODE_NORM_QC_NO}, + {0x2F8FB, UNICODE_NORM_QC_NO}, + {0x2F8FC, UNICODE_NORM_QC_NO}, + {0x2F8FD, UNICODE_NORM_QC_NO}, + {0x2F8FE, UNICODE_NORM_QC_NO}, + {0x2F8FF, UNICODE_NORM_QC_NO}, + {0x2F900, UNICODE_NORM_QC_NO}, + {0x2F901, UNICODE_NORM_QC_NO}, + {0x2F902, UNICODE_NORM_QC_NO}, + {0x2F903, UNICODE_NORM_QC_NO}, + {0x2F904, UNICODE_NORM_QC_NO}, + {0x2F905, UNICODE_NORM_QC_NO}, + {0x2F906, UNICODE_NORM_QC_NO}, + {0x2F907, UNICODE_NORM_QC_NO}, + {0x2F908, UNICODE_NORM_QC_NO}, + {0x2F909, UNICODE_NORM_QC_NO}, + {0x2F90A, UNICODE_NORM_QC_NO}, + {0x2F90B, UNICODE_NORM_QC_NO}, + {0x2F90C, UNICODE_NORM_QC_NO}, + {0x2F90D, UNICODE_NORM_QC_NO}, + {0x2F90E, UNICODE_NORM_QC_NO}, + {0x2F90F, UNICODE_NORM_QC_NO}, + {0x2F910, UNICODE_NORM_QC_NO}, + {0x2F911, UNICODE_NORM_QC_NO}, + {0x2F912, UNICODE_NORM_QC_NO}, + {0x2F913, UNICODE_NORM_QC_NO}, + {0x2F914, UNICODE_NORM_QC_NO}, + {0x2F915, UNICODE_NORM_QC_NO}, + {0x2F916, UNICODE_NORM_QC_NO}, + {0x2F917, UNICODE_NORM_QC_NO}, + {0x2F918, UNICODE_NORM_QC_NO}, + {0x2F919, UNICODE_NORM_QC_NO}, + {0x2F91A, UNICODE_NORM_QC_NO}, + {0x2F91B, UNICODE_NORM_QC_NO}, + {0x2F91C, UNICODE_NORM_QC_NO}, + {0x2F91D, UNICODE_NORM_QC_NO}, + {0x2F91E, UNICODE_NORM_QC_NO}, + {0x2F91F, UNICODE_NORM_QC_NO}, + {0x2F920, UNICODE_NORM_QC_NO}, + {0x2F921, UNICODE_NORM_QC_NO}, + {0x2F922, UNICODE_NORM_QC_NO}, + {0x2F923, UNICODE_NORM_QC_NO}, + {0x2F924, UNICODE_NORM_QC_NO}, + {0x2F925, UNICODE_NORM_QC_NO}, + {0x2F926, UNICODE_NORM_QC_NO}, + {0x2F927, UNICODE_NORM_QC_NO}, + {0x2F928, UNICODE_NORM_QC_NO}, + {0x2F929, UNICODE_NORM_QC_NO}, + {0x2F92A, UNICODE_NORM_QC_NO}, + {0x2F92B, UNICODE_NORM_QC_NO}, + {0x2F92C, UNICODE_NORM_QC_NO}, + {0x2F92D, UNICODE_NORM_QC_NO}, + {0x2F92E, UNICODE_NORM_QC_NO}, + {0x2F92F, UNICODE_NORM_QC_NO}, + {0x2F930, UNICODE_NORM_QC_NO}, + {0x2F931, UNICODE_NORM_QC_NO}, + {0x2F932, UNICODE_NORM_QC_NO}, + {0x2F933, UNICODE_NORM_QC_NO}, + {0x2F934, UNICODE_NORM_QC_NO}, + {0x2F935, UNICODE_NORM_QC_NO}, + {0x2F936, UNICODE_NORM_QC_NO}, + {0x2F937, UNICODE_NORM_QC_NO}, + {0x2F938, UNICODE_NORM_QC_NO}, + {0x2F939, UNICODE_NORM_QC_NO}, + {0x2F93A, UNICODE_NORM_QC_NO}, + {0x2F93B, UNICODE_NORM_QC_NO}, + {0x2F93C, UNICODE_NORM_QC_NO}, + {0x2F93D, UNICODE_NORM_QC_NO}, + {0x2F93E, UNICODE_NORM_QC_NO}, + {0x2F93F, UNICODE_NORM_QC_NO}, + {0x2F940, UNICODE_NORM_QC_NO}, + {0x2F941, UNICODE_NORM_QC_NO}, + {0x2F942, UNICODE_NORM_QC_NO}, + {0x2F943, UNICODE_NORM_QC_NO}, + {0x2F944, UNICODE_NORM_QC_NO}, + {0x2F945, UNICODE_NORM_QC_NO}, + {0x2F946, UNICODE_NORM_QC_NO}, + {0x2F947, UNICODE_NORM_QC_NO}, + {0x2F948, UNICODE_NORM_QC_NO}, + {0x2F949, UNICODE_NORM_QC_NO}, + {0x2F94A, UNICODE_NORM_QC_NO}, + {0x2F94B, UNICODE_NORM_QC_NO}, + {0x2F94C, UNICODE_NORM_QC_NO}, + {0x2F94D, UNICODE_NORM_QC_NO}, + {0x2F94E, UNICODE_NORM_QC_NO}, + {0x2F94F, UNICODE_NORM_QC_NO}, + {0x2F950, UNICODE_NORM_QC_NO}, + {0x2F951, UNICODE_NORM_QC_NO}, + {0x2F952, UNICODE_NORM_QC_NO}, + {0x2F953, UNICODE_NORM_QC_NO}, + {0x2F954, UNICODE_NORM_QC_NO}, + {0x2F955, UNICODE_NORM_QC_NO}, + {0x2F956, UNICODE_NORM_QC_NO}, + {0x2F957, UNICODE_NORM_QC_NO}, + {0x2F958, UNICODE_NORM_QC_NO}, + {0x2F959, UNICODE_NORM_QC_NO}, + {0x2F95A, UNICODE_NORM_QC_NO}, + {0x2F95B, UNICODE_NORM_QC_NO}, + {0x2F95C, UNICODE_NORM_QC_NO}, + {0x2F95D, UNICODE_NORM_QC_NO}, + {0x2F95E, UNICODE_NORM_QC_NO}, + {0x2F95F, UNICODE_NORM_QC_NO}, + {0x2F960, UNICODE_NORM_QC_NO}, + {0x2F961, UNICODE_NORM_QC_NO}, + {0x2F962, UNICODE_NORM_QC_NO}, + {0x2F963, UNICODE_NORM_QC_NO}, + {0x2F964, UNICODE_NORM_QC_NO}, + {0x2F965, UNICODE_NORM_QC_NO}, + {0x2F966, UNICODE_NORM_QC_NO}, + {0x2F967, UNICODE_NORM_QC_NO}, + {0x2F968, UNICODE_NORM_QC_NO}, + {0x2F969, UNICODE_NORM_QC_NO}, + {0x2F96A, UNICODE_NORM_QC_NO}, + {0x2F96B, UNICODE_NORM_QC_NO}, + {0x2F96C, UNICODE_NORM_QC_NO}, + {0x2F96D, UNICODE_NORM_QC_NO}, + {0x2F96E, UNICODE_NORM_QC_NO}, + {0x2F96F, UNICODE_NORM_QC_NO}, + {0x2F970, UNICODE_NORM_QC_NO}, + {0x2F971, UNICODE_NORM_QC_NO}, + {0x2F972, UNICODE_NORM_QC_NO}, + {0x2F973, UNICODE_NORM_QC_NO}, + {0x2F974, UNICODE_NORM_QC_NO}, + {0x2F975, UNICODE_NORM_QC_NO}, + {0x2F976, UNICODE_NORM_QC_NO}, + {0x2F977, UNICODE_NORM_QC_NO}, + {0x2F978, UNICODE_NORM_QC_NO}, + {0x2F979, UNICODE_NORM_QC_NO}, + {0x2F97A, UNICODE_NORM_QC_NO}, + {0x2F97B, UNICODE_NORM_QC_NO}, + {0x2F97C, UNICODE_NORM_QC_NO}, + {0x2F97D, UNICODE_NORM_QC_NO}, + {0x2F97E, UNICODE_NORM_QC_NO}, + {0x2F97F, UNICODE_NORM_QC_NO}, + {0x2F980, UNICODE_NORM_QC_NO}, + {0x2F981, UNICODE_NORM_QC_NO}, + {0x2F982, UNICODE_NORM_QC_NO}, + {0x2F983, UNICODE_NORM_QC_NO}, + {0x2F984, UNICODE_NORM_QC_NO}, + {0x2F985, UNICODE_NORM_QC_NO}, + {0x2F986, UNICODE_NORM_QC_NO}, + {0x2F987, UNICODE_NORM_QC_NO}, + {0x2F988, UNICODE_NORM_QC_NO}, + {0x2F989, UNICODE_NORM_QC_NO}, + {0x2F98A, UNICODE_NORM_QC_NO}, + {0x2F98B, UNICODE_NORM_QC_NO}, + {0x2F98C, UNICODE_NORM_QC_NO}, + {0x2F98D, UNICODE_NORM_QC_NO}, + {0x2F98E, UNICODE_NORM_QC_NO}, + {0x2F98F, UNICODE_NORM_QC_NO}, + {0x2F990, UNICODE_NORM_QC_NO}, + {0x2F991, UNICODE_NORM_QC_NO}, + {0x2F992, UNICODE_NORM_QC_NO}, + {0x2F993, UNICODE_NORM_QC_NO}, + {0x2F994, UNICODE_NORM_QC_NO}, + {0x2F995, UNICODE_NORM_QC_NO}, + {0x2F996, UNICODE_NORM_QC_NO}, + {0x2F997, UNICODE_NORM_QC_NO}, + {0x2F998, UNICODE_NORM_QC_NO}, + {0x2F999, UNICODE_NORM_QC_NO}, + {0x2F99A, UNICODE_NORM_QC_NO}, + {0x2F99B, UNICODE_NORM_QC_NO}, + {0x2F99C, UNICODE_NORM_QC_NO}, + {0x2F99D, UNICODE_NORM_QC_NO}, + {0x2F99E, UNICODE_NORM_QC_NO}, + {0x2F99F, UNICODE_NORM_QC_NO}, + {0x2F9A0, UNICODE_NORM_QC_NO}, + {0x2F9A1, UNICODE_NORM_QC_NO}, + {0x2F9A2, UNICODE_NORM_QC_NO}, + {0x2F9A3, UNICODE_NORM_QC_NO}, + {0x2F9A4, UNICODE_NORM_QC_NO}, + {0x2F9A5, UNICODE_NORM_QC_NO}, + {0x2F9A6, UNICODE_NORM_QC_NO}, + {0x2F9A7, UNICODE_NORM_QC_NO}, + {0x2F9A8, UNICODE_NORM_QC_NO}, + {0x2F9A9, UNICODE_NORM_QC_NO}, + {0x2F9AA, UNICODE_NORM_QC_NO}, + {0x2F9AB, UNICODE_NORM_QC_NO}, + {0x2F9AC, UNICODE_NORM_QC_NO}, + {0x2F9AD, UNICODE_NORM_QC_NO}, + {0x2F9AE, UNICODE_NORM_QC_NO}, + {0x2F9AF, UNICODE_NORM_QC_NO}, + {0x2F9B0, UNICODE_NORM_QC_NO}, + {0x2F9B1, UNICODE_NORM_QC_NO}, + {0x2F9B2, UNICODE_NORM_QC_NO}, + {0x2F9B3, UNICODE_NORM_QC_NO}, + {0x2F9B4, UNICODE_NORM_QC_NO}, + {0x2F9B5, UNICODE_NORM_QC_NO}, + {0x2F9B6, UNICODE_NORM_QC_NO}, + {0x2F9B7, UNICODE_NORM_QC_NO}, + {0x2F9B8, UNICODE_NORM_QC_NO}, + {0x2F9B9, UNICODE_NORM_QC_NO}, + {0x2F9BA, UNICODE_NORM_QC_NO}, + {0x2F9BB, UNICODE_NORM_QC_NO}, + {0x2F9BC, UNICODE_NORM_QC_NO}, + {0x2F9BD, UNICODE_NORM_QC_NO}, + {0x2F9BE, UNICODE_NORM_QC_NO}, + {0x2F9BF, UNICODE_NORM_QC_NO}, + {0x2F9C0, UNICODE_NORM_QC_NO}, + {0x2F9C1, UNICODE_NORM_QC_NO}, + {0x2F9C2, UNICODE_NORM_QC_NO}, + {0x2F9C3, UNICODE_NORM_QC_NO}, + {0x2F9C4, UNICODE_NORM_QC_NO}, + {0x2F9C5, UNICODE_NORM_QC_NO}, + {0x2F9C6, UNICODE_NORM_QC_NO}, + {0x2F9C7, UNICODE_NORM_QC_NO}, + {0x2F9C8, UNICODE_NORM_QC_NO}, + {0x2F9C9, UNICODE_NORM_QC_NO}, + {0x2F9CA, UNICODE_NORM_QC_NO}, + {0x2F9CB, UNICODE_NORM_QC_NO}, + {0x2F9CC, UNICODE_NORM_QC_NO}, + {0x2F9CD, UNICODE_NORM_QC_NO}, + {0x2F9CE, UNICODE_NORM_QC_NO}, + {0x2F9CF, UNICODE_NORM_QC_NO}, + {0x2F9D0, UNICODE_NORM_QC_NO}, + {0x2F9D1, UNICODE_NORM_QC_NO}, + {0x2F9D2, UNICODE_NORM_QC_NO}, + {0x2F9D3, UNICODE_NORM_QC_NO}, + {0x2F9D4, UNICODE_NORM_QC_NO}, + {0x2F9D5, UNICODE_NORM_QC_NO}, + {0x2F9D6, UNICODE_NORM_QC_NO}, + {0x2F9D7, UNICODE_NORM_QC_NO}, + {0x2F9D8, UNICODE_NORM_QC_NO}, + {0x2F9D9, UNICODE_NORM_QC_NO}, + {0x2F9DA, UNICODE_NORM_QC_NO}, + {0x2F9DB, UNICODE_NORM_QC_NO}, + {0x2F9DC, UNICODE_NORM_QC_NO}, + {0x2F9DD, UNICODE_NORM_QC_NO}, + {0x2F9DE, UNICODE_NORM_QC_NO}, + {0x2F9DF, UNICODE_NORM_QC_NO}, + {0x2F9E0, UNICODE_NORM_QC_NO}, + {0x2F9E1, UNICODE_NORM_QC_NO}, + {0x2F9E2, UNICODE_NORM_QC_NO}, + {0x2F9E3, UNICODE_NORM_QC_NO}, + {0x2F9E4, UNICODE_NORM_QC_NO}, + {0x2F9E5, UNICODE_NORM_QC_NO}, + {0x2F9E6, UNICODE_NORM_QC_NO}, + {0x2F9E7, UNICODE_NORM_QC_NO}, + {0x2F9E8, UNICODE_NORM_QC_NO}, + {0x2F9E9, UNICODE_NORM_QC_NO}, + {0x2F9EA, UNICODE_NORM_QC_NO}, + {0x2F9EB, UNICODE_NORM_QC_NO}, + {0x2F9EC, UNICODE_NORM_QC_NO}, + {0x2F9ED, UNICODE_NORM_QC_NO}, + {0x2F9EE, UNICODE_NORM_QC_NO}, + {0x2F9EF, UNICODE_NORM_QC_NO}, + {0x2F9F0, UNICODE_NORM_QC_NO}, + {0x2F9F1, UNICODE_NORM_QC_NO}, + {0x2F9F2, UNICODE_NORM_QC_NO}, + {0x2F9F3, UNICODE_NORM_QC_NO}, + {0x2F9F4, UNICODE_NORM_QC_NO}, + {0x2F9F5, UNICODE_NORM_QC_NO}, + {0x2F9F6, UNICODE_NORM_QC_NO}, + {0x2F9F7, UNICODE_NORM_QC_NO}, + {0x2F9F8, UNICODE_NORM_QC_NO}, + {0x2F9F9, UNICODE_NORM_QC_NO}, + {0x2F9FA, UNICODE_NORM_QC_NO}, + {0x2F9FB, UNICODE_NORM_QC_NO}, + {0x2F9FC, UNICODE_NORM_QC_NO}, + {0x2F9FD, UNICODE_NORM_QC_NO}, + {0x2F9FE, UNICODE_NORM_QC_NO}, + {0x2F9FF, UNICODE_NORM_QC_NO}, + {0x2FA00, UNICODE_NORM_QC_NO}, + {0x2FA01, UNICODE_NORM_QC_NO}, + {0x2FA02, UNICODE_NORM_QC_NO}, + {0x2FA03, UNICODE_NORM_QC_NO}, + {0x2FA04, UNICODE_NORM_QC_NO}, + {0x2FA05, UNICODE_NORM_QC_NO}, + {0x2FA06, UNICODE_NORM_QC_NO}, + {0x2FA07, UNICODE_NORM_QC_NO}, + {0x2FA08, UNICODE_NORM_QC_NO}, + {0x2FA09, UNICODE_NORM_QC_NO}, + {0x2FA0A, UNICODE_NORM_QC_NO}, + {0x2FA0B, UNICODE_NORM_QC_NO}, + {0x2FA0C, UNICODE_NORM_QC_NO}, + {0x2FA0D, UNICODE_NORM_QC_NO}, + {0x2FA0E, UNICODE_NORM_QC_NO}, + {0x2FA0F, UNICODE_NORM_QC_NO}, + {0x2FA10, UNICODE_NORM_QC_NO}, + {0x2FA11, UNICODE_NORM_QC_NO}, + {0x2FA12, UNICODE_NORM_QC_NO}, + {0x2FA13, UNICODE_NORM_QC_NO}, + {0x2FA14, UNICODE_NORM_QC_NO}, + {0x2FA15, UNICODE_NORM_QC_NO}, + {0x2FA16, UNICODE_NORM_QC_NO}, + {0x2FA17, UNICODE_NORM_QC_NO}, + {0x2FA18, UNICODE_NORM_QC_NO}, + {0x2FA19, UNICODE_NORM_QC_NO}, + {0x2FA1A, UNICODE_NORM_QC_NO}, + {0x2FA1B, UNICODE_NORM_QC_NO}, + {0x2FA1C, UNICODE_NORM_QC_NO}, + {0x2FA1D, UNICODE_NORM_QC_NO}, +}; + +/* Perfect hash function for NFC_QC */ +static int +NFC_QC_hash_func(const void *key) +{ + static const int16 h[2463] = { + 0, -2717, 0, 221, 1293, 223, 1295, 225, + 226, 241, 0, 229, 230, 231, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -386, 0, 0, 0, 0, 0, 0, 0, + -163, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -246, -175, 1260, 0, 0, 0, -174, -173, + 0, -172, 0, 0, 0, 0, 0, 0, + 1049, 0, 300, 301, 1071, 0, 1071, 0, + 1071, 1071, 1057, 0, 0, 0, 0, 1061, + 0, -1053, 1664, 0, 2956, 0, 0, -13, + 0, 0, 0, 0, 2156, 0, 0, 0, + 0, 0, 0, 0, 71, 0, 1082, 0, + 1083, 1083, 0, 1084, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 359, 360, 361, + -1091, 363, -762, -130, -129, -128, -127, -126, + 137, -124, -708, -707, -706, -120, -185, -705, + -117, -184, -1307, -114, -113, -112, -111, 0, + 386, 387, 388, 389, -90, 391, 171, 172, + 394, -94, -183, 397, 398, 399, -98, -225, + 402, -1019, -636, -1019, -225, 407, 408, 409, + 410, 411, 674, 413, -171, -170, -169, 417, + 352, -168, 420, 353, -770, 423, 424, 425, + 426, 427, 428, 32767, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 32767, 32767, 237, 32767, 236, 32767, + 32767, 234, 234, 234, 234, 617, 234, 234, + 234, -2483, 234, -1430, 1526, -1430, 1527, 47, + 48, 471, 230, 32767, 32767, 32767, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, + -159, 227, 227, 227, 227, 227, 227, 227, + 64, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, + 227, 227, 227, 227, 227, 227, 227, 227, + -19, 52, 1487, 227, 227, 227, 53, 54, + 227, 55, 227, 227, 227, 227, 227, 227, + 1276, 227, -989, 32767, 1296, 225, 1296, 225, + 1296, 1296, 1282, 225, 225, 225, 225, 1286, + 225, -828, 1889, 225, 3181, 225, 225, 212, + 225, 225, 225, 225, 2381, 225, 225, 225, + 225, 225, 225, 225, 296, 225, 1307, 225, + 1308, 1308, 225, 1309, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 225, 225, 225, + 225, 225, 225, 225, 225, 584, 585, 586, + -866, 588, -537, 95, 96, 97, 98, 99, + 362, 101, -483, -482, -481, 105, 40, -480, + 108, 41, -1082, 111, 112, 113, 114, 225, + 611, 612, 613, 614, 135, 616, 396, 397, + 619, 131, 42, 622, 623, 624, 127, 0, + 627, -794, -411, -794, 0, 632, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -272, 32767, 32767, 32767, 0, 32767, 32767, 32767, + 32767, 32767, -166, -165, 32767, 32767, 32767, 32767, + -164, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 397, 32767, 396, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 386, + 0, 386, 386, 386, 386, 386, 386, 386, + 223, 386, 386, 386, 32767, 385, 385, 385, + 385, 385, 32767, 384, 32767, 383, 383, 32767, + 382, 382, 32767, 381, 381, 381, 381, 381, + 135, 206, 1641, 381, 32767, 32767, 32767, 32767, + 32767, 32767, -160, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 1148, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 0, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -257, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, -910, -910, 32767, 32767, + 0, 32767, 0, 32767, 0, 32767, 0, 32767, + 147, 32767, 0, 32767, 0, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 143, 32767, 144, 32767, 145, + 32767, 146, 32767, 0, 32767, 148, 32767, 149, + 32767, 32767, 32767, -160, 32767, 32767, 32767, 32767, + 32767, 32767, 15, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 145, 32767, 144, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, -148, 32767, 32767, 32767, 32767, + 32767, 32767, 2009, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 0, 32767, 32767, 135, -918, 32767, + 151, 32767, 32767, 0, 1, 2, 3, 4, + 133, 5, 6, 7, 8, 9, 10, 11, + 32767, 32767, -1248, 32767, 13, 154, 188, 188, + 32767, 32767, 32767, 32767, 32767, 155, 16, 32767, + 32767, 32767, 32767, 32767, 32767, -1853, -1054, 18, + -1052, -1051, -1036, 22, 32767, 157, 32767, 28, + 23, 1077, 673, 25, -2930, 0, 32767, 32767, + 32767, 32767, 32767, 27, 32767, 155, 32767, 154, + 32767, 32767, -62, 28, -42, 30, -1051, 32, + -1050, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 34, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 129, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 672, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 32767, + 32767, 32767, 32767, 32767, -156, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, -155, 32767, 32767, + 32767, 0, 0, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 73, 32767, 32767, 32767, 32767, 74, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 675, + 32767, 32767, 32767, 32767, 32767, 75, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 165, 32767, 32767, 32767, 166, 167, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 170, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 689, 690, 691, 692, 693, 694, 695, + 696, 697, 698, 699, 700, 701, 702, 703, + 704, 705, 706, 707, 708, 709, 710, 711, + 712, 713, 714, 715, 716, 717, 718, 719, + 720, 721, 722, -304, -303, -302, -301, -300, + -299, -298, -297, 930, -295, -294, -293, -292, + -291, -290, -289, -288, -287, -286, -285, -284, + -283, -282, -281, -280, -279, -278, -277, -276, + -275, 753, 754, 755, 646, 757, -712, -1765, + 952, -712, 2244, -712, 2245, 765, 766, 767, + 768, 125, 770, 771, 772, 773, 774, 775, + 603, 777, 778, 779, 780, 781, 782, 783, + 784, 2011, 786, 787, 788, 789, 790, 791, + 792, 793, 794, 795, 796, 797, 798, 799, + 800, 801, 802, 803, 804, 805, 806, 603, + 603, 809, 603, 811, 603, 603, 814, 815, + 816, 817, 435, 819, 820, 821, 3539, 823, + 603, -468, 603, -468, 603, 603, 589, 831, + 603, 603, 603, 835, 836, 837, 838, 839, + 840, 841, 842, 843, 844, 845, 846, 847, + 848, 849, 850, 851, 852, 1239, 854, 855, + 856, 857, 858, 859, 860, 1024, 862, 863, + 864, 865, 866, 867, 868, 869, 870, 871, + 872, 873, 874, 875, 876, 877, 878, 879, + 880, 881, 882, 883, 884, 1131, 1061, -373, + 888, 889, 890, 1065, 1065, 893, 1066, 895, + 896, 897, 898, 899, 900, -148, 902, 603, + 603, -166, 906, -164, 908, -162, -161, -146, + 912, 913, 914, 915, -145, 917, 1971, -745, + 920, -2035, 922, 923, 937, 925, 926, 927, + 928, -1227, 930, 931, 932, 933, 934, 935, + 936, 866, 938, -143, 940, -142, -141, 943, + -140, 32767, 945, 946, 947, 948, 949, 950, + 951, 952, 953, 954, 955, 956, 957, 958, + 959, 960, 961, -65, -64, -63, -62, -61, + -60, -59, -58, 1169, -56, -55, -54, -53, + -52, -51, -50, -49, -48, -47, -46, -45, + -44, -43, -42, -41, -40, -39, -38, -37, + -36, 992, 993, 994, 885, 996, -473, -1526, + 1191, -473, 2483, -473, 2484, 1004, 1005, 1006, + 1007, 364, 1009, 1010, 1011, 1012, 1013, 1014, + 842, 1016, 1017, 1018, 1019, 1020, 1021, 1022, + 1023, 2250, 1025, 1026, 1027, 1028, 1029, 1030, + 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, + 1039, 1040, 1041, 1042, 1043, 1044, 1045, 842, + 842, 1048, 842, 1050, 842, 842, 1053, 1054, + 1055, 1056, 674, 1058, 1059, 1060, 3778, 1062, + 842, -229, 842, -229, 842, 842, 828, 1070, + 842, 842, 842, 1074, 1075, 1076, 1077, 1078, + 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, + 1087, 1088, 1089, 1090, 1091, 1478, 1093, 1094, + 1095, 1096, 1097, 1098, 1099, 1263, 1101, 1102, + 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, + 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, + 1119, 1120, 1121, 1122, 1123, 1370, 1300, -134, + 1127, 1128, 1129, 1304, 1304, 1132, 1305, 1134, + 1135, 1136, 1137, 1138, 1139, 91, 1141, 842, + 842, 73, 1145, 75, 1147, 77, 78, 93, + 1151, 1152, 1153, 1154, 94, 1156, 2210, -506, + 1159, -1796, 1161, 1162, 1176, 1164, 1165, 1166, + 1167, -988, 1169, 1170, 1171, 1172, 1173, 1174, + 1175, 1105, 1177, 96, 1179, 97, 98, 1182, + 99, 1184, 1185, 1186, 1187, 1188, 1189, 1190, + 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, + 1199, 1200, 0, 174, 175, 176, 177, 178, + 179, 180, 181, 1408, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, + 203, 0, 0, 206, 0, 208, 0, 0, + 211, 212, 213, 214, -168, 216, 217, 218, + 2936, 220, 0, -1071, 0, -1071, 0, 0, + -14, 228, 0, 0, 0, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 636, + 251, 252, 253, 254, 255, 256, 257, 421, + 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 528, + 458, -976, 285, 286, 287, 462, 462, 290, + 463, 292, 293, 294, 295, 296, 297, -751, + 299, 0, 0, -769, 303, -767, 305, -765, + -764, -749, 309, 310, 311, 312, -748, 314, + 1368, -1348, 317, -2638, 319, 320, 334, 322, + 323, 324, 325, -1830, 327, 328, 329, 330, + 331, 332, 333, 263, 335, -746, 337, -745, + -744, 340, -743, 342, 343, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 0, 0, 0, 1453, + 0, 1126, 495, 495, 495, 495, 495, 233, + 495, 1080, 1080, 1080, 495, 561, 1082, 495, + 563, 1687, 495, 495, 495, 495, 385, 0, + 0, 0, 0, 480, 0, 221, 221, 0, + 489, 579, 0, 0, 0, 498, 626, 0, + 1422, 1040, 1424, 631, 0, 0, 0, 0, + 0, -262, 0, 585, 585, 585, 0, 66, + 587, 0, 68, 1192, 0, 0, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, 669, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 670, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 142, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1027, 1027, 1027, + 1027, 1027, 1027, 1027, 1027, -199, 1027, 1027, + 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, + 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, + 1027, 1027, 1027, 0, 0, 0, 110, 0, + 1470, 2524, -192, 1473, -1482, 1475, -1481, 0, + 0, 0, 0, 644, 0, 0, 0, 0, + 0, 0, 173, 0, 0, 0, 0, 0, + 0, 0, 0, -1226, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 204, 205, 0, 207, 0, 209, 210, + 0, 0, 0, 0, 383, 0, 0 + }; + + const unsigned char *k = (const unsigned char *) key; + size_t keylen = 4; + uint32 a = 0; + uint32 b = 0; + + while (keylen--) + { + unsigned char c = *k++; + + a = a * 257 + c; + b = b * 17 + c; + } + return h[a % 2463] + h[b % 2463]; +} + +/* Hash lookup information for NFC_QC */ +static const pg_unicode_norminfo UnicodeNormInfo_NFC_QC = { + UnicodeNormProps_NFC_QC, + NFC_QC_hash_func, + 1231 +}; + +static const pg_unicode_normprops UnicodeNormProps_NFKC_QC[] = { + {0x00A0, UNICODE_NORM_QC_NO}, + {0x00A8, UNICODE_NORM_QC_NO}, + {0x00AA, UNICODE_NORM_QC_NO}, + {0x00AF, UNICODE_NORM_QC_NO}, + {0x00B2, UNICODE_NORM_QC_NO}, + {0x00B3, UNICODE_NORM_QC_NO}, + {0x00B4, UNICODE_NORM_QC_NO}, + {0x00B5, UNICODE_NORM_QC_NO}, + {0x00B8, UNICODE_NORM_QC_NO}, + {0x00B9, UNICODE_NORM_QC_NO}, + {0x00BA, UNICODE_NORM_QC_NO}, + {0x00BC, UNICODE_NORM_QC_NO}, + {0x00BD, UNICODE_NORM_QC_NO}, + {0x00BE, UNICODE_NORM_QC_NO}, + {0x0132, UNICODE_NORM_QC_NO}, + {0x0133, UNICODE_NORM_QC_NO}, + {0x013F, UNICODE_NORM_QC_NO}, + {0x0140, UNICODE_NORM_QC_NO}, + {0x0149, UNICODE_NORM_QC_NO}, + {0x017F, UNICODE_NORM_QC_NO}, + {0x01C4, UNICODE_NORM_QC_NO}, + {0x01C5, UNICODE_NORM_QC_NO}, + {0x01C6, UNICODE_NORM_QC_NO}, + {0x01C7, UNICODE_NORM_QC_NO}, + {0x01C8, UNICODE_NORM_QC_NO}, + {0x01C9, UNICODE_NORM_QC_NO}, + {0x01CA, UNICODE_NORM_QC_NO}, + {0x01CB, UNICODE_NORM_QC_NO}, + {0x01CC, UNICODE_NORM_QC_NO}, + {0x01F1, UNICODE_NORM_QC_NO}, + {0x01F2, UNICODE_NORM_QC_NO}, + {0x01F3, UNICODE_NORM_QC_NO}, + {0x02B0, UNICODE_NORM_QC_NO}, + {0x02B1, UNICODE_NORM_QC_NO}, + {0x02B2, UNICODE_NORM_QC_NO}, + {0x02B3, UNICODE_NORM_QC_NO}, + {0x02B4, UNICODE_NORM_QC_NO}, + {0x02B5, UNICODE_NORM_QC_NO}, + {0x02B6, UNICODE_NORM_QC_NO}, + {0x02B7, UNICODE_NORM_QC_NO}, + {0x02B8, UNICODE_NORM_QC_NO}, + {0x02D8, UNICODE_NORM_QC_NO}, + {0x02D9, UNICODE_NORM_QC_NO}, + {0x02DA, UNICODE_NORM_QC_NO}, + {0x02DB, UNICODE_NORM_QC_NO}, + {0x02DC, UNICODE_NORM_QC_NO}, + {0x02DD, UNICODE_NORM_QC_NO}, + {0x02E0, UNICODE_NORM_QC_NO}, + {0x02E1, UNICODE_NORM_QC_NO}, + {0x02E2, UNICODE_NORM_QC_NO}, + {0x02E3, UNICODE_NORM_QC_NO}, + {0x02E4, UNICODE_NORM_QC_NO}, + {0x0300, UNICODE_NORM_QC_MAYBE}, + {0x0301, UNICODE_NORM_QC_MAYBE}, + {0x0302, UNICODE_NORM_QC_MAYBE}, + {0x0303, UNICODE_NORM_QC_MAYBE}, + {0x0304, UNICODE_NORM_QC_MAYBE}, + {0x0306, UNICODE_NORM_QC_MAYBE}, + {0x0307, UNICODE_NORM_QC_MAYBE}, + {0x0308, UNICODE_NORM_QC_MAYBE}, + {0x0309, UNICODE_NORM_QC_MAYBE}, + {0x030A, UNICODE_NORM_QC_MAYBE}, + {0x030B, UNICODE_NORM_QC_MAYBE}, + {0x030C, UNICODE_NORM_QC_MAYBE}, + {0x030F, UNICODE_NORM_QC_MAYBE}, + {0x0311, UNICODE_NORM_QC_MAYBE}, + {0x0313, UNICODE_NORM_QC_MAYBE}, + {0x0314, UNICODE_NORM_QC_MAYBE}, + {0x031B, UNICODE_NORM_QC_MAYBE}, + {0x0323, UNICODE_NORM_QC_MAYBE}, + {0x0324, UNICODE_NORM_QC_MAYBE}, + {0x0325, UNICODE_NORM_QC_MAYBE}, + {0x0326, UNICODE_NORM_QC_MAYBE}, + {0x0327, UNICODE_NORM_QC_MAYBE}, + {0x0328, UNICODE_NORM_QC_MAYBE}, + {0x032D, UNICODE_NORM_QC_MAYBE}, + {0x032E, UNICODE_NORM_QC_MAYBE}, + {0x0330, UNICODE_NORM_QC_MAYBE}, + {0x0331, UNICODE_NORM_QC_MAYBE}, + {0x0338, UNICODE_NORM_QC_MAYBE}, + {0x0340, UNICODE_NORM_QC_NO}, + {0x0341, UNICODE_NORM_QC_NO}, + {0x0342, UNICODE_NORM_QC_MAYBE}, + {0x0343, UNICODE_NORM_QC_NO}, + {0x0344, UNICODE_NORM_QC_NO}, + {0x0345, UNICODE_NORM_QC_MAYBE}, + {0x0374, UNICODE_NORM_QC_NO}, + {0x037A, UNICODE_NORM_QC_NO}, + {0x037E, UNICODE_NORM_QC_NO}, + {0x0384, UNICODE_NORM_QC_NO}, + {0x0385, UNICODE_NORM_QC_NO}, + {0x0387, UNICODE_NORM_QC_NO}, + {0x03D0, UNICODE_NORM_QC_NO}, + {0x03D1, UNICODE_NORM_QC_NO}, + {0x03D2, UNICODE_NORM_QC_NO}, + {0x03D3, UNICODE_NORM_QC_NO}, + {0x03D4, UNICODE_NORM_QC_NO}, + {0x03D5, UNICODE_NORM_QC_NO}, + {0x03D6, UNICODE_NORM_QC_NO}, + {0x03F0, UNICODE_NORM_QC_NO}, + {0x03F1, UNICODE_NORM_QC_NO}, + {0x03F2, UNICODE_NORM_QC_NO}, + {0x03F4, UNICODE_NORM_QC_NO}, + {0x03F5, UNICODE_NORM_QC_NO}, + {0x03F9, UNICODE_NORM_QC_NO}, + {0x0587, UNICODE_NORM_QC_NO}, + {0x0653, UNICODE_NORM_QC_MAYBE}, + {0x0654, UNICODE_NORM_QC_MAYBE}, + {0x0655, UNICODE_NORM_QC_MAYBE}, + {0x0675, UNICODE_NORM_QC_NO}, + {0x0676, UNICODE_NORM_QC_NO}, + {0x0677, UNICODE_NORM_QC_NO}, + {0x0678, UNICODE_NORM_QC_NO}, + {0x093C, UNICODE_NORM_QC_MAYBE}, + {0x0958, UNICODE_NORM_QC_NO}, + {0x0959, UNICODE_NORM_QC_NO}, + {0x095A, UNICODE_NORM_QC_NO}, + {0x095B, UNICODE_NORM_QC_NO}, + {0x095C, UNICODE_NORM_QC_NO}, + {0x095D, UNICODE_NORM_QC_NO}, + {0x095E, UNICODE_NORM_QC_NO}, + {0x095F, UNICODE_NORM_QC_NO}, + {0x09BE, UNICODE_NORM_QC_MAYBE}, + {0x09D7, UNICODE_NORM_QC_MAYBE}, + {0x09DC, UNICODE_NORM_QC_NO}, + {0x09DD, UNICODE_NORM_QC_NO}, + {0x09DF, UNICODE_NORM_QC_NO}, + {0x0A33, UNICODE_NORM_QC_NO}, + {0x0A36, UNICODE_NORM_QC_NO}, + {0x0A59, UNICODE_NORM_QC_NO}, + {0x0A5A, UNICODE_NORM_QC_NO}, + {0x0A5B, UNICODE_NORM_QC_NO}, + {0x0A5E, UNICODE_NORM_QC_NO}, + {0x0B3E, UNICODE_NORM_QC_MAYBE}, + {0x0B56, UNICODE_NORM_QC_MAYBE}, + {0x0B57, UNICODE_NORM_QC_MAYBE}, + {0x0B5C, UNICODE_NORM_QC_NO}, + {0x0B5D, UNICODE_NORM_QC_NO}, + {0x0BBE, UNICODE_NORM_QC_MAYBE}, + {0x0BD7, UNICODE_NORM_QC_MAYBE}, + {0x0C56, UNICODE_NORM_QC_MAYBE}, + {0x0CC2, UNICODE_NORM_QC_MAYBE}, + {0x0CD5, UNICODE_NORM_QC_MAYBE}, + {0x0CD6, UNICODE_NORM_QC_MAYBE}, + {0x0D3E, UNICODE_NORM_QC_MAYBE}, + {0x0D57, UNICODE_NORM_QC_MAYBE}, + {0x0DCA, UNICODE_NORM_QC_MAYBE}, + {0x0DCF, UNICODE_NORM_QC_MAYBE}, + {0x0DDF, UNICODE_NORM_QC_MAYBE}, + {0x0E33, UNICODE_NORM_QC_NO}, + {0x0EB3, UNICODE_NORM_QC_NO}, + {0x0EDC, UNICODE_NORM_QC_NO}, + {0x0EDD, UNICODE_NORM_QC_NO}, + {0x0F0C, UNICODE_NORM_QC_NO}, + {0x0F43, UNICODE_NORM_QC_NO}, + {0x0F4D, UNICODE_NORM_QC_NO}, + {0x0F52, UNICODE_NORM_QC_NO}, + {0x0F57, UNICODE_NORM_QC_NO}, + {0x0F5C, UNICODE_NORM_QC_NO}, + {0x0F69, UNICODE_NORM_QC_NO}, + {0x0F73, UNICODE_NORM_QC_NO}, + {0x0F75, UNICODE_NORM_QC_NO}, + {0x0F76, UNICODE_NORM_QC_NO}, + {0x0F77, UNICODE_NORM_QC_NO}, + {0x0F78, UNICODE_NORM_QC_NO}, + {0x0F79, UNICODE_NORM_QC_NO}, + {0x0F81, UNICODE_NORM_QC_NO}, + {0x0F93, UNICODE_NORM_QC_NO}, + {0x0F9D, UNICODE_NORM_QC_NO}, + {0x0FA2, UNICODE_NORM_QC_NO}, + {0x0FA7, UNICODE_NORM_QC_NO}, + {0x0FAC, UNICODE_NORM_QC_NO}, + {0x0FB9, UNICODE_NORM_QC_NO}, + {0x102E, UNICODE_NORM_QC_MAYBE}, + {0x10FC, UNICODE_NORM_QC_NO}, + {0x1161, UNICODE_NORM_QC_MAYBE}, + {0x1162, UNICODE_NORM_QC_MAYBE}, + {0x1163, UNICODE_NORM_QC_MAYBE}, + {0x1164, UNICODE_NORM_QC_MAYBE}, + {0x1165, UNICODE_NORM_QC_MAYBE}, + {0x1166, UNICODE_NORM_QC_MAYBE}, + {0x1167, UNICODE_NORM_QC_MAYBE}, + {0x1168, UNICODE_NORM_QC_MAYBE}, + {0x1169, UNICODE_NORM_QC_MAYBE}, + {0x116A, UNICODE_NORM_QC_MAYBE}, + {0x116B, UNICODE_NORM_QC_MAYBE}, + {0x116C, UNICODE_NORM_QC_MAYBE}, + {0x116D, UNICODE_NORM_QC_MAYBE}, + {0x116E, UNICODE_NORM_QC_MAYBE}, + {0x116F, UNICODE_NORM_QC_MAYBE}, + {0x1170, UNICODE_NORM_QC_MAYBE}, + {0x1171, UNICODE_NORM_QC_MAYBE}, + {0x1172, UNICODE_NORM_QC_MAYBE}, + {0x1173, UNICODE_NORM_QC_MAYBE}, + {0x1174, UNICODE_NORM_QC_MAYBE}, + {0x1175, UNICODE_NORM_QC_MAYBE}, + {0x11A8, UNICODE_NORM_QC_MAYBE}, + {0x11A9, UNICODE_NORM_QC_MAYBE}, + {0x11AA, UNICODE_NORM_QC_MAYBE}, + {0x11AB, UNICODE_NORM_QC_MAYBE}, + {0x11AC, UNICODE_NORM_QC_MAYBE}, + {0x11AD, UNICODE_NORM_QC_MAYBE}, + {0x11AE, UNICODE_NORM_QC_MAYBE}, + {0x11AF, UNICODE_NORM_QC_MAYBE}, + {0x11B0, UNICODE_NORM_QC_MAYBE}, + {0x11B1, UNICODE_NORM_QC_MAYBE}, + {0x11B2, UNICODE_NORM_QC_MAYBE}, + {0x11B3, UNICODE_NORM_QC_MAYBE}, + {0x11B4, UNICODE_NORM_QC_MAYBE}, + {0x11B5, UNICODE_NORM_QC_MAYBE}, + {0x11B6, UNICODE_NORM_QC_MAYBE}, + {0x11B7, UNICODE_NORM_QC_MAYBE}, + {0x11B8, UNICODE_NORM_QC_MAYBE}, + {0x11B9, UNICODE_NORM_QC_MAYBE}, + {0x11BA, UNICODE_NORM_QC_MAYBE}, + {0x11BB, UNICODE_NORM_QC_MAYBE}, + {0x11BC, UNICODE_NORM_QC_MAYBE}, + {0x11BD, UNICODE_NORM_QC_MAYBE}, + {0x11BE, UNICODE_NORM_QC_MAYBE}, + {0x11BF, UNICODE_NORM_QC_MAYBE}, + {0x11C0, UNICODE_NORM_QC_MAYBE}, + {0x11C1, UNICODE_NORM_QC_MAYBE}, + {0x11C2, UNICODE_NORM_QC_MAYBE}, + {0x1B35, UNICODE_NORM_QC_MAYBE}, + {0x1D2C, UNICODE_NORM_QC_NO}, + {0x1D2D, UNICODE_NORM_QC_NO}, + {0x1D2E, UNICODE_NORM_QC_NO}, + {0x1D30, UNICODE_NORM_QC_NO}, + {0x1D31, UNICODE_NORM_QC_NO}, + {0x1D32, UNICODE_NORM_QC_NO}, + {0x1D33, UNICODE_NORM_QC_NO}, + {0x1D34, UNICODE_NORM_QC_NO}, + {0x1D35, UNICODE_NORM_QC_NO}, + {0x1D36, UNICODE_NORM_QC_NO}, + {0x1D37, UNICODE_NORM_QC_NO}, + {0x1D38, UNICODE_NORM_QC_NO}, + {0x1D39, UNICODE_NORM_QC_NO}, + {0x1D3A, UNICODE_NORM_QC_NO}, + {0x1D3C, UNICODE_NORM_QC_NO}, + {0x1D3D, UNICODE_NORM_QC_NO}, + {0x1D3E, UNICODE_NORM_QC_NO}, + {0x1D3F, UNICODE_NORM_QC_NO}, + {0x1D40, UNICODE_NORM_QC_NO}, + {0x1D41, UNICODE_NORM_QC_NO}, + {0x1D42, UNICODE_NORM_QC_NO}, + {0x1D43, UNICODE_NORM_QC_NO}, + {0x1D44, UNICODE_NORM_QC_NO}, + {0x1D45, UNICODE_NORM_QC_NO}, + {0x1D46, UNICODE_NORM_QC_NO}, + {0x1D47, UNICODE_NORM_QC_NO}, + {0x1D48, UNICODE_NORM_QC_NO}, + {0x1D49, UNICODE_NORM_QC_NO}, + {0x1D4A, UNICODE_NORM_QC_NO}, + {0x1D4B, UNICODE_NORM_QC_NO}, + {0x1D4C, UNICODE_NORM_QC_NO}, + {0x1D4D, UNICODE_NORM_QC_NO}, + {0x1D4F, UNICODE_NORM_QC_NO}, + {0x1D50, UNICODE_NORM_QC_NO}, + {0x1D51, UNICODE_NORM_QC_NO}, + {0x1D52, UNICODE_NORM_QC_NO}, + {0x1D53, UNICODE_NORM_QC_NO}, + {0x1D54, UNICODE_NORM_QC_NO}, + {0x1D55, UNICODE_NORM_QC_NO}, + {0x1D56, UNICODE_NORM_QC_NO}, + {0x1D57, UNICODE_NORM_QC_NO}, + {0x1D58, UNICODE_NORM_QC_NO}, + {0x1D59, UNICODE_NORM_QC_NO}, + {0x1D5A, UNICODE_NORM_QC_NO}, + {0x1D5B, UNICODE_NORM_QC_NO}, + {0x1D5C, UNICODE_NORM_QC_NO}, + {0x1D5D, UNICODE_NORM_QC_NO}, + {0x1D5E, UNICODE_NORM_QC_NO}, + {0x1D5F, UNICODE_NORM_QC_NO}, + {0x1D60, UNICODE_NORM_QC_NO}, + {0x1D61, UNICODE_NORM_QC_NO}, + {0x1D62, UNICODE_NORM_QC_NO}, + {0x1D63, UNICODE_NORM_QC_NO}, + {0x1D64, UNICODE_NORM_QC_NO}, + {0x1D65, UNICODE_NORM_QC_NO}, + {0x1D66, UNICODE_NORM_QC_NO}, + {0x1D67, UNICODE_NORM_QC_NO}, + {0x1D68, UNICODE_NORM_QC_NO}, + {0x1D69, UNICODE_NORM_QC_NO}, + {0x1D6A, UNICODE_NORM_QC_NO}, + {0x1D78, UNICODE_NORM_QC_NO}, + {0x1D9B, UNICODE_NORM_QC_NO}, + {0x1D9C, UNICODE_NORM_QC_NO}, + {0x1D9D, UNICODE_NORM_QC_NO}, + {0x1D9E, UNICODE_NORM_QC_NO}, + {0x1D9F, UNICODE_NORM_QC_NO}, + {0x1DA0, UNICODE_NORM_QC_NO}, + {0x1DA1, UNICODE_NORM_QC_NO}, + {0x1DA2, UNICODE_NORM_QC_NO}, + {0x1DA3, UNICODE_NORM_QC_NO}, + {0x1DA4, UNICODE_NORM_QC_NO}, + {0x1DA5, UNICODE_NORM_QC_NO}, + {0x1DA6, UNICODE_NORM_QC_NO}, + {0x1DA7, UNICODE_NORM_QC_NO}, + {0x1DA8, UNICODE_NORM_QC_NO}, + {0x1DA9, UNICODE_NORM_QC_NO}, + {0x1DAA, UNICODE_NORM_QC_NO}, + {0x1DAB, UNICODE_NORM_QC_NO}, + {0x1DAC, UNICODE_NORM_QC_NO}, + {0x1DAD, UNICODE_NORM_QC_NO}, + {0x1DAE, UNICODE_NORM_QC_NO}, + {0x1DAF, UNICODE_NORM_QC_NO}, + {0x1DB0, UNICODE_NORM_QC_NO}, + {0x1DB1, UNICODE_NORM_QC_NO}, + {0x1DB2, UNICODE_NORM_QC_NO}, + {0x1DB3, UNICODE_NORM_QC_NO}, + {0x1DB4, UNICODE_NORM_QC_NO}, + {0x1DB5, UNICODE_NORM_QC_NO}, + {0x1DB6, UNICODE_NORM_QC_NO}, + {0x1DB7, UNICODE_NORM_QC_NO}, + {0x1DB8, UNICODE_NORM_QC_NO}, + {0x1DB9, UNICODE_NORM_QC_NO}, + {0x1DBA, UNICODE_NORM_QC_NO}, + {0x1DBB, UNICODE_NORM_QC_NO}, + {0x1DBC, UNICODE_NORM_QC_NO}, + {0x1DBD, UNICODE_NORM_QC_NO}, + {0x1DBE, UNICODE_NORM_QC_NO}, + {0x1DBF, UNICODE_NORM_QC_NO}, + {0x1E9A, UNICODE_NORM_QC_NO}, + {0x1E9B, UNICODE_NORM_QC_NO}, + {0x1F71, UNICODE_NORM_QC_NO}, + {0x1F73, UNICODE_NORM_QC_NO}, + {0x1F75, UNICODE_NORM_QC_NO}, + {0x1F77, UNICODE_NORM_QC_NO}, + {0x1F79, UNICODE_NORM_QC_NO}, + {0x1F7B, UNICODE_NORM_QC_NO}, + {0x1F7D, UNICODE_NORM_QC_NO}, + {0x1FBB, UNICODE_NORM_QC_NO}, + {0x1FBD, UNICODE_NORM_QC_NO}, + {0x1FBE, UNICODE_NORM_QC_NO}, + {0x1FBF, UNICODE_NORM_QC_NO}, + {0x1FC0, UNICODE_NORM_QC_NO}, + {0x1FC1, UNICODE_NORM_QC_NO}, + {0x1FC9, UNICODE_NORM_QC_NO}, + {0x1FCB, UNICODE_NORM_QC_NO}, + {0x1FCD, UNICODE_NORM_QC_NO}, + {0x1FCE, UNICODE_NORM_QC_NO}, + {0x1FCF, UNICODE_NORM_QC_NO}, + {0x1FD3, UNICODE_NORM_QC_NO}, + {0x1FDB, UNICODE_NORM_QC_NO}, + {0x1FDD, UNICODE_NORM_QC_NO}, + {0x1FDE, UNICODE_NORM_QC_NO}, + {0x1FDF, UNICODE_NORM_QC_NO}, + {0x1FE3, UNICODE_NORM_QC_NO}, + {0x1FEB, UNICODE_NORM_QC_NO}, + {0x1FED, UNICODE_NORM_QC_NO}, + {0x1FEE, UNICODE_NORM_QC_NO}, + {0x1FEF, UNICODE_NORM_QC_NO}, + {0x1FF9, UNICODE_NORM_QC_NO}, + {0x1FFB, UNICODE_NORM_QC_NO}, + {0x1FFD, UNICODE_NORM_QC_NO}, + {0x1FFE, UNICODE_NORM_QC_NO}, + {0x2000, UNICODE_NORM_QC_NO}, + {0x2001, UNICODE_NORM_QC_NO}, + {0x2002, UNICODE_NORM_QC_NO}, + {0x2003, UNICODE_NORM_QC_NO}, + {0x2004, UNICODE_NORM_QC_NO}, + {0x2005, UNICODE_NORM_QC_NO}, + {0x2006, UNICODE_NORM_QC_NO}, + {0x2007, UNICODE_NORM_QC_NO}, + {0x2008, UNICODE_NORM_QC_NO}, + {0x2009, UNICODE_NORM_QC_NO}, + {0x200A, UNICODE_NORM_QC_NO}, + {0x2011, UNICODE_NORM_QC_NO}, + {0x2017, UNICODE_NORM_QC_NO}, + {0x2024, UNICODE_NORM_QC_NO}, + {0x2025, UNICODE_NORM_QC_NO}, + {0x2026, UNICODE_NORM_QC_NO}, + {0x202F, UNICODE_NORM_QC_NO}, + {0x2033, UNICODE_NORM_QC_NO}, + {0x2034, UNICODE_NORM_QC_NO}, + {0x2036, UNICODE_NORM_QC_NO}, + {0x2037, UNICODE_NORM_QC_NO}, + {0x203C, UNICODE_NORM_QC_NO}, + {0x203E, UNICODE_NORM_QC_NO}, + {0x2047, UNICODE_NORM_QC_NO}, + {0x2048, UNICODE_NORM_QC_NO}, + {0x2049, UNICODE_NORM_QC_NO}, + {0x2057, UNICODE_NORM_QC_NO}, + {0x205F, UNICODE_NORM_QC_NO}, + {0x2070, UNICODE_NORM_QC_NO}, + {0x2071, UNICODE_NORM_QC_NO}, + {0x2074, UNICODE_NORM_QC_NO}, + {0x2075, UNICODE_NORM_QC_NO}, + {0x2076, UNICODE_NORM_QC_NO}, + {0x2077, UNICODE_NORM_QC_NO}, + {0x2078, UNICODE_NORM_QC_NO}, + {0x2079, UNICODE_NORM_QC_NO}, + {0x207A, UNICODE_NORM_QC_NO}, + {0x207B, UNICODE_NORM_QC_NO}, + {0x207C, UNICODE_NORM_QC_NO}, + {0x207D, UNICODE_NORM_QC_NO}, + {0x207E, UNICODE_NORM_QC_NO}, + {0x207F, UNICODE_NORM_QC_NO}, + {0x2080, UNICODE_NORM_QC_NO}, + {0x2081, UNICODE_NORM_QC_NO}, + {0x2082, UNICODE_NORM_QC_NO}, + {0x2083, UNICODE_NORM_QC_NO}, + {0x2084, UNICODE_NORM_QC_NO}, + {0x2085, UNICODE_NORM_QC_NO}, + {0x2086, UNICODE_NORM_QC_NO}, + {0x2087, UNICODE_NORM_QC_NO}, + {0x2088, UNICODE_NORM_QC_NO}, + {0x2089, UNICODE_NORM_QC_NO}, + {0x208A, UNICODE_NORM_QC_NO}, + {0x208B, UNICODE_NORM_QC_NO}, + {0x208C, UNICODE_NORM_QC_NO}, + {0x208D, UNICODE_NORM_QC_NO}, + {0x208E, UNICODE_NORM_QC_NO}, + {0x2090, UNICODE_NORM_QC_NO}, + {0x2091, UNICODE_NORM_QC_NO}, + {0x2092, UNICODE_NORM_QC_NO}, + {0x2093, UNICODE_NORM_QC_NO}, + {0x2094, UNICODE_NORM_QC_NO}, + {0x2095, UNICODE_NORM_QC_NO}, + {0x2096, UNICODE_NORM_QC_NO}, + {0x2097, UNICODE_NORM_QC_NO}, + {0x2098, UNICODE_NORM_QC_NO}, + {0x2099, UNICODE_NORM_QC_NO}, + {0x209A, UNICODE_NORM_QC_NO}, + {0x209B, UNICODE_NORM_QC_NO}, + {0x209C, UNICODE_NORM_QC_NO}, + {0x20A8, UNICODE_NORM_QC_NO}, + {0x2100, UNICODE_NORM_QC_NO}, + {0x2101, UNICODE_NORM_QC_NO}, + {0x2102, UNICODE_NORM_QC_NO}, + {0x2103, UNICODE_NORM_QC_NO}, + {0x2105, UNICODE_NORM_QC_NO}, + {0x2106, UNICODE_NORM_QC_NO}, + {0x2107, UNICODE_NORM_QC_NO}, + {0x2109, UNICODE_NORM_QC_NO}, + {0x210A, UNICODE_NORM_QC_NO}, + {0x210B, UNICODE_NORM_QC_NO}, + {0x210C, UNICODE_NORM_QC_NO}, + {0x210D, UNICODE_NORM_QC_NO}, + {0x210E, UNICODE_NORM_QC_NO}, + {0x210F, UNICODE_NORM_QC_NO}, + {0x2110, UNICODE_NORM_QC_NO}, + {0x2111, UNICODE_NORM_QC_NO}, + {0x2112, UNICODE_NORM_QC_NO}, + {0x2113, UNICODE_NORM_QC_NO}, + {0x2115, UNICODE_NORM_QC_NO}, + {0x2116, UNICODE_NORM_QC_NO}, + {0x2119, UNICODE_NORM_QC_NO}, + {0x211A, UNICODE_NORM_QC_NO}, + {0x211B, UNICODE_NORM_QC_NO}, + {0x211C, UNICODE_NORM_QC_NO}, + {0x211D, UNICODE_NORM_QC_NO}, + {0x2120, UNICODE_NORM_QC_NO}, + {0x2121, UNICODE_NORM_QC_NO}, + {0x2122, UNICODE_NORM_QC_NO}, + {0x2124, UNICODE_NORM_QC_NO}, + {0x2126, UNICODE_NORM_QC_NO}, + {0x2128, UNICODE_NORM_QC_NO}, + {0x212A, UNICODE_NORM_QC_NO}, + {0x212B, UNICODE_NORM_QC_NO}, + {0x212C, UNICODE_NORM_QC_NO}, + {0x212D, UNICODE_NORM_QC_NO}, + {0x212F, UNICODE_NORM_QC_NO}, + {0x2130, UNICODE_NORM_QC_NO}, + {0x2131, UNICODE_NORM_QC_NO}, + {0x2133, UNICODE_NORM_QC_NO}, + {0x2134, UNICODE_NORM_QC_NO}, + {0x2135, UNICODE_NORM_QC_NO}, + {0x2136, UNICODE_NORM_QC_NO}, + {0x2137, UNICODE_NORM_QC_NO}, + {0x2138, UNICODE_NORM_QC_NO}, + {0x2139, UNICODE_NORM_QC_NO}, + {0x213B, UNICODE_NORM_QC_NO}, + {0x213C, UNICODE_NORM_QC_NO}, + {0x213D, UNICODE_NORM_QC_NO}, + {0x213E, UNICODE_NORM_QC_NO}, + {0x213F, UNICODE_NORM_QC_NO}, + {0x2140, UNICODE_NORM_QC_NO}, + {0x2145, UNICODE_NORM_QC_NO}, + {0x2146, UNICODE_NORM_QC_NO}, + {0x2147, UNICODE_NORM_QC_NO}, + {0x2148, UNICODE_NORM_QC_NO}, + {0x2149, UNICODE_NORM_QC_NO}, + {0x2150, UNICODE_NORM_QC_NO}, + {0x2151, UNICODE_NORM_QC_NO}, + {0x2152, UNICODE_NORM_QC_NO}, + {0x2153, UNICODE_NORM_QC_NO}, + {0x2154, UNICODE_NORM_QC_NO}, + {0x2155, UNICODE_NORM_QC_NO}, + {0x2156, UNICODE_NORM_QC_NO}, + {0x2157, UNICODE_NORM_QC_NO}, + {0x2158, UNICODE_NORM_QC_NO}, + {0x2159, UNICODE_NORM_QC_NO}, + {0x215A, UNICODE_NORM_QC_NO}, + {0x215B, UNICODE_NORM_QC_NO}, + {0x215C, UNICODE_NORM_QC_NO}, + {0x215D, UNICODE_NORM_QC_NO}, + {0x215E, UNICODE_NORM_QC_NO}, + {0x215F, UNICODE_NORM_QC_NO}, + {0x2160, UNICODE_NORM_QC_NO}, + {0x2161, UNICODE_NORM_QC_NO}, + {0x2162, UNICODE_NORM_QC_NO}, + {0x2163, UNICODE_NORM_QC_NO}, + {0x2164, UNICODE_NORM_QC_NO}, + {0x2165, UNICODE_NORM_QC_NO}, + {0x2166, UNICODE_NORM_QC_NO}, + {0x2167, UNICODE_NORM_QC_NO}, + {0x2168, UNICODE_NORM_QC_NO}, + {0x2169, UNICODE_NORM_QC_NO}, + {0x216A, UNICODE_NORM_QC_NO}, + {0x216B, UNICODE_NORM_QC_NO}, + {0x216C, UNICODE_NORM_QC_NO}, + {0x216D, UNICODE_NORM_QC_NO}, + {0x216E, UNICODE_NORM_QC_NO}, + {0x216F, UNICODE_NORM_QC_NO}, + {0x2170, UNICODE_NORM_QC_NO}, + {0x2171, UNICODE_NORM_QC_NO}, + {0x2172, UNICODE_NORM_QC_NO}, + {0x2173, UNICODE_NORM_QC_NO}, + {0x2174, UNICODE_NORM_QC_NO}, + {0x2175, UNICODE_NORM_QC_NO}, + {0x2176, UNICODE_NORM_QC_NO}, + {0x2177, UNICODE_NORM_QC_NO}, + {0x2178, UNICODE_NORM_QC_NO}, + {0x2179, UNICODE_NORM_QC_NO}, + {0x217A, UNICODE_NORM_QC_NO}, + {0x217B, UNICODE_NORM_QC_NO}, + {0x217C, UNICODE_NORM_QC_NO}, + {0x217D, UNICODE_NORM_QC_NO}, + {0x217E, UNICODE_NORM_QC_NO}, + {0x217F, UNICODE_NORM_QC_NO}, + {0x2189, UNICODE_NORM_QC_NO}, + {0x222C, UNICODE_NORM_QC_NO}, + {0x222D, UNICODE_NORM_QC_NO}, + {0x222F, UNICODE_NORM_QC_NO}, + {0x2230, UNICODE_NORM_QC_NO}, + {0x2329, UNICODE_NORM_QC_NO}, + {0x232A, UNICODE_NORM_QC_NO}, + {0x2460, UNICODE_NORM_QC_NO}, + {0x2461, UNICODE_NORM_QC_NO}, + {0x2462, UNICODE_NORM_QC_NO}, + {0x2463, UNICODE_NORM_QC_NO}, + {0x2464, UNICODE_NORM_QC_NO}, + {0x2465, UNICODE_NORM_QC_NO}, + {0x2466, UNICODE_NORM_QC_NO}, + {0x2467, UNICODE_NORM_QC_NO}, + {0x2468, UNICODE_NORM_QC_NO}, + {0x2469, UNICODE_NORM_QC_NO}, + {0x246A, UNICODE_NORM_QC_NO}, + {0x246B, UNICODE_NORM_QC_NO}, + {0x246C, UNICODE_NORM_QC_NO}, + {0x246D, UNICODE_NORM_QC_NO}, + {0x246E, UNICODE_NORM_QC_NO}, + {0x246F, UNICODE_NORM_QC_NO}, + {0x2470, UNICODE_NORM_QC_NO}, + {0x2471, UNICODE_NORM_QC_NO}, + {0x2472, UNICODE_NORM_QC_NO}, + {0x2473, UNICODE_NORM_QC_NO}, + {0x2474, UNICODE_NORM_QC_NO}, + {0x2475, UNICODE_NORM_QC_NO}, + {0x2476, UNICODE_NORM_QC_NO}, + {0x2477, UNICODE_NORM_QC_NO}, + {0x2478, UNICODE_NORM_QC_NO}, + {0x2479, UNICODE_NORM_QC_NO}, + {0x247A, UNICODE_NORM_QC_NO}, + {0x247B, UNICODE_NORM_QC_NO}, + {0x247C, UNICODE_NORM_QC_NO}, + {0x247D, UNICODE_NORM_QC_NO}, + {0x247E, UNICODE_NORM_QC_NO}, + {0x247F, UNICODE_NORM_QC_NO}, + {0x2480, UNICODE_NORM_QC_NO}, + {0x2481, UNICODE_NORM_QC_NO}, + {0x2482, UNICODE_NORM_QC_NO}, + {0x2483, UNICODE_NORM_QC_NO}, + {0x2484, UNICODE_NORM_QC_NO}, + {0x2485, UNICODE_NORM_QC_NO}, + {0x2486, UNICODE_NORM_QC_NO}, + {0x2487, UNICODE_NORM_QC_NO}, + {0x2488, UNICODE_NORM_QC_NO}, + {0x2489, UNICODE_NORM_QC_NO}, + {0x248A, UNICODE_NORM_QC_NO}, + {0x248B, UNICODE_NORM_QC_NO}, + {0x248C, UNICODE_NORM_QC_NO}, + {0x248D, UNICODE_NORM_QC_NO}, + {0x248E, UNICODE_NORM_QC_NO}, + {0x248F, UNICODE_NORM_QC_NO}, + {0x2490, UNICODE_NORM_QC_NO}, + {0x2491, UNICODE_NORM_QC_NO}, + {0x2492, UNICODE_NORM_QC_NO}, + {0x2493, UNICODE_NORM_QC_NO}, + {0x2494, UNICODE_NORM_QC_NO}, + {0x2495, UNICODE_NORM_QC_NO}, + {0x2496, UNICODE_NORM_QC_NO}, + {0x2497, UNICODE_NORM_QC_NO}, + {0x2498, UNICODE_NORM_QC_NO}, + {0x2499, UNICODE_NORM_QC_NO}, + {0x249A, UNICODE_NORM_QC_NO}, + {0x249B, UNICODE_NORM_QC_NO}, + {0x249C, UNICODE_NORM_QC_NO}, + {0x249D, UNICODE_NORM_QC_NO}, + {0x249E, UNICODE_NORM_QC_NO}, + {0x249F, UNICODE_NORM_QC_NO}, + {0x24A0, UNICODE_NORM_QC_NO}, + {0x24A1, UNICODE_NORM_QC_NO}, + {0x24A2, UNICODE_NORM_QC_NO}, + {0x24A3, UNICODE_NORM_QC_NO}, + {0x24A4, UNICODE_NORM_QC_NO}, + {0x24A5, UNICODE_NORM_QC_NO}, + {0x24A6, UNICODE_NORM_QC_NO}, + {0x24A7, UNICODE_NORM_QC_NO}, + {0x24A8, UNICODE_NORM_QC_NO}, + {0x24A9, UNICODE_NORM_QC_NO}, + {0x24AA, UNICODE_NORM_QC_NO}, + {0x24AB, UNICODE_NORM_QC_NO}, + {0x24AC, UNICODE_NORM_QC_NO}, + {0x24AD, UNICODE_NORM_QC_NO}, + {0x24AE, UNICODE_NORM_QC_NO}, + {0x24AF, UNICODE_NORM_QC_NO}, + {0x24B0, UNICODE_NORM_QC_NO}, + {0x24B1, UNICODE_NORM_QC_NO}, + {0x24B2, UNICODE_NORM_QC_NO}, + {0x24B3, UNICODE_NORM_QC_NO}, + {0x24B4, UNICODE_NORM_QC_NO}, + {0x24B5, UNICODE_NORM_QC_NO}, + {0x24B6, UNICODE_NORM_QC_NO}, + {0x24B7, UNICODE_NORM_QC_NO}, + {0x24B8, UNICODE_NORM_QC_NO}, + {0x24B9, UNICODE_NORM_QC_NO}, + {0x24BA, UNICODE_NORM_QC_NO}, + {0x24BB, UNICODE_NORM_QC_NO}, + {0x24BC, UNICODE_NORM_QC_NO}, + {0x24BD, UNICODE_NORM_QC_NO}, + {0x24BE, UNICODE_NORM_QC_NO}, + {0x24BF, UNICODE_NORM_QC_NO}, + {0x24C0, UNICODE_NORM_QC_NO}, + {0x24C1, UNICODE_NORM_QC_NO}, + {0x24C2, UNICODE_NORM_QC_NO}, + {0x24C3, UNICODE_NORM_QC_NO}, + {0x24C4, UNICODE_NORM_QC_NO}, + {0x24C5, UNICODE_NORM_QC_NO}, + {0x24C6, UNICODE_NORM_QC_NO}, + {0x24C7, UNICODE_NORM_QC_NO}, + {0x24C8, UNICODE_NORM_QC_NO}, + {0x24C9, UNICODE_NORM_QC_NO}, + {0x24CA, UNICODE_NORM_QC_NO}, + {0x24CB, UNICODE_NORM_QC_NO}, + {0x24CC, UNICODE_NORM_QC_NO}, + {0x24CD, UNICODE_NORM_QC_NO}, + {0x24CE, UNICODE_NORM_QC_NO}, + {0x24CF, UNICODE_NORM_QC_NO}, + {0x24D0, UNICODE_NORM_QC_NO}, + {0x24D1, UNICODE_NORM_QC_NO}, + {0x24D2, UNICODE_NORM_QC_NO}, + {0x24D3, UNICODE_NORM_QC_NO}, + {0x24D4, UNICODE_NORM_QC_NO}, + {0x24D5, UNICODE_NORM_QC_NO}, + {0x24D6, UNICODE_NORM_QC_NO}, + {0x24D7, UNICODE_NORM_QC_NO}, + {0x24D8, UNICODE_NORM_QC_NO}, + {0x24D9, UNICODE_NORM_QC_NO}, + {0x24DA, UNICODE_NORM_QC_NO}, + {0x24DB, UNICODE_NORM_QC_NO}, + {0x24DC, UNICODE_NORM_QC_NO}, + {0x24DD, UNICODE_NORM_QC_NO}, + {0x24DE, UNICODE_NORM_QC_NO}, + {0x24DF, UNICODE_NORM_QC_NO}, + {0x24E0, UNICODE_NORM_QC_NO}, + {0x24E1, UNICODE_NORM_QC_NO}, + {0x24E2, UNICODE_NORM_QC_NO}, + {0x24E3, UNICODE_NORM_QC_NO}, + {0x24E4, UNICODE_NORM_QC_NO}, + {0x24E5, UNICODE_NORM_QC_NO}, + {0x24E6, UNICODE_NORM_QC_NO}, + {0x24E7, UNICODE_NORM_QC_NO}, + {0x24E8, UNICODE_NORM_QC_NO}, + {0x24E9, UNICODE_NORM_QC_NO}, + {0x24EA, UNICODE_NORM_QC_NO}, + {0x2A0C, UNICODE_NORM_QC_NO}, + {0x2A74, UNICODE_NORM_QC_NO}, + {0x2A75, UNICODE_NORM_QC_NO}, + {0x2A76, UNICODE_NORM_QC_NO}, + {0x2ADC, UNICODE_NORM_QC_NO}, + {0x2C7C, UNICODE_NORM_QC_NO}, + {0x2C7D, UNICODE_NORM_QC_NO}, + {0x2D6F, UNICODE_NORM_QC_NO}, + {0x2E9F, UNICODE_NORM_QC_NO}, + {0x2EF3, UNICODE_NORM_QC_NO}, + {0x2F00, UNICODE_NORM_QC_NO}, + {0x2F01, UNICODE_NORM_QC_NO}, + {0x2F02, UNICODE_NORM_QC_NO}, + {0x2F03, UNICODE_NORM_QC_NO}, + {0x2F04, UNICODE_NORM_QC_NO}, + {0x2F05, UNICODE_NORM_QC_NO}, + {0x2F06, UNICODE_NORM_QC_NO}, + {0x2F07, UNICODE_NORM_QC_NO}, + {0x2F08, UNICODE_NORM_QC_NO}, + {0x2F09, UNICODE_NORM_QC_NO}, + {0x2F0A, UNICODE_NORM_QC_NO}, + {0x2F0B, UNICODE_NORM_QC_NO}, + {0x2F0C, UNICODE_NORM_QC_NO}, + {0x2F0D, UNICODE_NORM_QC_NO}, + {0x2F0E, UNICODE_NORM_QC_NO}, + {0x2F0F, UNICODE_NORM_QC_NO}, + {0x2F10, UNICODE_NORM_QC_NO}, + {0x2F11, UNICODE_NORM_QC_NO}, + {0x2F12, UNICODE_NORM_QC_NO}, + {0x2F13, UNICODE_NORM_QC_NO}, + {0x2F14, UNICODE_NORM_QC_NO}, + {0x2F15, UNICODE_NORM_QC_NO}, + {0x2F16, UNICODE_NORM_QC_NO}, + {0x2F17, UNICODE_NORM_QC_NO}, + {0x2F18, UNICODE_NORM_QC_NO}, + {0x2F19, UNICODE_NORM_QC_NO}, + {0x2F1A, UNICODE_NORM_QC_NO}, + {0x2F1B, UNICODE_NORM_QC_NO}, + {0x2F1C, UNICODE_NORM_QC_NO}, + {0x2F1D, UNICODE_NORM_QC_NO}, + {0x2F1E, UNICODE_NORM_QC_NO}, + {0x2F1F, UNICODE_NORM_QC_NO}, + {0x2F20, UNICODE_NORM_QC_NO}, + {0x2F21, UNICODE_NORM_QC_NO}, + {0x2F22, UNICODE_NORM_QC_NO}, + {0x2F23, UNICODE_NORM_QC_NO}, + {0x2F24, UNICODE_NORM_QC_NO}, + {0x2F25, UNICODE_NORM_QC_NO}, + {0x2F26, UNICODE_NORM_QC_NO}, + {0x2F27, UNICODE_NORM_QC_NO}, + {0x2F28, UNICODE_NORM_QC_NO}, + {0x2F29, UNICODE_NORM_QC_NO}, + {0x2F2A, UNICODE_NORM_QC_NO}, + {0x2F2B, UNICODE_NORM_QC_NO}, + {0x2F2C, UNICODE_NORM_QC_NO}, + {0x2F2D, UNICODE_NORM_QC_NO}, + {0x2F2E, UNICODE_NORM_QC_NO}, + {0x2F2F, UNICODE_NORM_QC_NO}, + {0x2F30, UNICODE_NORM_QC_NO}, + {0x2F31, UNICODE_NORM_QC_NO}, + {0x2F32, UNICODE_NORM_QC_NO}, + {0x2F33, UNICODE_NORM_QC_NO}, + {0x2F34, UNICODE_NORM_QC_NO}, + {0x2F35, UNICODE_NORM_QC_NO}, + {0x2F36, UNICODE_NORM_QC_NO}, + {0x2F37, UNICODE_NORM_QC_NO}, + {0x2F38, UNICODE_NORM_QC_NO}, + {0x2F39, UNICODE_NORM_QC_NO}, + {0x2F3A, UNICODE_NORM_QC_NO}, + {0x2F3B, UNICODE_NORM_QC_NO}, + {0x2F3C, UNICODE_NORM_QC_NO}, + {0x2F3D, UNICODE_NORM_QC_NO}, + {0x2F3E, UNICODE_NORM_QC_NO}, + {0x2F3F, UNICODE_NORM_QC_NO}, + {0x2F40, UNICODE_NORM_QC_NO}, + {0x2F41, UNICODE_NORM_QC_NO}, + {0x2F42, UNICODE_NORM_QC_NO}, + {0x2F43, UNICODE_NORM_QC_NO}, + {0x2F44, UNICODE_NORM_QC_NO}, + {0x2F45, UNICODE_NORM_QC_NO}, + {0x2F46, UNICODE_NORM_QC_NO}, + {0x2F47, UNICODE_NORM_QC_NO}, + {0x2F48, UNICODE_NORM_QC_NO}, + {0x2F49, UNICODE_NORM_QC_NO}, + {0x2F4A, UNICODE_NORM_QC_NO}, + {0x2F4B, UNICODE_NORM_QC_NO}, + {0x2F4C, UNICODE_NORM_QC_NO}, + {0x2F4D, UNICODE_NORM_QC_NO}, + {0x2F4E, UNICODE_NORM_QC_NO}, + {0x2F4F, UNICODE_NORM_QC_NO}, + {0x2F50, UNICODE_NORM_QC_NO}, + {0x2F51, UNICODE_NORM_QC_NO}, + {0x2F52, UNICODE_NORM_QC_NO}, + {0x2F53, UNICODE_NORM_QC_NO}, + {0x2F54, UNICODE_NORM_QC_NO}, + {0x2F55, UNICODE_NORM_QC_NO}, + {0x2F56, UNICODE_NORM_QC_NO}, + {0x2F57, UNICODE_NORM_QC_NO}, + {0x2F58, UNICODE_NORM_QC_NO}, + {0x2F59, UNICODE_NORM_QC_NO}, + {0x2F5A, UNICODE_NORM_QC_NO}, + {0x2F5B, UNICODE_NORM_QC_NO}, + {0x2F5C, UNICODE_NORM_QC_NO}, + {0x2F5D, UNICODE_NORM_QC_NO}, + {0x2F5E, UNICODE_NORM_QC_NO}, + {0x2F5F, UNICODE_NORM_QC_NO}, + {0x2F60, UNICODE_NORM_QC_NO}, + {0x2F61, UNICODE_NORM_QC_NO}, + {0x2F62, UNICODE_NORM_QC_NO}, + {0x2F63, UNICODE_NORM_QC_NO}, + {0x2F64, UNICODE_NORM_QC_NO}, + {0x2F65, UNICODE_NORM_QC_NO}, + {0x2F66, UNICODE_NORM_QC_NO}, + {0x2F67, UNICODE_NORM_QC_NO}, + {0x2F68, UNICODE_NORM_QC_NO}, + {0x2F69, UNICODE_NORM_QC_NO}, + {0x2F6A, UNICODE_NORM_QC_NO}, + {0x2F6B, UNICODE_NORM_QC_NO}, + {0x2F6C, UNICODE_NORM_QC_NO}, + {0x2F6D, UNICODE_NORM_QC_NO}, + {0x2F6E, UNICODE_NORM_QC_NO}, + {0x2F6F, UNICODE_NORM_QC_NO}, + {0x2F70, UNICODE_NORM_QC_NO}, + {0x2F71, UNICODE_NORM_QC_NO}, + {0x2F72, UNICODE_NORM_QC_NO}, + {0x2F73, UNICODE_NORM_QC_NO}, + {0x2F74, UNICODE_NORM_QC_NO}, + {0x2F75, UNICODE_NORM_QC_NO}, + {0x2F76, UNICODE_NORM_QC_NO}, + {0x2F77, UNICODE_NORM_QC_NO}, + {0x2F78, UNICODE_NORM_QC_NO}, + {0x2F79, UNICODE_NORM_QC_NO}, + {0x2F7A, UNICODE_NORM_QC_NO}, + {0x2F7B, UNICODE_NORM_QC_NO}, + {0x2F7C, UNICODE_NORM_QC_NO}, + {0x2F7D, UNICODE_NORM_QC_NO}, + {0x2F7E, UNICODE_NORM_QC_NO}, + {0x2F7F, UNICODE_NORM_QC_NO}, + {0x2F80, UNICODE_NORM_QC_NO}, + {0x2F81, UNICODE_NORM_QC_NO}, + {0x2F82, UNICODE_NORM_QC_NO}, + {0x2F83, UNICODE_NORM_QC_NO}, + {0x2F84, UNICODE_NORM_QC_NO}, + {0x2F85, UNICODE_NORM_QC_NO}, + {0x2F86, UNICODE_NORM_QC_NO}, + {0x2F87, UNICODE_NORM_QC_NO}, + {0x2F88, UNICODE_NORM_QC_NO}, + {0x2F89, UNICODE_NORM_QC_NO}, + {0x2F8A, UNICODE_NORM_QC_NO}, + {0x2F8B, UNICODE_NORM_QC_NO}, + {0x2F8C, UNICODE_NORM_QC_NO}, + {0x2F8D, UNICODE_NORM_QC_NO}, + {0x2F8E, UNICODE_NORM_QC_NO}, + {0x2F8F, UNICODE_NORM_QC_NO}, + {0x2F90, UNICODE_NORM_QC_NO}, + {0x2F91, UNICODE_NORM_QC_NO}, + {0x2F92, UNICODE_NORM_QC_NO}, + {0x2F93, UNICODE_NORM_QC_NO}, + {0x2F94, UNICODE_NORM_QC_NO}, + {0x2F95, UNICODE_NORM_QC_NO}, + {0x2F96, UNICODE_NORM_QC_NO}, + {0x2F97, UNICODE_NORM_QC_NO}, + {0x2F98, UNICODE_NORM_QC_NO}, + {0x2F99, UNICODE_NORM_QC_NO}, + {0x2F9A, UNICODE_NORM_QC_NO}, + {0x2F9B, UNICODE_NORM_QC_NO}, + {0x2F9C, UNICODE_NORM_QC_NO}, + {0x2F9D, UNICODE_NORM_QC_NO}, + {0x2F9E, UNICODE_NORM_QC_NO}, + {0x2F9F, UNICODE_NORM_QC_NO}, + {0x2FA0, UNICODE_NORM_QC_NO}, + {0x2FA1, UNICODE_NORM_QC_NO}, + {0x2FA2, UNICODE_NORM_QC_NO}, + {0x2FA3, UNICODE_NORM_QC_NO}, + {0x2FA4, UNICODE_NORM_QC_NO}, + {0x2FA5, UNICODE_NORM_QC_NO}, + {0x2FA6, UNICODE_NORM_QC_NO}, + {0x2FA7, UNICODE_NORM_QC_NO}, + {0x2FA8, UNICODE_NORM_QC_NO}, + {0x2FA9, UNICODE_NORM_QC_NO}, + {0x2FAA, UNICODE_NORM_QC_NO}, + {0x2FAB, UNICODE_NORM_QC_NO}, + {0x2FAC, UNICODE_NORM_QC_NO}, + {0x2FAD, UNICODE_NORM_QC_NO}, + {0x2FAE, UNICODE_NORM_QC_NO}, + {0x2FAF, UNICODE_NORM_QC_NO}, + {0x2FB0, UNICODE_NORM_QC_NO}, + {0x2FB1, UNICODE_NORM_QC_NO}, + {0x2FB2, UNICODE_NORM_QC_NO}, + {0x2FB3, UNICODE_NORM_QC_NO}, + {0x2FB4, UNICODE_NORM_QC_NO}, + {0x2FB5, UNICODE_NORM_QC_NO}, + {0x2FB6, UNICODE_NORM_QC_NO}, + {0x2FB7, UNICODE_NORM_QC_NO}, + {0x2FB8, UNICODE_NORM_QC_NO}, + {0x2FB9, UNICODE_NORM_QC_NO}, + {0x2FBA, UNICODE_NORM_QC_NO}, + {0x2FBB, UNICODE_NORM_QC_NO}, + {0x2FBC, UNICODE_NORM_QC_NO}, + {0x2FBD, UNICODE_NORM_QC_NO}, + {0x2FBE, UNICODE_NORM_QC_NO}, + {0x2FBF, UNICODE_NORM_QC_NO}, + {0x2FC0, UNICODE_NORM_QC_NO}, + {0x2FC1, UNICODE_NORM_QC_NO}, + {0x2FC2, UNICODE_NORM_QC_NO}, + {0x2FC3, UNICODE_NORM_QC_NO}, + {0x2FC4, UNICODE_NORM_QC_NO}, + {0x2FC5, UNICODE_NORM_QC_NO}, + {0x2FC6, UNICODE_NORM_QC_NO}, + {0x2FC7, UNICODE_NORM_QC_NO}, + {0x2FC8, UNICODE_NORM_QC_NO}, + {0x2FC9, UNICODE_NORM_QC_NO}, + {0x2FCA, UNICODE_NORM_QC_NO}, + {0x2FCB, UNICODE_NORM_QC_NO}, + {0x2FCC, UNICODE_NORM_QC_NO}, + {0x2FCD, UNICODE_NORM_QC_NO}, + {0x2FCE, UNICODE_NORM_QC_NO}, + {0x2FCF, UNICODE_NORM_QC_NO}, + {0x2FD0, UNICODE_NORM_QC_NO}, + {0x2FD1, UNICODE_NORM_QC_NO}, + {0x2FD2, UNICODE_NORM_QC_NO}, + {0x2FD3, UNICODE_NORM_QC_NO}, + {0x2FD4, UNICODE_NORM_QC_NO}, + {0x2FD5, UNICODE_NORM_QC_NO}, + {0x3000, UNICODE_NORM_QC_NO}, + {0x3036, UNICODE_NORM_QC_NO}, + {0x3038, UNICODE_NORM_QC_NO}, + {0x3039, UNICODE_NORM_QC_NO}, + {0x303A, UNICODE_NORM_QC_NO}, + {0x3099, UNICODE_NORM_QC_MAYBE}, + {0x309A, UNICODE_NORM_QC_MAYBE}, + {0x309B, UNICODE_NORM_QC_NO}, + {0x309C, UNICODE_NORM_QC_NO}, + {0x309F, UNICODE_NORM_QC_NO}, + {0x30FF, UNICODE_NORM_QC_NO}, + {0x3131, UNICODE_NORM_QC_NO}, + {0x3132, UNICODE_NORM_QC_NO}, + {0x3133, UNICODE_NORM_QC_NO}, + {0x3134, UNICODE_NORM_QC_NO}, + {0x3135, UNICODE_NORM_QC_NO}, + {0x3136, UNICODE_NORM_QC_NO}, + {0x3137, UNICODE_NORM_QC_NO}, + {0x3138, UNICODE_NORM_QC_NO}, + {0x3139, UNICODE_NORM_QC_NO}, + {0x313A, UNICODE_NORM_QC_NO}, + {0x313B, UNICODE_NORM_QC_NO}, + {0x313C, UNICODE_NORM_QC_NO}, + {0x313D, UNICODE_NORM_QC_NO}, + {0x313E, UNICODE_NORM_QC_NO}, + {0x313F, UNICODE_NORM_QC_NO}, + {0x3140, UNICODE_NORM_QC_NO}, + {0x3141, UNICODE_NORM_QC_NO}, + {0x3142, UNICODE_NORM_QC_NO}, + {0x3143, UNICODE_NORM_QC_NO}, + {0x3144, UNICODE_NORM_QC_NO}, + {0x3145, UNICODE_NORM_QC_NO}, + {0x3146, UNICODE_NORM_QC_NO}, + {0x3147, UNICODE_NORM_QC_NO}, + {0x3148, UNICODE_NORM_QC_NO}, + {0x3149, UNICODE_NORM_QC_NO}, + {0x314A, UNICODE_NORM_QC_NO}, + {0x314B, UNICODE_NORM_QC_NO}, + {0x314C, UNICODE_NORM_QC_NO}, + {0x314D, UNICODE_NORM_QC_NO}, + {0x314E, UNICODE_NORM_QC_NO}, + {0x314F, UNICODE_NORM_QC_NO}, + {0x3150, UNICODE_NORM_QC_NO}, + {0x3151, UNICODE_NORM_QC_NO}, + {0x3152, UNICODE_NORM_QC_NO}, + {0x3153, UNICODE_NORM_QC_NO}, + {0x3154, UNICODE_NORM_QC_NO}, + {0x3155, UNICODE_NORM_QC_NO}, + {0x3156, UNICODE_NORM_QC_NO}, + {0x3157, UNICODE_NORM_QC_NO}, + {0x3158, UNICODE_NORM_QC_NO}, + {0x3159, UNICODE_NORM_QC_NO}, + {0x315A, UNICODE_NORM_QC_NO}, + {0x315B, UNICODE_NORM_QC_NO}, + {0x315C, UNICODE_NORM_QC_NO}, + {0x315D, UNICODE_NORM_QC_NO}, + {0x315E, UNICODE_NORM_QC_NO}, + {0x315F, UNICODE_NORM_QC_NO}, + {0x3160, UNICODE_NORM_QC_NO}, + {0x3161, UNICODE_NORM_QC_NO}, + {0x3162, UNICODE_NORM_QC_NO}, + {0x3163, UNICODE_NORM_QC_NO}, + {0x3164, UNICODE_NORM_QC_NO}, + {0x3165, UNICODE_NORM_QC_NO}, + {0x3166, UNICODE_NORM_QC_NO}, + {0x3167, UNICODE_NORM_QC_NO}, + {0x3168, UNICODE_NORM_QC_NO}, + {0x3169, UNICODE_NORM_QC_NO}, + {0x316A, UNICODE_NORM_QC_NO}, + {0x316B, UNICODE_NORM_QC_NO}, + {0x316C, UNICODE_NORM_QC_NO}, + {0x316D, UNICODE_NORM_QC_NO}, + {0x316E, UNICODE_NORM_QC_NO}, + {0x316F, UNICODE_NORM_QC_NO}, + {0x3170, UNICODE_NORM_QC_NO}, + {0x3171, UNICODE_NORM_QC_NO}, + {0x3172, UNICODE_NORM_QC_NO}, + {0x3173, UNICODE_NORM_QC_NO}, + {0x3174, UNICODE_NORM_QC_NO}, + {0x3175, UNICODE_NORM_QC_NO}, + {0x3176, UNICODE_NORM_QC_NO}, + {0x3177, UNICODE_NORM_QC_NO}, + {0x3178, UNICODE_NORM_QC_NO}, + {0x3179, UNICODE_NORM_QC_NO}, + {0x317A, UNICODE_NORM_QC_NO}, + {0x317B, UNICODE_NORM_QC_NO}, + {0x317C, UNICODE_NORM_QC_NO}, + {0x317D, UNICODE_NORM_QC_NO}, + {0x317E, UNICODE_NORM_QC_NO}, + {0x317F, UNICODE_NORM_QC_NO}, + {0x3180, UNICODE_NORM_QC_NO}, + {0x3181, UNICODE_NORM_QC_NO}, + {0x3182, UNICODE_NORM_QC_NO}, + {0x3183, UNICODE_NORM_QC_NO}, + {0x3184, UNICODE_NORM_QC_NO}, + {0x3185, UNICODE_NORM_QC_NO}, + {0x3186, UNICODE_NORM_QC_NO}, + {0x3187, UNICODE_NORM_QC_NO}, + {0x3188, UNICODE_NORM_QC_NO}, + {0x3189, UNICODE_NORM_QC_NO}, + {0x318A, UNICODE_NORM_QC_NO}, + {0x318B, UNICODE_NORM_QC_NO}, + {0x318C, UNICODE_NORM_QC_NO}, + {0x318D, UNICODE_NORM_QC_NO}, + {0x318E, UNICODE_NORM_QC_NO}, + {0x3192, UNICODE_NORM_QC_NO}, + {0x3193, UNICODE_NORM_QC_NO}, + {0x3194, UNICODE_NORM_QC_NO}, + {0x3195, UNICODE_NORM_QC_NO}, + {0x3196, UNICODE_NORM_QC_NO}, + {0x3197, UNICODE_NORM_QC_NO}, + {0x3198, UNICODE_NORM_QC_NO}, + {0x3199, UNICODE_NORM_QC_NO}, + {0x319A, UNICODE_NORM_QC_NO}, + {0x319B, UNICODE_NORM_QC_NO}, + {0x319C, UNICODE_NORM_QC_NO}, + {0x319D, UNICODE_NORM_QC_NO}, + {0x319E, UNICODE_NORM_QC_NO}, + {0x319F, UNICODE_NORM_QC_NO}, + {0x3200, UNICODE_NORM_QC_NO}, + {0x3201, UNICODE_NORM_QC_NO}, + {0x3202, UNICODE_NORM_QC_NO}, + {0x3203, UNICODE_NORM_QC_NO}, + {0x3204, UNICODE_NORM_QC_NO}, + {0x3205, UNICODE_NORM_QC_NO}, + {0x3206, UNICODE_NORM_QC_NO}, + {0x3207, UNICODE_NORM_QC_NO}, + {0x3208, UNICODE_NORM_QC_NO}, + {0x3209, UNICODE_NORM_QC_NO}, + {0x320A, UNICODE_NORM_QC_NO}, + {0x320B, UNICODE_NORM_QC_NO}, + {0x320C, UNICODE_NORM_QC_NO}, + {0x320D, UNICODE_NORM_QC_NO}, + {0x320E, UNICODE_NORM_QC_NO}, + {0x320F, UNICODE_NORM_QC_NO}, + {0x3210, UNICODE_NORM_QC_NO}, + {0x3211, UNICODE_NORM_QC_NO}, + {0x3212, UNICODE_NORM_QC_NO}, + {0x3213, UNICODE_NORM_QC_NO}, + {0x3214, UNICODE_NORM_QC_NO}, + {0x3215, UNICODE_NORM_QC_NO}, + {0x3216, UNICODE_NORM_QC_NO}, + {0x3217, UNICODE_NORM_QC_NO}, + {0x3218, UNICODE_NORM_QC_NO}, + {0x3219, UNICODE_NORM_QC_NO}, + {0x321A, UNICODE_NORM_QC_NO}, + {0x321B, UNICODE_NORM_QC_NO}, + {0x321C, UNICODE_NORM_QC_NO}, + {0x321D, UNICODE_NORM_QC_NO}, + {0x321E, UNICODE_NORM_QC_NO}, + {0x3220, UNICODE_NORM_QC_NO}, + {0x3221, UNICODE_NORM_QC_NO}, + {0x3222, UNICODE_NORM_QC_NO}, + {0x3223, UNICODE_NORM_QC_NO}, + {0x3224, UNICODE_NORM_QC_NO}, + {0x3225, UNICODE_NORM_QC_NO}, + {0x3226, UNICODE_NORM_QC_NO}, + {0x3227, UNICODE_NORM_QC_NO}, + {0x3228, UNICODE_NORM_QC_NO}, + {0x3229, UNICODE_NORM_QC_NO}, + {0x322A, UNICODE_NORM_QC_NO}, + {0x322B, UNICODE_NORM_QC_NO}, + {0x322C, UNICODE_NORM_QC_NO}, + {0x322D, UNICODE_NORM_QC_NO}, + {0x322E, UNICODE_NORM_QC_NO}, + {0x322F, UNICODE_NORM_QC_NO}, + {0x3230, UNICODE_NORM_QC_NO}, + {0x3231, UNICODE_NORM_QC_NO}, + {0x3232, UNICODE_NORM_QC_NO}, + {0x3233, UNICODE_NORM_QC_NO}, + {0x3234, UNICODE_NORM_QC_NO}, + {0x3235, UNICODE_NORM_QC_NO}, + {0x3236, UNICODE_NORM_QC_NO}, + {0x3237, UNICODE_NORM_QC_NO}, + {0x3238, UNICODE_NORM_QC_NO}, + {0x3239, UNICODE_NORM_QC_NO}, + {0x323A, UNICODE_NORM_QC_NO}, + {0x323B, UNICODE_NORM_QC_NO}, + {0x323C, UNICODE_NORM_QC_NO}, + {0x323D, UNICODE_NORM_QC_NO}, + {0x323E, UNICODE_NORM_QC_NO}, + {0x323F, UNICODE_NORM_QC_NO}, + {0x3240, UNICODE_NORM_QC_NO}, + {0x3241, UNICODE_NORM_QC_NO}, + {0x3242, UNICODE_NORM_QC_NO}, + {0x3243, UNICODE_NORM_QC_NO}, + {0x3244, UNICODE_NORM_QC_NO}, + {0x3245, UNICODE_NORM_QC_NO}, + {0x3246, UNICODE_NORM_QC_NO}, + {0x3247, UNICODE_NORM_QC_NO}, + {0x3250, UNICODE_NORM_QC_NO}, + {0x3251, UNICODE_NORM_QC_NO}, + {0x3252, UNICODE_NORM_QC_NO}, + {0x3253, UNICODE_NORM_QC_NO}, + {0x3254, UNICODE_NORM_QC_NO}, + {0x3255, UNICODE_NORM_QC_NO}, + {0x3256, UNICODE_NORM_QC_NO}, + {0x3257, UNICODE_NORM_QC_NO}, + {0x3258, UNICODE_NORM_QC_NO}, + {0x3259, UNICODE_NORM_QC_NO}, + {0x325A, UNICODE_NORM_QC_NO}, + {0x325B, UNICODE_NORM_QC_NO}, + {0x325C, UNICODE_NORM_QC_NO}, + {0x325D, UNICODE_NORM_QC_NO}, + {0x325E, UNICODE_NORM_QC_NO}, + {0x325F, UNICODE_NORM_QC_NO}, + {0x3260, UNICODE_NORM_QC_NO}, + {0x3261, UNICODE_NORM_QC_NO}, + {0x3262, UNICODE_NORM_QC_NO}, + {0x3263, UNICODE_NORM_QC_NO}, + {0x3264, UNICODE_NORM_QC_NO}, + {0x3265, UNICODE_NORM_QC_NO}, + {0x3266, UNICODE_NORM_QC_NO}, + {0x3267, UNICODE_NORM_QC_NO}, + {0x3268, UNICODE_NORM_QC_NO}, + {0x3269, UNICODE_NORM_QC_NO}, + {0x326A, UNICODE_NORM_QC_NO}, + {0x326B, UNICODE_NORM_QC_NO}, + {0x326C, UNICODE_NORM_QC_NO}, + {0x326D, UNICODE_NORM_QC_NO}, + {0x326E, UNICODE_NORM_QC_NO}, + {0x326F, UNICODE_NORM_QC_NO}, + {0x3270, UNICODE_NORM_QC_NO}, + {0x3271, UNICODE_NORM_QC_NO}, + {0x3272, UNICODE_NORM_QC_NO}, + {0x3273, UNICODE_NORM_QC_NO}, + {0x3274, UNICODE_NORM_QC_NO}, + {0x3275, UNICODE_NORM_QC_NO}, + {0x3276, UNICODE_NORM_QC_NO}, + {0x3277, UNICODE_NORM_QC_NO}, + {0x3278, UNICODE_NORM_QC_NO}, + {0x3279, UNICODE_NORM_QC_NO}, + {0x327A, UNICODE_NORM_QC_NO}, + {0x327B, UNICODE_NORM_QC_NO}, + {0x327C, UNICODE_NORM_QC_NO}, + {0x327D, UNICODE_NORM_QC_NO}, + {0x327E, UNICODE_NORM_QC_NO}, + {0x3280, UNICODE_NORM_QC_NO}, + {0x3281, UNICODE_NORM_QC_NO}, + {0x3282, UNICODE_NORM_QC_NO}, + {0x3283, UNICODE_NORM_QC_NO}, + {0x3284, UNICODE_NORM_QC_NO}, + {0x3285, UNICODE_NORM_QC_NO}, + {0x3286, UNICODE_NORM_QC_NO}, + {0x3287, UNICODE_NORM_QC_NO}, + {0x3288, UNICODE_NORM_QC_NO}, + {0x3289, UNICODE_NORM_QC_NO}, + {0x328A, UNICODE_NORM_QC_NO}, + {0x328B, UNICODE_NORM_QC_NO}, + {0x328C, UNICODE_NORM_QC_NO}, + {0x328D, UNICODE_NORM_QC_NO}, + {0x328E, UNICODE_NORM_QC_NO}, + {0x328F, UNICODE_NORM_QC_NO}, + {0x3290, UNICODE_NORM_QC_NO}, + {0x3291, UNICODE_NORM_QC_NO}, + {0x3292, UNICODE_NORM_QC_NO}, + {0x3293, UNICODE_NORM_QC_NO}, + {0x3294, UNICODE_NORM_QC_NO}, + {0x3295, UNICODE_NORM_QC_NO}, + {0x3296, UNICODE_NORM_QC_NO}, + {0x3297, UNICODE_NORM_QC_NO}, + {0x3298, UNICODE_NORM_QC_NO}, + {0x3299, UNICODE_NORM_QC_NO}, + {0x329A, UNICODE_NORM_QC_NO}, + {0x329B, UNICODE_NORM_QC_NO}, + {0x329C, UNICODE_NORM_QC_NO}, + {0x329D, UNICODE_NORM_QC_NO}, + {0x329E, UNICODE_NORM_QC_NO}, + {0x329F, UNICODE_NORM_QC_NO}, + {0x32A0, UNICODE_NORM_QC_NO}, + {0x32A1, UNICODE_NORM_QC_NO}, + {0x32A2, UNICODE_NORM_QC_NO}, + {0x32A3, UNICODE_NORM_QC_NO}, + {0x32A4, UNICODE_NORM_QC_NO}, + {0x32A5, UNICODE_NORM_QC_NO}, + {0x32A6, UNICODE_NORM_QC_NO}, + {0x32A7, UNICODE_NORM_QC_NO}, + {0x32A8, UNICODE_NORM_QC_NO}, + {0x32A9, UNICODE_NORM_QC_NO}, + {0x32AA, UNICODE_NORM_QC_NO}, + {0x32AB, UNICODE_NORM_QC_NO}, + {0x32AC, UNICODE_NORM_QC_NO}, + {0x32AD, UNICODE_NORM_QC_NO}, + {0x32AE, UNICODE_NORM_QC_NO}, + {0x32AF, UNICODE_NORM_QC_NO}, + {0x32B0, UNICODE_NORM_QC_NO}, + {0x32B1, UNICODE_NORM_QC_NO}, + {0x32B2, UNICODE_NORM_QC_NO}, + {0x32B3, UNICODE_NORM_QC_NO}, + {0x32B4, UNICODE_NORM_QC_NO}, + {0x32B5, UNICODE_NORM_QC_NO}, + {0x32B6, UNICODE_NORM_QC_NO}, + {0x32B7, UNICODE_NORM_QC_NO}, + {0x32B8, UNICODE_NORM_QC_NO}, + {0x32B9, UNICODE_NORM_QC_NO}, + {0x32BA, UNICODE_NORM_QC_NO}, + {0x32BB, UNICODE_NORM_QC_NO}, + {0x32BC, UNICODE_NORM_QC_NO}, + {0x32BD, UNICODE_NORM_QC_NO}, + {0x32BE, UNICODE_NORM_QC_NO}, + {0x32BF, UNICODE_NORM_QC_NO}, + {0x32C0, UNICODE_NORM_QC_NO}, + {0x32C1, UNICODE_NORM_QC_NO}, + {0x32C2, UNICODE_NORM_QC_NO}, + {0x32C3, UNICODE_NORM_QC_NO}, + {0x32C4, UNICODE_NORM_QC_NO}, + {0x32C5, UNICODE_NORM_QC_NO}, + {0x32C6, UNICODE_NORM_QC_NO}, + {0x32C7, UNICODE_NORM_QC_NO}, + {0x32C8, UNICODE_NORM_QC_NO}, + {0x32C9, UNICODE_NORM_QC_NO}, + {0x32CA, UNICODE_NORM_QC_NO}, + {0x32CB, UNICODE_NORM_QC_NO}, + {0x32CC, UNICODE_NORM_QC_NO}, + {0x32CD, UNICODE_NORM_QC_NO}, + {0x32CE, UNICODE_NORM_QC_NO}, + {0x32CF, UNICODE_NORM_QC_NO}, + {0x32D0, UNICODE_NORM_QC_NO}, + {0x32D1, UNICODE_NORM_QC_NO}, + {0x32D2, UNICODE_NORM_QC_NO}, + {0x32D3, UNICODE_NORM_QC_NO}, + {0x32D4, UNICODE_NORM_QC_NO}, + {0x32D5, UNICODE_NORM_QC_NO}, + {0x32D6, UNICODE_NORM_QC_NO}, + {0x32D7, UNICODE_NORM_QC_NO}, + {0x32D8, UNICODE_NORM_QC_NO}, + {0x32D9, UNICODE_NORM_QC_NO}, + {0x32DA, UNICODE_NORM_QC_NO}, + {0x32DB, UNICODE_NORM_QC_NO}, + {0x32DC, UNICODE_NORM_QC_NO}, + {0x32DD, UNICODE_NORM_QC_NO}, + {0x32DE, UNICODE_NORM_QC_NO}, + {0x32DF, UNICODE_NORM_QC_NO}, + {0x32E0, UNICODE_NORM_QC_NO}, + {0x32E1, UNICODE_NORM_QC_NO}, + {0x32E2, UNICODE_NORM_QC_NO}, + {0x32E3, UNICODE_NORM_QC_NO}, + {0x32E4, UNICODE_NORM_QC_NO}, + {0x32E5, UNICODE_NORM_QC_NO}, + {0x32E6, UNICODE_NORM_QC_NO}, + {0x32E7, UNICODE_NORM_QC_NO}, + {0x32E8, UNICODE_NORM_QC_NO}, + {0x32E9, UNICODE_NORM_QC_NO}, + {0x32EA, UNICODE_NORM_QC_NO}, + {0x32EB, UNICODE_NORM_QC_NO}, + {0x32EC, UNICODE_NORM_QC_NO}, + {0x32ED, UNICODE_NORM_QC_NO}, + {0x32EE, UNICODE_NORM_QC_NO}, + {0x32EF, UNICODE_NORM_QC_NO}, + {0x32F0, UNICODE_NORM_QC_NO}, + {0x32F1, UNICODE_NORM_QC_NO}, + {0x32F2, UNICODE_NORM_QC_NO}, + {0x32F3, UNICODE_NORM_QC_NO}, + {0x32F4, UNICODE_NORM_QC_NO}, + {0x32F5, UNICODE_NORM_QC_NO}, + {0x32F6, UNICODE_NORM_QC_NO}, + {0x32F7, UNICODE_NORM_QC_NO}, + {0x32F8, UNICODE_NORM_QC_NO}, + {0x32F9, UNICODE_NORM_QC_NO}, + {0x32FA, UNICODE_NORM_QC_NO}, + {0x32FB, UNICODE_NORM_QC_NO}, + {0x32FC, UNICODE_NORM_QC_NO}, + {0x32FD, UNICODE_NORM_QC_NO}, + {0x32FE, UNICODE_NORM_QC_NO}, + {0x32FF, UNICODE_NORM_QC_NO}, + {0x3300, UNICODE_NORM_QC_NO}, + {0x3301, UNICODE_NORM_QC_NO}, + {0x3302, UNICODE_NORM_QC_NO}, + {0x3303, UNICODE_NORM_QC_NO}, + {0x3304, UNICODE_NORM_QC_NO}, + {0x3305, UNICODE_NORM_QC_NO}, + {0x3306, UNICODE_NORM_QC_NO}, + {0x3307, UNICODE_NORM_QC_NO}, + {0x3308, UNICODE_NORM_QC_NO}, + {0x3309, UNICODE_NORM_QC_NO}, + {0x330A, UNICODE_NORM_QC_NO}, + {0x330B, UNICODE_NORM_QC_NO}, + {0x330C, UNICODE_NORM_QC_NO}, + {0x330D, UNICODE_NORM_QC_NO}, + {0x330E, UNICODE_NORM_QC_NO}, + {0x330F, UNICODE_NORM_QC_NO}, + {0x3310, UNICODE_NORM_QC_NO}, + {0x3311, UNICODE_NORM_QC_NO}, + {0x3312, UNICODE_NORM_QC_NO}, + {0x3313, UNICODE_NORM_QC_NO}, + {0x3314, UNICODE_NORM_QC_NO}, + {0x3315, UNICODE_NORM_QC_NO}, + {0x3316, UNICODE_NORM_QC_NO}, + {0x3317, UNICODE_NORM_QC_NO}, + {0x3318, UNICODE_NORM_QC_NO}, + {0x3319, UNICODE_NORM_QC_NO}, + {0x331A, UNICODE_NORM_QC_NO}, + {0x331B, UNICODE_NORM_QC_NO}, + {0x331C, UNICODE_NORM_QC_NO}, + {0x331D, UNICODE_NORM_QC_NO}, + {0x331E, UNICODE_NORM_QC_NO}, + {0x331F, UNICODE_NORM_QC_NO}, + {0x3320, UNICODE_NORM_QC_NO}, + {0x3321, UNICODE_NORM_QC_NO}, + {0x3322, UNICODE_NORM_QC_NO}, + {0x3323, UNICODE_NORM_QC_NO}, + {0x3324, UNICODE_NORM_QC_NO}, + {0x3325, UNICODE_NORM_QC_NO}, + {0x3326, UNICODE_NORM_QC_NO}, + {0x3327, UNICODE_NORM_QC_NO}, + {0x3328, UNICODE_NORM_QC_NO}, + {0x3329, UNICODE_NORM_QC_NO}, + {0x332A, UNICODE_NORM_QC_NO}, + {0x332B, UNICODE_NORM_QC_NO}, + {0x332C, UNICODE_NORM_QC_NO}, + {0x332D, UNICODE_NORM_QC_NO}, + {0x332E, UNICODE_NORM_QC_NO}, + {0x332F, UNICODE_NORM_QC_NO}, + {0x3330, UNICODE_NORM_QC_NO}, + {0x3331, UNICODE_NORM_QC_NO}, + {0x3332, UNICODE_NORM_QC_NO}, + {0x3333, UNICODE_NORM_QC_NO}, + {0x3334, UNICODE_NORM_QC_NO}, + {0x3335, UNICODE_NORM_QC_NO}, + {0x3336, UNICODE_NORM_QC_NO}, + {0x3337, UNICODE_NORM_QC_NO}, + {0x3338, UNICODE_NORM_QC_NO}, + {0x3339, UNICODE_NORM_QC_NO}, + {0x333A, UNICODE_NORM_QC_NO}, + {0x333B, UNICODE_NORM_QC_NO}, + {0x333C, UNICODE_NORM_QC_NO}, + {0x333D, UNICODE_NORM_QC_NO}, + {0x333E, UNICODE_NORM_QC_NO}, + {0x333F, UNICODE_NORM_QC_NO}, + {0x3340, UNICODE_NORM_QC_NO}, + {0x3341, UNICODE_NORM_QC_NO}, + {0x3342, UNICODE_NORM_QC_NO}, + {0x3343, UNICODE_NORM_QC_NO}, + {0x3344, UNICODE_NORM_QC_NO}, + {0x3345, UNICODE_NORM_QC_NO}, + {0x3346, UNICODE_NORM_QC_NO}, + {0x3347, UNICODE_NORM_QC_NO}, + {0x3348, UNICODE_NORM_QC_NO}, + {0x3349, UNICODE_NORM_QC_NO}, + {0x334A, UNICODE_NORM_QC_NO}, + {0x334B, UNICODE_NORM_QC_NO}, + {0x334C, UNICODE_NORM_QC_NO}, + {0x334D, UNICODE_NORM_QC_NO}, + {0x334E, UNICODE_NORM_QC_NO}, + {0x334F, UNICODE_NORM_QC_NO}, + {0x3350, UNICODE_NORM_QC_NO}, + {0x3351, UNICODE_NORM_QC_NO}, + {0x3352, UNICODE_NORM_QC_NO}, + {0x3353, UNICODE_NORM_QC_NO}, + {0x3354, UNICODE_NORM_QC_NO}, + {0x3355, UNICODE_NORM_QC_NO}, + {0x3356, UNICODE_NORM_QC_NO}, + {0x3357, UNICODE_NORM_QC_NO}, + {0x3358, UNICODE_NORM_QC_NO}, + {0x3359, UNICODE_NORM_QC_NO}, + {0x335A, UNICODE_NORM_QC_NO}, + {0x335B, UNICODE_NORM_QC_NO}, + {0x335C, UNICODE_NORM_QC_NO}, + {0x335D, UNICODE_NORM_QC_NO}, + {0x335E, UNICODE_NORM_QC_NO}, + {0x335F, UNICODE_NORM_QC_NO}, + {0x3360, UNICODE_NORM_QC_NO}, + {0x3361, UNICODE_NORM_QC_NO}, + {0x3362, UNICODE_NORM_QC_NO}, + {0x3363, UNICODE_NORM_QC_NO}, + {0x3364, UNICODE_NORM_QC_NO}, + {0x3365, UNICODE_NORM_QC_NO}, + {0x3366, UNICODE_NORM_QC_NO}, + {0x3367, UNICODE_NORM_QC_NO}, + {0x3368, UNICODE_NORM_QC_NO}, + {0x3369, UNICODE_NORM_QC_NO}, + {0x336A, UNICODE_NORM_QC_NO}, + {0x336B, UNICODE_NORM_QC_NO}, + {0x336C, UNICODE_NORM_QC_NO}, + {0x336D, UNICODE_NORM_QC_NO}, + {0x336E, UNICODE_NORM_QC_NO}, + {0x336F, UNICODE_NORM_QC_NO}, + {0x3370, UNICODE_NORM_QC_NO}, + {0x3371, UNICODE_NORM_QC_NO}, + {0x3372, UNICODE_NORM_QC_NO}, + {0x3373, UNICODE_NORM_QC_NO}, + {0x3374, UNICODE_NORM_QC_NO}, + {0x3375, UNICODE_NORM_QC_NO}, + {0x3376, UNICODE_NORM_QC_NO}, + {0x3377, UNICODE_NORM_QC_NO}, + {0x3378, UNICODE_NORM_QC_NO}, + {0x3379, UNICODE_NORM_QC_NO}, + {0x337A, UNICODE_NORM_QC_NO}, + {0x337B, UNICODE_NORM_QC_NO}, + {0x337C, UNICODE_NORM_QC_NO}, + {0x337D, UNICODE_NORM_QC_NO}, + {0x337E, UNICODE_NORM_QC_NO}, + {0x337F, UNICODE_NORM_QC_NO}, + {0x3380, UNICODE_NORM_QC_NO}, + {0x3381, UNICODE_NORM_QC_NO}, + {0x3382, UNICODE_NORM_QC_NO}, + {0x3383, UNICODE_NORM_QC_NO}, + {0x3384, UNICODE_NORM_QC_NO}, + {0x3385, UNICODE_NORM_QC_NO}, + {0x3386, UNICODE_NORM_QC_NO}, + {0x3387, UNICODE_NORM_QC_NO}, + {0x3388, UNICODE_NORM_QC_NO}, + {0x3389, UNICODE_NORM_QC_NO}, + {0x338A, UNICODE_NORM_QC_NO}, + {0x338B, UNICODE_NORM_QC_NO}, + {0x338C, UNICODE_NORM_QC_NO}, + {0x338D, UNICODE_NORM_QC_NO}, + {0x338E, UNICODE_NORM_QC_NO}, + {0x338F, UNICODE_NORM_QC_NO}, + {0x3390, UNICODE_NORM_QC_NO}, + {0x3391, UNICODE_NORM_QC_NO}, + {0x3392, UNICODE_NORM_QC_NO}, + {0x3393, UNICODE_NORM_QC_NO}, + {0x3394, UNICODE_NORM_QC_NO}, + {0x3395, UNICODE_NORM_QC_NO}, + {0x3396, UNICODE_NORM_QC_NO}, + {0x3397, UNICODE_NORM_QC_NO}, + {0x3398, UNICODE_NORM_QC_NO}, + {0x3399, UNICODE_NORM_QC_NO}, + {0x339A, UNICODE_NORM_QC_NO}, + {0x339B, UNICODE_NORM_QC_NO}, + {0x339C, UNICODE_NORM_QC_NO}, + {0x339D, UNICODE_NORM_QC_NO}, + {0x339E, UNICODE_NORM_QC_NO}, + {0x339F, UNICODE_NORM_QC_NO}, + {0x33A0, UNICODE_NORM_QC_NO}, + {0x33A1, UNICODE_NORM_QC_NO}, + {0x33A2, UNICODE_NORM_QC_NO}, + {0x33A3, UNICODE_NORM_QC_NO}, + {0x33A4, UNICODE_NORM_QC_NO}, + {0x33A5, UNICODE_NORM_QC_NO}, + {0x33A6, UNICODE_NORM_QC_NO}, + {0x33A7, UNICODE_NORM_QC_NO}, + {0x33A8, UNICODE_NORM_QC_NO}, + {0x33A9, UNICODE_NORM_QC_NO}, + {0x33AA, UNICODE_NORM_QC_NO}, + {0x33AB, UNICODE_NORM_QC_NO}, + {0x33AC, UNICODE_NORM_QC_NO}, + {0x33AD, UNICODE_NORM_QC_NO}, + {0x33AE, UNICODE_NORM_QC_NO}, + {0x33AF, UNICODE_NORM_QC_NO}, + {0x33B0, UNICODE_NORM_QC_NO}, + {0x33B1, UNICODE_NORM_QC_NO}, + {0x33B2, UNICODE_NORM_QC_NO}, + {0x33B3, UNICODE_NORM_QC_NO}, + {0x33B4, UNICODE_NORM_QC_NO}, + {0x33B5, UNICODE_NORM_QC_NO}, + {0x33B6, UNICODE_NORM_QC_NO}, + {0x33B7, UNICODE_NORM_QC_NO}, + {0x33B8, UNICODE_NORM_QC_NO}, + {0x33B9, UNICODE_NORM_QC_NO}, + {0x33BA, UNICODE_NORM_QC_NO}, + {0x33BB, UNICODE_NORM_QC_NO}, + {0x33BC, UNICODE_NORM_QC_NO}, + {0x33BD, UNICODE_NORM_QC_NO}, + {0x33BE, UNICODE_NORM_QC_NO}, + {0x33BF, UNICODE_NORM_QC_NO}, + {0x33C0, UNICODE_NORM_QC_NO}, + {0x33C1, UNICODE_NORM_QC_NO}, + {0x33C2, UNICODE_NORM_QC_NO}, + {0x33C3, UNICODE_NORM_QC_NO}, + {0x33C4, UNICODE_NORM_QC_NO}, + {0x33C5, UNICODE_NORM_QC_NO}, + {0x33C6, UNICODE_NORM_QC_NO}, + {0x33C7, UNICODE_NORM_QC_NO}, + {0x33C8, UNICODE_NORM_QC_NO}, + {0x33C9, UNICODE_NORM_QC_NO}, + {0x33CA, UNICODE_NORM_QC_NO}, + {0x33CB, UNICODE_NORM_QC_NO}, + {0x33CC, UNICODE_NORM_QC_NO}, + {0x33CD, UNICODE_NORM_QC_NO}, + {0x33CE, UNICODE_NORM_QC_NO}, + {0x33CF, UNICODE_NORM_QC_NO}, + {0x33D0, UNICODE_NORM_QC_NO}, + {0x33D1, UNICODE_NORM_QC_NO}, + {0x33D2, UNICODE_NORM_QC_NO}, + {0x33D3, UNICODE_NORM_QC_NO}, + {0x33D4, UNICODE_NORM_QC_NO}, + {0x33D5, UNICODE_NORM_QC_NO}, + {0x33D6, UNICODE_NORM_QC_NO}, + {0x33D7, UNICODE_NORM_QC_NO}, + {0x33D8, UNICODE_NORM_QC_NO}, + {0x33D9, UNICODE_NORM_QC_NO}, + {0x33DA, UNICODE_NORM_QC_NO}, + {0x33DB, UNICODE_NORM_QC_NO}, + {0x33DC, UNICODE_NORM_QC_NO}, + {0x33DD, UNICODE_NORM_QC_NO}, + {0x33DE, UNICODE_NORM_QC_NO}, + {0x33DF, UNICODE_NORM_QC_NO}, + {0x33E0, UNICODE_NORM_QC_NO}, + {0x33E1, UNICODE_NORM_QC_NO}, + {0x33E2, UNICODE_NORM_QC_NO}, + {0x33E3, UNICODE_NORM_QC_NO}, + {0x33E4, UNICODE_NORM_QC_NO}, + {0x33E5, UNICODE_NORM_QC_NO}, + {0x33E6, UNICODE_NORM_QC_NO}, + {0x33E7, UNICODE_NORM_QC_NO}, + {0x33E8, UNICODE_NORM_QC_NO}, + {0x33E9, UNICODE_NORM_QC_NO}, + {0x33EA, UNICODE_NORM_QC_NO}, + {0x33EB, UNICODE_NORM_QC_NO}, + {0x33EC, UNICODE_NORM_QC_NO}, + {0x33ED, UNICODE_NORM_QC_NO}, + {0x33EE, UNICODE_NORM_QC_NO}, + {0x33EF, UNICODE_NORM_QC_NO}, + {0x33F0, UNICODE_NORM_QC_NO}, + {0x33F1, UNICODE_NORM_QC_NO}, + {0x33F2, UNICODE_NORM_QC_NO}, + {0x33F3, UNICODE_NORM_QC_NO}, + {0x33F4, UNICODE_NORM_QC_NO}, + {0x33F5, UNICODE_NORM_QC_NO}, + {0x33F6, UNICODE_NORM_QC_NO}, + {0x33F7, UNICODE_NORM_QC_NO}, + {0x33F8, UNICODE_NORM_QC_NO}, + {0x33F9, UNICODE_NORM_QC_NO}, + {0x33FA, UNICODE_NORM_QC_NO}, + {0x33FB, UNICODE_NORM_QC_NO}, + {0x33FC, UNICODE_NORM_QC_NO}, + {0x33FD, UNICODE_NORM_QC_NO}, + {0x33FE, UNICODE_NORM_QC_NO}, + {0x33FF, UNICODE_NORM_QC_NO}, + {0xA69C, UNICODE_NORM_QC_NO}, + {0xA69D, UNICODE_NORM_QC_NO}, + {0xA770, UNICODE_NORM_QC_NO}, + {0xA7F2, UNICODE_NORM_QC_NO}, + {0xA7F3, UNICODE_NORM_QC_NO}, + {0xA7F4, UNICODE_NORM_QC_NO}, + {0xA7F8, UNICODE_NORM_QC_NO}, + {0xA7F9, UNICODE_NORM_QC_NO}, + {0xAB5C, UNICODE_NORM_QC_NO}, + {0xAB5D, UNICODE_NORM_QC_NO}, + {0xAB5E, UNICODE_NORM_QC_NO}, + {0xAB5F, UNICODE_NORM_QC_NO}, + {0xAB69, UNICODE_NORM_QC_NO}, + {0xF900, UNICODE_NORM_QC_NO}, + {0xF901, UNICODE_NORM_QC_NO}, + {0xF902, UNICODE_NORM_QC_NO}, + {0xF903, UNICODE_NORM_QC_NO}, + {0xF904, UNICODE_NORM_QC_NO}, + {0xF905, UNICODE_NORM_QC_NO}, + {0xF906, UNICODE_NORM_QC_NO}, + {0xF907, UNICODE_NORM_QC_NO}, + {0xF908, UNICODE_NORM_QC_NO}, + {0xF909, UNICODE_NORM_QC_NO}, + {0xF90A, UNICODE_NORM_QC_NO}, + {0xF90B, UNICODE_NORM_QC_NO}, + {0xF90C, UNICODE_NORM_QC_NO}, + {0xF90D, UNICODE_NORM_QC_NO}, + {0xF90E, UNICODE_NORM_QC_NO}, + {0xF90F, UNICODE_NORM_QC_NO}, + {0xF910, UNICODE_NORM_QC_NO}, + {0xF911, UNICODE_NORM_QC_NO}, + {0xF912, UNICODE_NORM_QC_NO}, + {0xF913, UNICODE_NORM_QC_NO}, + {0xF914, UNICODE_NORM_QC_NO}, + {0xF915, UNICODE_NORM_QC_NO}, + {0xF916, UNICODE_NORM_QC_NO}, + {0xF917, UNICODE_NORM_QC_NO}, + {0xF918, UNICODE_NORM_QC_NO}, + {0xF919, UNICODE_NORM_QC_NO}, + {0xF91A, UNICODE_NORM_QC_NO}, + {0xF91B, UNICODE_NORM_QC_NO}, + {0xF91C, UNICODE_NORM_QC_NO}, + {0xF91D, UNICODE_NORM_QC_NO}, + {0xF91E, UNICODE_NORM_QC_NO}, + {0xF91F, UNICODE_NORM_QC_NO}, + {0xF920, UNICODE_NORM_QC_NO}, + {0xF921, UNICODE_NORM_QC_NO}, + {0xF922, UNICODE_NORM_QC_NO}, + {0xF923, UNICODE_NORM_QC_NO}, + {0xF924, UNICODE_NORM_QC_NO}, + {0xF925, UNICODE_NORM_QC_NO}, + {0xF926, UNICODE_NORM_QC_NO}, + {0xF927, UNICODE_NORM_QC_NO}, + {0xF928, UNICODE_NORM_QC_NO}, + {0xF929, UNICODE_NORM_QC_NO}, + {0xF92A, UNICODE_NORM_QC_NO}, + {0xF92B, UNICODE_NORM_QC_NO}, + {0xF92C, UNICODE_NORM_QC_NO}, + {0xF92D, UNICODE_NORM_QC_NO}, + {0xF92E, UNICODE_NORM_QC_NO}, + {0xF92F, UNICODE_NORM_QC_NO}, + {0xF930, UNICODE_NORM_QC_NO}, + {0xF931, UNICODE_NORM_QC_NO}, + {0xF932, UNICODE_NORM_QC_NO}, + {0xF933, UNICODE_NORM_QC_NO}, + {0xF934, UNICODE_NORM_QC_NO}, + {0xF935, UNICODE_NORM_QC_NO}, + {0xF936, UNICODE_NORM_QC_NO}, + {0xF937, UNICODE_NORM_QC_NO}, + {0xF938, UNICODE_NORM_QC_NO}, + {0xF939, UNICODE_NORM_QC_NO}, + {0xF93A, UNICODE_NORM_QC_NO}, + {0xF93B, UNICODE_NORM_QC_NO}, + {0xF93C, UNICODE_NORM_QC_NO}, + {0xF93D, UNICODE_NORM_QC_NO}, + {0xF93E, UNICODE_NORM_QC_NO}, + {0xF93F, UNICODE_NORM_QC_NO}, + {0xF940, UNICODE_NORM_QC_NO}, + {0xF941, UNICODE_NORM_QC_NO}, + {0xF942, UNICODE_NORM_QC_NO}, + {0xF943, UNICODE_NORM_QC_NO}, + {0xF944, UNICODE_NORM_QC_NO}, + {0xF945, UNICODE_NORM_QC_NO}, + {0xF946, UNICODE_NORM_QC_NO}, + {0xF947, UNICODE_NORM_QC_NO}, + {0xF948, UNICODE_NORM_QC_NO}, + {0xF949, UNICODE_NORM_QC_NO}, + {0xF94A, UNICODE_NORM_QC_NO}, + {0xF94B, UNICODE_NORM_QC_NO}, + {0xF94C, UNICODE_NORM_QC_NO}, + {0xF94D, UNICODE_NORM_QC_NO}, + {0xF94E, UNICODE_NORM_QC_NO}, + {0xF94F, UNICODE_NORM_QC_NO}, + {0xF950, UNICODE_NORM_QC_NO}, + {0xF951, UNICODE_NORM_QC_NO}, + {0xF952, UNICODE_NORM_QC_NO}, + {0xF953, UNICODE_NORM_QC_NO}, + {0xF954, UNICODE_NORM_QC_NO}, + {0xF955, UNICODE_NORM_QC_NO}, + {0xF956, UNICODE_NORM_QC_NO}, + {0xF957, UNICODE_NORM_QC_NO}, + {0xF958, UNICODE_NORM_QC_NO}, + {0xF959, UNICODE_NORM_QC_NO}, + {0xF95A, UNICODE_NORM_QC_NO}, + {0xF95B, UNICODE_NORM_QC_NO}, + {0xF95C, UNICODE_NORM_QC_NO}, + {0xF95D, UNICODE_NORM_QC_NO}, + {0xF95E, UNICODE_NORM_QC_NO}, + {0xF95F, UNICODE_NORM_QC_NO}, + {0xF960, UNICODE_NORM_QC_NO}, + {0xF961, UNICODE_NORM_QC_NO}, + {0xF962, UNICODE_NORM_QC_NO}, + {0xF963, UNICODE_NORM_QC_NO}, + {0xF964, UNICODE_NORM_QC_NO}, + {0xF965, UNICODE_NORM_QC_NO}, + {0xF966, UNICODE_NORM_QC_NO}, + {0xF967, UNICODE_NORM_QC_NO}, + {0xF968, UNICODE_NORM_QC_NO}, + {0xF969, UNICODE_NORM_QC_NO}, + {0xF96A, UNICODE_NORM_QC_NO}, + {0xF96B, UNICODE_NORM_QC_NO}, + {0xF96C, UNICODE_NORM_QC_NO}, + {0xF96D, UNICODE_NORM_QC_NO}, + {0xF96E, UNICODE_NORM_QC_NO}, + {0xF96F, UNICODE_NORM_QC_NO}, + {0xF970, UNICODE_NORM_QC_NO}, + {0xF971, UNICODE_NORM_QC_NO}, + {0xF972, UNICODE_NORM_QC_NO}, + {0xF973, UNICODE_NORM_QC_NO}, + {0xF974, UNICODE_NORM_QC_NO}, + {0xF975, UNICODE_NORM_QC_NO}, + {0xF976, UNICODE_NORM_QC_NO}, + {0xF977, UNICODE_NORM_QC_NO}, + {0xF978, UNICODE_NORM_QC_NO}, + {0xF979, UNICODE_NORM_QC_NO}, + {0xF97A, UNICODE_NORM_QC_NO}, + {0xF97B, UNICODE_NORM_QC_NO}, + {0xF97C, UNICODE_NORM_QC_NO}, + {0xF97D, UNICODE_NORM_QC_NO}, + {0xF97E, UNICODE_NORM_QC_NO}, + {0xF97F, UNICODE_NORM_QC_NO}, + {0xF980, UNICODE_NORM_QC_NO}, + {0xF981, UNICODE_NORM_QC_NO}, + {0xF982, UNICODE_NORM_QC_NO}, + {0xF983, UNICODE_NORM_QC_NO}, + {0xF984, UNICODE_NORM_QC_NO}, + {0xF985, UNICODE_NORM_QC_NO}, + {0xF986, UNICODE_NORM_QC_NO}, + {0xF987, UNICODE_NORM_QC_NO}, + {0xF988, UNICODE_NORM_QC_NO}, + {0xF989, UNICODE_NORM_QC_NO}, + {0xF98A, UNICODE_NORM_QC_NO}, + {0xF98B, UNICODE_NORM_QC_NO}, + {0xF98C, UNICODE_NORM_QC_NO}, + {0xF98D, UNICODE_NORM_QC_NO}, + {0xF98E, UNICODE_NORM_QC_NO}, + {0xF98F, UNICODE_NORM_QC_NO}, + {0xF990, UNICODE_NORM_QC_NO}, + {0xF991, UNICODE_NORM_QC_NO}, + {0xF992, UNICODE_NORM_QC_NO}, + {0xF993, UNICODE_NORM_QC_NO}, + {0xF994, UNICODE_NORM_QC_NO}, + {0xF995, UNICODE_NORM_QC_NO}, + {0xF996, UNICODE_NORM_QC_NO}, + {0xF997, UNICODE_NORM_QC_NO}, + {0xF998, UNICODE_NORM_QC_NO}, + {0xF999, UNICODE_NORM_QC_NO}, + {0xF99A, UNICODE_NORM_QC_NO}, + {0xF99B, UNICODE_NORM_QC_NO}, + {0xF99C, UNICODE_NORM_QC_NO}, + {0xF99D, UNICODE_NORM_QC_NO}, + {0xF99E, UNICODE_NORM_QC_NO}, + {0xF99F, UNICODE_NORM_QC_NO}, + {0xF9A0, UNICODE_NORM_QC_NO}, + {0xF9A1, UNICODE_NORM_QC_NO}, + {0xF9A2, UNICODE_NORM_QC_NO}, + {0xF9A3, UNICODE_NORM_QC_NO}, + {0xF9A4, UNICODE_NORM_QC_NO}, + {0xF9A5, UNICODE_NORM_QC_NO}, + {0xF9A6, UNICODE_NORM_QC_NO}, + {0xF9A7, UNICODE_NORM_QC_NO}, + {0xF9A8, UNICODE_NORM_QC_NO}, + {0xF9A9, UNICODE_NORM_QC_NO}, + {0xF9AA, UNICODE_NORM_QC_NO}, + {0xF9AB, UNICODE_NORM_QC_NO}, + {0xF9AC, UNICODE_NORM_QC_NO}, + {0xF9AD, UNICODE_NORM_QC_NO}, + {0xF9AE, UNICODE_NORM_QC_NO}, + {0xF9AF, UNICODE_NORM_QC_NO}, + {0xF9B0, UNICODE_NORM_QC_NO}, + {0xF9B1, UNICODE_NORM_QC_NO}, + {0xF9B2, UNICODE_NORM_QC_NO}, + {0xF9B3, UNICODE_NORM_QC_NO}, + {0xF9B4, UNICODE_NORM_QC_NO}, + {0xF9B5, UNICODE_NORM_QC_NO}, + {0xF9B6, UNICODE_NORM_QC_NO}, + {0xF9B7, UNICODE_NORM_QC_NO}, + {0xF9B8, UNICODE_NORM_QC_NO}, + {0xF9B9, UNICODE_NORM_QC_NO}, + {0xF9BA, UNICODE_NORM_QC_NO}, + {0xF9BB, UNICODE_NORM_QC_NO}, + {0xF9BC, UNICODE_NORM_QC_NO}, + {0xF9BD, UNICODE_NORM_QC_NO}, + {0xF9BE, UNICODE_NORM_QC_NO}, + {0xF9BF, UNICODE_NORM_QC_NO}, + {0xF9C0, UNICODE_NORM_QC_NO}, + {0xF9C1, UNICODE_NORM_QC_NO}, + {0xF9C2, UNICODE_NORM_QC_NO}, + {0xF9C3, UNICODE_NORM_QC_NO}, + {0xF9C4, UNICODE_NORM_QC_NO}, + {0xF9C5, UNICODE_NORM_QC_NO}, + {0xF9C6, UNICODE_NORM_QC_NO}, + {0xF9C7, UNICODE_NORM_QC_NO}, + {0xF9C8, UNICODE_NORM_QC_NO}, + {0xF9C9, UNICODE_NORM_QC_NO}, + {0xF9CA, UNICODE_NORM_QC_NO}, + {0xF9CB, UNICODE_NORM_QC_NO}, + {0xF9CC, UNICODE_NORM_QC_NO}, + {0xF9CD, UNICODE_NORM_QC_NO}, + {0xF9CE, UNICODE_NORM_QC_NO}, + {0xF9CF, UNICODE_NORM_QC_NO}, + {0xF9D0, UNICODE_NORM_QC_NO}, + {0xF9D1, UNICODE_NORM_QC_NO}, + {0xF9D2, UNICODE_NORM_QC_NO}, + {0xF9D3, UNICODE_NORM_QC_NO}, + {0xF9D4, UNICODE_NORM_QC_NO}, + {0xF9D5, UNICODE_NORM_QC_NO}, + {0xF9D6, UNICODE_NORM_QC_NO}, + {0xF9D7, UNICODE_NORM_QC_NO}, + {0xF9D8, UNICODE_NORM_QC_NO}, + {0xF9D9, UNICODE_NORM_QC_NO}, + {0xF9DA, UNICODE_NORM_QC_NO}, + {0xF9DB, UNICODE_NORM_QC_NO}, + {0xF9DC, UNICODE_NORM_QC_NO}, + {0xF9DD, UNICODE_NORM_QC_NO}, + {0xF9DE, UNICODE_NORM_QC_NO}, + {0xF9DF, UNICODE_NORM_QC_NO}, + {0xF9E0, UNICODE_NORM_QC_NO}, + {0xF9E1, UNICODE_NORM_QC_NO}, + {0xF9E2, UNICODE_NORM_QC_NO}, + {0xF9E3, UNICODE_NORM_QC_NO}, + {0xF9E4, UNICODE_NORM_QC_NO}, + {0xF9E5, UNICODE_NORM_QC_NO}, + {0xF9E6, UNICODE_NORM_QC_NO}, + {0xF9E7, UNICODE_NORM_QC_NO}, + {0xF9E8, UNICODE_NORM_QC_NO}, + {0xF9E9, UNICODE_NORM_QC_NO}, + {0xF9EA, UNICODE_NORM_QC_NO}, + {0xF9EB, UNICODE_NORM_QC_NO}, + {0xF9EC, UNICODE_NORM_QC_NO}, + {0xF9ED, UNICODE_NORM_QC_NO}, + {0xF9EE, UNICODE_NORM_QC_NO}, + {0xF9EF, UNICODE_NORM_QC_NO}, + {0xF9F0, UNICODE_NORM_QC_NO}, + {0xF9F1, UNICODE_NORM_QC_NO}, + {0xF9F2, UNICODE_NORM_QC_NO}, + {0xF9F3, UNICODE_NORM_QC_NO}, + {0xF9F4, UNICODE_NORM_QC_NO}, + {0xF9F5, UNICODE_NORM_QC_NO}, + {0xF9F6, UNICODE_NORM_QC_NO}, + {0xF9F7, UNICODE_NORM_QC_NO}, + {0xF9F8, UNICODE_NORM_QC_NO}, + {0xF9F9, UNICODE_NORM_QC_NO}, + {0xF9FA, UNICODE_NORM_QC_NO}, + {0xF9FB, UNICODE_NORM_QC_NO}, + {0xF9FC, UNICODE_NORM_QC_NO}, + {0xF9FD, UNICODE_NORM_QC_NO}, + {0xF9FE, UNICODE_NORM_QC_NO}, + {0xF9FF, UNICODE_NORM_QC_NO}, + {0xFA00, UNICODE_NORM_QC_NO}, + {0xFA01, UNICODE_NORM_QC_NO}, + {0xFA02, UNICODE_NORM_QC_NO}, + {0xFA03, UNICODE_NORM_QC_NO}, + {0xFA04, UNICODE_NORM_QC_NO}, + {0xFA05, UNICODE_NORM_QC_NO}, + {0xFA06, UNICODE_NORM_QC_NO}, + {0xFA07, UNICODE_NORM_QC_NO}, + {0xFA08, UNICODE_NORM_QC_NO}, + {0xFA09, UNICODE_NORM_QC_NO}, + {0xFA0A, UNICODE_NORM_QC_NO}, + {0xFA0B, UNICODE_NORM_QC_NO}, + {0xFA0C, UNICODE_NORM_QC_NO}, + {0xFA0D, UNICODE_NORM_QC_NO}, + {0xFA10, UNICODE_NORM_QC_NO}, + {0xFA12, UNICODE_NORM_QC_NO}, + {0xFA15, UNICODE_NORM_QC_NO}, + {0xFA16, UNICODE_NORM_QC_NO}, + {0xFA17, UNICODE_NORM_QC_NO}, + {0xFA18, UNICODE_NORM_QC_NO}, + {0xFA19, UNICODE_NORM_QC_NO}, + {0xFA1A, UNICODE_NORM_QC_NO}, + {0xFA1B, UNICODE_NORM_QC_NO}, + {0xFA1C, UNICODE_NORM_QC_NO}, + {0xFA1D, UNICODE_NORM_QC_NO}, + {0xFA1E, UNICODE_NORM_QC_NO}, + {0xFA20, UNICODE_NORM_QC_NO}, + {0xFA22, UNICODE_NORM_QC_NO}, + {0xFA25, UNICODE_NORM_QC_NO}, + {0xFA26, UNICODE_NORM_QC_NO}, + {0xFA2A, UNICODE_NORM_QC_NO}, + {0xFA2B, UNICODE_NORM_QC_NO}, + {0xFA2C, UNICODE_NORM_QC_NO}, + {0xFA2D, UNICODE_NORM_QC_NO}, + {0xFA2E, UNICODE_NORM_QC_NO}, + {0xFA2F, UNICODE_NORM_QC_NO}, + {0xFA30, UNICODE_NORM_QC_NO}, + {0xFA31, UNICODE_NORM_QC_NO}, + {0xFA32, UNICODE_NORM_QC_NO}, + {0xFA33, UNICODE_NORM_QC_NO}, + {0xFA34, UNICODE_NORM_QC_NO}, + {0xFA35, UNICODE_NORM_QC_NO}, + {0xFA36, UNICODE_NORM_QC_NO}, + {0xFA37, UNICODE_NORM_QC_NO}, + {0xFA38, UNICODE_NORM_QC_NO}, + {0xFA39, UNICODE_NORM_QC_NO}, + {0xFA3A, UNICODE_NORM_QC_NO}, + {0xFA3B, UNICODE_NORM_QC_NO}, + {0xFA3C, UNICODE_NORM_QC_NO}, + {0xFA3D, UNICODE_NORM_QC_NO}, + {0xFA3E, UNICODE_NORM_QC_NO}, + {0xFA3F, UNICODE_NORM_QC_NO}, + {0xFA40, UNICODE_NORM_QC_NO}, + {0xFA41, UNICODE_NORM_QC_NO}, + {0xFA42, UNICODE_NORM_QC_NO}, + {0xFA43, UNICODE_NORM_QC_NO}, + {0xFA44, UNICODE_NORM_QC_NO}, + {0xFA45, UNICODE_NORM_QC_NO}, + {0xFA46, UNICODE_NORM_QC_NO}, + {0xFA47, UNICODE_NORM_QC_NO}, + {0xFA48, UNICODE_NORM_QC_NO}, + {0xFA49, UNICODE_NORM_QC_NO}, + {0xFA4A, UNICODE_NORM_QC_NO}, + {0xFA4B, UNICODE_NORM_QC_NO}, + {0xFA4C, UNICODE_NORM_QC_NO}, + {0xFA4D, UNICODE_NORM_QC_NO}, + {0xFA4E, UNICODE_NORM_QC_NO}, + {0xFA4F, UNICODE_NORM_QC_NO}, + {0xFA50, UNICODE_NORM_QC_NO}, + {0xFA51, UNICODE_NORM_QC_NO}, + {0xFA52, UNICODE_NORM_QC_NO}, + {0xFA53, UNICODE_NORM_QC_NO}, + {0xFA54, UNICODE_NORM_QC_NO}, + {0xFA55, UNICODE_NORM_QC_NO}, + {0xFA56, UNICODE_NORM_QC_NO}, + {0xFA57, UNICODE_NORM_QC_NO}, + {0xFA58, UNICODE_NORM_QC_NO}, + {0xFA59, UNICODE_NORM_QC_NO}, + {0xFA5A, UNICODE_NORM_QC_NO}, + {0xFA5B, UNICODE_NORM_QC_NO}, + {0xFA5C, UNICODE_NORM_QC_NO}, + {0xFA5D, UNICODE_NORM_QC_NO}, + {0xFA5E, UNICODE_NORM_QC_NO}, + {0xFA5F, UNICODE_NORM_QC_NO}, + {0xFA60, UNICODE_NORM_QC_NO}, + {0xFA61, UNICODE_NORM_QC_NO}, + {0xFA62, UNICODE_NORM_QC_NO}, + {0xFA63, UNICODE_NORM_QC_NO}, + {0xFA64, UNICODE_NORM_QC_NO}, + {0xFA65, UNICODE_NORM_QC_NO}, + {0xFA66, UNICODE_NORM_QC_NO}, + {0xFA67, UNICODE_NORM_QC_NO}, + {0xFA68, UNICODE_NORM_QC_NO}, + {0xFA69, UNICODE_NORM_QC_NO}, + {0xFA6A, UNICODE_NORM_QC_NO}, + {0xFA6B, UNICODE_NORM_QC_NO}, + {0xFA6C, UNICODE_NORM_QC_NO}, + {0xFA6D, UNICODE_NORM_QC_NO}, + {0xFA70, UNICODE_NORM_QC_NO}, + {0xFA71, UNICODE_NORM_QC_NO}, + {0xFA72, UNICODE_NORM_QC_NO}, + {0xFA73, UNICODE_NORM_QC_NO}, + {0xFA74, UNICODE_NORM_QC_NO}, + {0xFA75, UNICODE_NORM_QC_NO}, + {0xFA76, UNICODE_NORM_QC_NO}, + {0xFA77, UNICODE_NORM_QC_NO}, + {0xFA78, UNICODE_NORM_QC_NO}, + {0xFA79, UNICODE_NORM_QC_NO}, + {0xFA7A, UNICODE_NORM_QC_NO}, + {0xFA7B, UNICODE_NORM_QC_NO}, + {0xFA7C, UNICODE_NORM_QC_NO}, + {0xFA7D, UNICODE_NORM_QC_NO}, + {0xFA7E, UNICODE_NORM_QC_NO}, + {0xFA7F, UNICODE_NORM_QC_NO}, + {0xFA80, UNICODE_NORM_QC_NO}, + {0xFA81, UNICODE_NORM_QC_NO}, + {0xFA82, UNICODE_NORM_QC_NO}, + {0xFA83, UNICODE_NORM_QC_NO}, + {0xFA84, UNICODE_NORM_QC_NO}, + {0xFA85, UNICODE_NORM_QC_NO}, + {0xFA86, UNICODE_NORM_QC_NO}, + {0xFA87, UNICODE_NORM_QC_NO}, + {0xFA88, UNICODE_NORM_QC_NO}, + {0xFA89, UNICODE_NORM_QC_NO}, + {0xFA8A, UNICODE_NORM_QC_NO}, + {0xFA8B, UNICODE_NORM_QC_NO}, + {0xFA8C, UNICODE_NORM_QC_NO}, + {0xFA8D, UNICODE_NORM_QC_NO}, + {0xFA8E, UNICODE_NORM_QC_NO}, + {0xFA8F, UNICODE_NORM_QC_NO}, + {0xFA90, UNICODE_NORM_QC_NO}, + {0xFA91, UNICODE_NORM_QC_NO}, + {0xFA92, UNICODE_NORM_QC_NO}, + {0xFA93, UNICODE_NORM_QC_NO}, + {0xFA94, UNICODE_NORM_QC_NO}, + {0xFA95, UNICODE_NORM_QC_NO}, + {0xFA96, UNICODE_NORM_QC_NO}, + {0xFA97, UNICODE_NORM_QC_NO}, + {0xFA98, UNICODE_NORM_QC_NO}, + {0xFA99, UNICODE_NORM_QC_NO}, + {0xFA9A, UNICODE_NORM_QC_NO}, + {0xFA9B, UNICODE_NORM_QC_NO}, + {0xFA9C, UNICODE_NORM_QC_NO}, + {0xFA9D, UNICODE_NORM_QC_NO}, + {0xFA9E, UNICODE_NORM_QC_NO}, + {0xFA9F, UNICODE_NORM_QC_NO}, + {0xFAA0, UNICODE_NORM_QC_NO}, + {0xFAA1, UNICODE_NORM_QC_NO}, + {0xFAA2, UNICODE_NORM_QC_NO}, + {0xFAA3, UNICODE_NORM_QC_NO}, + {0xFAA4, UNICODE_NORM_QC_NO}, + {0xFAA5, UNICODE_NORM_QC_NO}, + {0xFAA6, UNICODE_NORM_QC_NO}, + {0xFAA7, UNICODE_NORM_QC_NO}, + {0xFAA8, UNICODE_NORM_QC_NO}, + {0xFAA9, UNICODE_NORM_QC_NO}, + {0xFAAA, UNICODE_NORM_QC_NO}, + {0xFAAB, UNICODE_NORM_QC_NO}, + {0xFAAC, UNICODE_NORM_QC_NO}, + {0xFAAD, UNICODE_NORM_QC_NO}, + {0xFAAE, UNICODE_NORM_QC_NO}, + {0xFAAF, UNICODE_NORM_QC_NO}, + {0xFAB0, UNICODE_NORM_QC_NO}, + {0xFAB1, UNICODE_NORM_QC_NO}, + {0xFAB2, UNICODE_NORM_QC_NO}, + {0xFAB3, UNICODE_NORM_QC_NO}, + {0xFAB4, UNICODE_NORM_QC_NO}, + {0xFAB5, UNICODE_NORM_QC_NO}, + {0xFAB6, UNICODE_NORM_QC_NO}, + {0xFAB7, UNICODE_NORM_QC_NO}, + {0xFAB8, UNICODE_NORM_QC_NO}, + {0xFAB9, UNICODE_NORM_QC_NO}, + {0xFABA, UNICODE_NORM_QC_NO}, + {0xFABB, UNICODE_NORM_QC_NO}, + {0xFABC, UNICODE_NORM_QC_NO}, + {0xFABD, UNICODE_NORM_QC_NO}, + {0xFABE, UNICODE_NORM_QC_NO}, + {0xFABF, UNICODE_NORM_QC_NO}, + {0xFAC0, UNICODE_NORM_QC_NO}, + {0xFAC1, UNICODE_NORM_QC_NO}, + {0xFAC2, UNICODE_NORM_QC_NO}, + {0xFAC3, UNICODE_NORM_QC_NO}, + {0xFAC4, UNICODE_NORM_QC_NO}, + {0xFAC5, UNICODE_NORM_QC_NO}, + {0xFAC6, UNICODE_NORM_QC_NO}, + {0xFAC7, UNICODE_NORM_QC_NO}, + {0xFAC8, UNICODE_NORM_QC_NO}, + {0xFAC9, UNICODE_NORM_QC_NO}, + {0xFACA, UNICODE_NORM_QC_NO}, + {0xFACB, UNICODE_NORM_QC_NO}, + {0xFACC, UNICODE_NORM_QC_NO}, + {0xFACD, UNICODE_NORM_QC_NO}, + {0xFACE, UNICODE_NORM_QC_NO}, + {0xFACF, UNICODE_NORM_QC_NO}, + {0xFAD0, UNICODE_NORM_QC_NO}, + {0xFAD1, UNICODE_NORM_QC_NO}, + {0xFAD2, UNICODE_NORM_QC_NO}, + {0xFAD3, UNICODE_NORM_QC_NO}, + {0xFAD4, UNICODE_NORM_QC_NO}, + {0xFAD5, UNICODE_NORM_QC_NO}, + {0xFAD6, UNICODE_NORM_QC_NO}, + {0xFAD7, UNICODE_NORM_QC_NO}, + {0xFAD8, UNICODE_NORM_QC_NO}, + {0xFAD9, UNICODE_NORM_QC_NO}, + {0xFB00, UNICODE_NORM_QC_NO}, + {0xFB01, UNICODE_NORM_QC_NO}, + {0xFB02, UNICODE_NORM_QC_NO}, + {0xFB03, UNICODE_NORM_QC_NO}, + {0xFB04, UNICODE_NORM_QC_NO}, + {0xFB05, UNICODE_NORM_QC_NO}, + {0xFB06, UNICODE_NORM_QC_NO}, + {0xFB13, UNICODE_NORM_QC_NO}, + {0xFB14, UNICODE_NORM_QC_NO}, + {0xFB15, UNICODE_NORM_QC_NO}, + {0xFB16, UNICODE_NORM_QC_NO}, + {0xFB17, UNICODE_NORM_QC_NO}, + {0xFB1D, UNICODE_NORM_QC_NO}, + {0xFB1F, UNICODE_NORM_QC_NO}, + {0xFB20, UNICODE_NORM_QC_NO}, + {0xFB21, UNICODE_NORM_QC_NO}, + {0xFB22, UNICODE_NORM_QC_NO}, + {0xFB23, UNICODE_NORM_QC_NO}, + {0xFB24, UNICODE_NORM_QC_NO}, + {0xFB25, UNICODE_NORM_QC_NO}, + {0xFB26, UNICODE_NORM_QC_NO}, + {0xFB27, UNICODE_NORM_QC_NO}, + {0xFB28, UNICODE_NORM_QC_NO}, + {0xFB29, UNICODE_NORM_QC_NO}, + {0xFB2A, UNICODE_NORM_QC_NO}, + {0xFB2B, UNICODE_NORM_QC_NO}, + {0xFB2C, UNICODE_NORM_QC_NO}, + {0xFB2D, UNICODE_NORM_QC_NO}, + {0xFB2E, UNICODE_NORM_QC_NO}, + {0xFB2F, UNICODE_NORM_QC_NO}, + {0xFB30, UNICODE_NORM_QC_NO}, + {0xFB31, UNICODE_NORM_QC_NO}, + {0xFB32, UNICODE_NORM_QC_NO}, + {0xFB33, UNICODE_NORM_QC_NO}, + {0xFB34, UNICODE_NORM_QC_NO}, + {0xFB35, UNICODE_NORM_QC_NO}, + {0xFB36, UNICODE_NORM_QC_NO}, + {0xFB38, UNICODE_NORM_QC_NO}, + {0xFB39, UNICODE_NORM_QC_NO}, + {0xFB3A, UNICODE_NORM_QC_NO}, + {0xFB3B, UNICODE_NORM_QC_NO}, + {0xFB3C, UNICODE_NORM_QC_NO}, + {0xFB3E, UNICODE_NORM_QC_NO}, + {0xFB40, UNICODE_NORM_QC_NO}, + {0xFB41, UNICODE_NORM_QC_NO}, + {0xFB43, UNICODE_NORM_QC_NO}, + {0xFB44, UNICODE_NORM_QC_NO}, + {0xFB46, UNICODE_NORM_QC_NO}, + {0xFB47, UNICODE_NORM_QC_NO}, + {0xFB48, UNICODE_NORM_QC_NO}, + {0xFB49, UNICODE_NORM_QC_NO}, + {0xFB4A, UNICODE_NORM_QC_NO}, + {0xFB4B, UNICODE_NORM_QC_NO}, + {0xFB4C, UNICODE_NORM_QC_NO}, + {0xFB4D, UNICODE_NORM_QC_NO}, + {0xFB4E, UNICODE_NORM_QC_NO}, + {0xFB4F, UNICODE_NORM_QC_NO}, + {0xFB50, UNICODE_NORM_QC_NO}, + {0xFB51, UNICODE_NORM_QC_NO}, + {0xFB52, UNICODE_NORM_QC_NO}, + {0xFB53, UNICODE_NORM_QC_NO}, + {0xFB54, UNICODE_NORM_QC_NO}, + {0xFB55, UNICODE_NORM_QC_NO}, + {0xFB56, UNICODE_NORM_QC_NO}, + {0xFB57, UNICODE_NORM_QC_NO}, + {0xFB58, UNICODE_NORM_QC_NO}, + {0xFB59, UNICODE_NORM_QC_NO}, + {0xFB5A, UNICODE_NORM_QC_NO}, + {0xFB5B, UNICODE_NORM_QC_NO}, + {0xFB5C, UNICODE_NORM_QC_NO}, + {0xFB5D, UNICODE_NORM_QC_NO}, + {0xFB5E, UNICODE_NORM_QC_NO}, + {0xFB5F, UNICODE_NORM_QC_NO}, + {0xFB60, UNICODE_NORM_QC_NO}, + {0xFB61, UNICODE_NORM_QC_NO}, + {0xFB62, UNICODE_NORM_QC_NO}, + {0xFB63, UNICODE_NORM_QC_NO}, + {0xFB64, UNICODE_NORM_QC_NO}, + {0xFB65, UNICODE_NORM_QC_NO}, + {0xFB66, UNICODE_NORM_QC_NO}, + {0xFB67, UNICODE_NORM_QC_NO}, + {0xFB68, UNICODE_NORM_QC_NO}, + {0xFB69, UNICODE_NORM_QC_NO}, + {0xFB6A, UNICODE_NORM_QC_NO}, + {0xFB6B, UNICODE_NORM_QC_NO}, + {0xFB6C, UNICODE_NORM_QC_NO}, + {0xFB6D, UNICODE_NORM_QC_NO}, + {0xFB6E, UNICODE_NORM_QC_NO}, + {0xFB6F, UNICODE_NORM_QC_NO}, + {0xFB70, UNICODE_NORM_QC_NO}, + {0xFB71, UNICODE_NORM_QC_NO}, + {0xFB72, UNICODE_NORM_QC_NO}, + {0xFB73, UNICODE_NORM_QC_NO}, + {0xFB74, UNICODE_NORM_QC_NO}, + {0xFB75, UNICODE_NORM_QC_NO}, + {0xFB76, UNICODE_NORM_QC_NO}, + {0xFB77, UNICODE_NORM_QC_NO}, + {0xFB78, UNICODE_NORM_QC_NO}, + {0xFB79, UNICODE_NORM_QC_NO}, + {0xFB7A, UNICODE_NORM_QC_NO}, + {0xFB7B, UNICODE_NORM_QC_NO}, + {0xFB7C, UNICODE_NORM_QC_NO}, + {0xFB7D, UNICODE_NORM_QC_NO}, + {0xFB7E, UNICODE_NORM_QC_NO}, + {0xFB7F, UNICODE_NORM_QC_NO}, + {0xFB80, UNICODE_NORM_QC_NO}, + {0xFB81, UNICODE_NORM_QC_NO}, + {0xFB82, UNICODE_NORM_QC_NO}, + {0xFB83, UNICODE_NORM_QC_NO}, + {0xFB84, UNICODE_NORM_QC_NO}, + {0xFB85, UNICODE_NORM_QC_NO}, + {0xFB86, UNICODE_NORM_QC_NO}, + {0xFB87, UNICODE_NORM_QC_NO}, + {0xFB88, UNICODE_NORM_QC_NO}, + {0xFB89, UNICODE_NORM_QC_NO}, + {0xFB8A, UNICODE_NORM_QC_NO}, + {0xFB8B, UNICODE_NORM_QC_NO}, + {0xFB8C, UNICODE_NORM_QC_NO}, + {0xFB8D, UNICODE_NORM_QC_NO}, + {0xFB8E, UNICODE_NORM_QC_NO}, + {0xFB8F, UNICODE_NORM_QC_NO}, + {0xFB90, UNICODE_NORM_QC_NO}, + {0xFB91, UNICODE_NORM_QC_NO}, + {0xFB92, UNICODE_NORM_QC_NO}, + {0xFB93, UNICODE_NORM_QC_NO}, + {0xFB94, UNICODE_NORM_QC_NO}, + {0xFB95, UNICODE_NORM_QC_NO}, + {0xFB96, UNICODE_NORM_QC_NO}, + {0xFB97, UNICODE_NORM_QC_NO}, + {0xFB98, UNICODE_NORM_QC_NO}, + {0xFB99, UNICODE_NORM_QC_NO}, + {0xFB9A, UNICODE_NORM_QC_NO}, + {0xFB9B, UNICODE_NORM_QC_NO}, + {0xFB9C, UNICODE_NORM_QC_NO}, + {0xFB9D, UNICODE_NORM_QC_NO}, + {0xFB9E, UNICODE_NORM_QC_NO}, + {0xFB9F, UNICODE_NORM_QC_NO}, + {0xFBA0, UNICODE_NORM_QC_NO}, + {0xFBA1, UNICODE_NORM_QC_NO}, + {0xFBA2, UNICODE_NORM_QC_NO}, + {0xFBA3, UNICODE_NORM_QC_NO}, + {0xFBA4, UNICODE_NORM_QC_NO}, + {0xFBA5, UNICODE_NORM_QC_NO}, + {0xFBA6, UNICODE_NORM_QC_NO}, + {0xFBA7, UNICODE_NORM_QC_NO}, + {0xFBA8, UNICODE_NORM_QC_NO}, + {0xFBA9, UNICODE_NORM_QC_NO}, + {0xFBAA, UNICODE_NORM_QC_NO}, + {0xFBAB, UNICODE_NORM_QC_NO}, + {0xFBAC, UNICODE_NORM_QC_NO}, + {0xFBAD, UNICODE_NORM_QC_NO}, + {0xFBAE, UNICODE_NORM_QC_NO}, + {0xFBAF, UNICODE_NORM_QC_NO}, + {0xFBB0, UNICODE_NORM_QC_NO}, + {0xFBB1, UNICODE_NORM_QC_NO}, + {0xFBD3, UNICODE_NORM_QC_NO}, + {0xFBD4, UNICODE_NORM_QC_NO}, + {0xFBD5, UNICODE_NORM_QC_NO}, + {0xFBD6, UNICODE_NORM_QC_NO}, + {0xFBD7, UNICODE_NORM_QC_NO}, + {0xFBD8, UNICODE_NORM_QC_NO}, + {0xFBD9, UNICODE_NORM_QC_NO}, + {0xFBDA, UNICODE_NORM_QC_NO}, + {0xFBDB, UNICODE_NORM_QC_NO}, + {0xFBDC, UNICODE_NORM_QC_NO}, + {0xFBDD, UNICODE_NORM_QC_NO}, + {0xFBDE, UNICODE_NORM_QC_NO}, + {0xFBDF, UNICODE_NORM_QC_NO}, + {0xFBE0, UNICODE_NORM_QC_NO}, + {0xFBE1, UNICODE_NORM_QC_NO}, + {0xFBE2, UNICODE_NORM_QC_NO}, + {0xFBE3, UNICODE_NORM_QC_NO}, + {0xFBE4, UNICODE_NORM_QC_NO}, + {0xFBE5, UNICODE_NORM_QC_NO}, + {0xFBE6, UNICODE_NORM_QC_NO}, + {0xFBE7, UNICODE_NORM_QC_NO}, + {0xFBE8, UNICODE_NORM_QC_NO}, + {0xFBE9, UNICODE_NORM_QC_NO}, + {0xFBEA, UNICODE_NORM_QC_NO}, + {0xFBEB, UNICODE_NORM_QC_NO}, + {0xFBEC, UNICODE_NORM_QC_NO}, + {0xFBED, UNICODE_NORM_QC_NO}, + {0xFBEE, UNICODE_NORM_QC_NO}, + {0xFBEF, UNICODE_NORM_QC_NO}, + {0xFBF0, UNICODE_NORM_QC_NO}, + {0xFBF1, UNICODE_NORM_QC_NO}, + {0xFBF2, UNICODE_NORM_QC_NO}, + {0xFBF3, UNICODE_NORM_QC_NO}, + {0xFBF4, UNICODE_NORM_QC_NO}, + {0xFBF5, UNICODE_NORM_QC_NO}, + {0xFBF6, UNICODE_NORM_QC_NO}, + {0xFBF7, UNICODE_NORM_QC_NO}, + {0xFBF8, UNICODE_NORM_QC_NO}, + {0xFBF9, UNICODE_NORM_QC_NO}, + {0xFBFA, UNICODE_NORM_QC_NO}, + {0xFBFB, UNICODE_NORM_QC_NO}, + {0xFBFC, UNICODE_NORM_QC_NO}, + {0xFBFD, UNICODE_NORM_QC_NO}, + {0xFBFE, UNICODE_NORM_QC_NO}, + {0xFBFF, UNICODE_NORM_QC_NO}, + {0xFC00, UNICODE_NORM_QC_NO}, + {0xFC01, UNICODE_NORM_QC_NO}, + {0xFC02, UNICODE_NORM_QC_NO}, + {0xFC03, UNICODE_NORM_QC_NO}, + {0xFC04, UNICODE_NORM_QC_NO}, + {0xFC05, UNICODE_NORM_QC_NO}, + {0xFC06, UNICODE_NORM_QC_NO}, + {0xFC07, UNICODE_NORM_QC_NO}, + {0xFC08, UNICODE_NORM_QC_NO}, + {0xFC09, UNICODE_NORM_QC_NO}, + {0xFC0A, UNICODE_NORM_QC_NO}, + {0xFC0B, UNICODE_NORM_QC_NO}, + {0xFC0C, UNICODE_NORM_QC_NO}, + {0xFC0D, UNICODE_NORM_QC_NO}, + {0xFC0E, UNICODE_NORM_QC_NO}, + {0xFC0F, UNICODE_NORM_QC_NO}, + {0xFC10, UNICODE_NORM_QC_NO}, + {0xFC11, UNICODE_NORM_QC_NO}, + {0xFC12, UNICODE_NORM_QC_NO}, + {0xFC13, UNICODE_NORM_QC_NO}, + {0xFC14, UNICODE_NORM_QC_NO}, + {0xFC15, UNICODE_NORM_QC_NO}, + {0xFC16, UNICODE_NORM_QC_NO}, + {0xFC17, UNICODE_NORM_QC_NO}, + {0xFC18, UNICODE_NORM_QC_NO}, + {0xFC19, UNICODE_NORM_QC_NO}, + {0xFC1A, UNICODE_NORM_QC_NO}, + {0xFC1B, UNICODE_NORM_QC_NO}, + {0xFC1C, UNICODE_NORM_QC_NO}, + {0xFC1D, UNICODE_NORM_QC_NO}, + {0xFC1E, UNICODE_NORM_QC_NO}, + {0xFC1F, UNICODE_NORM_QC_NO}, + {0xFC20, UNICODE_NORM_QC_NO}, + {0xFC21, UNICODE_NORM_QC_NO}, + {0xFC22, UNICODE_NORM_QC_NO}, + {0xFC23, UNICODE_NORM_QC_NO}, + {0xFC24, UNICODE_NORM_QC_NO}, + {0xFC25, UNICODE_NORM_QC_NO}, + {0xFC26, UNICODE_NORM_QC_NO}, + {0xFC27, UNICODE_NORM_QC_NO}, + {0xFC28, UNICODE_NORM_QC_NO}, + {0xFC29, UNICODE_NORM_QC_NO}, + {0xFC2A, UNICODE_NORM_QC_NO}, + {0xFC2B, UNICODE_NORM_QC_NO}, + {0xFC2C, UNICODE_NORM_QC_NO}, + {0xFC2D, UNICODE_NORM_QC_NO}, + {0xFC2E, UNICODE_NORM_QC_NO}, + {0xFC2F, UNICODE_NORM_QC_NO}, + {0xFC30, UNICODE_NORM_QC_NO}, + {0xFC31, UNICODE_NORM_QC_NO}, + {0xFC32, UNICODE_NORM_QC_NO}, + {0xFC33, UNICODE_NORM_QC_NO}, + {0xFC34, UNICODE_NORM_QC_NO}, + {0xFC35, UNICODE_NORM_QC_NO}, + {0xFC36, UNICODE_NORM_QC_NO}, + {0xFC37, UNICODE_NORM_QC_NO}, + {0xFC38, UNICODE_NORM_QC_NO}, + {0xFC39, UNICODE_NORM_QC_NO}, + {0xFC3A, UNICODE_NORM_QC_NO}, + {0xFC3B, UNICODE_NORM_QC_NO}, + {0xFC3C, UNICODE_NORM_QC_NO}, + {0xFC3D, UNICODE_NORM_QC_NO}, + {0xFC3E, UNICODE_NORM_QC_NO}, + {0xFC3F, UNICODE_NORM_QC_NO}, + {0xFC40, UNICODE_NORM_QC_NO}, + {0xFC41, UNICODE_NORM_QC_NO}, + {0xFC42, UNICODE_NORM_QC_NO}, + {0xFC43, UNICODE_NORM_QC_NO}, + {0xFC44, UNICODE_NORM_QC_NO}, + {0xFC45, UNICODE_NORM_QC_NO}, + {0xFC46, UNICODE_NORM_QC_NO}, + {0xFC47, UNICODE_NORM_QC_NO}, + {0xFC48, UNICODE_NORM_QC_NO}, + {0xFC49, UNICODE_NORM_QC_NO}, + {0xFC4A, UNICODE_NORM_QC_NO}, + {0xFC4B, UNICODE_NORM_QC_NO}, + {0xFC4C, UNICODE_NORM_QC_NO}, + {0xFC4D, UNICODE_NORM_QC_NO}, + {0xFC4E, UNICODE_NORM_QC_NO}, + {0xFC4F, UNICODE_NORM_QC_NO}, + {0xFC50, UNICODE_NORM_QC_NO}, + {0xFC51, UNICODE_NORM_QC_NO}, + {0xFC52, UNICODE_NORM_QC_NO}, + {0xFC53, UNICODE_NORM_QC_NO}, + {0xFC54, UNICODE_NORM_QC_NO}, + {0xFC55, UNICODE_NORM_QC_NO}, + {0xFC56, UNICODE_NORM_QC_NO}, + {0xFC57, UNICODE_NORM_QC_NO}, + {0xFC58, UNICODE_NORM_QC_NO}, + {0xFC59, UNICODE_NORM_QC_NO}, + {0xFC5A, UNICODE_NORM_QC_NO}, + {0xFC5B, UNICODE_NORM_QC_NO}, + {0xFC5C, UNICODE_NORM_QC_NO}, + {0xFC5D, UNICODE_NORM_QC_NO}, + {0xFC5E, UNICODE_NORM_QC_NO}, + {0xFC5F, UNICODE_NORM_QC_NO}, + {0xFC60, UNICODE_NORM_QC_NO}, + {0xFC61, UNICODE_NORM_QC_NO}, + {0xFC62, UNICODE_NORM_QC_NO}, + {0xFC63, UNICODE_NORM_QC_NO}, + {0xFC64, UNICODE_NORM_QC_NO}, + {0xFC65, UNICODE_NORM_QC_NO}, + {0xFC66, UNICODE_NORM_QC_NO}, + {0xFC67, UNICODE_NORM_QC_NO}, + {0xFC68, UNICODE_NORM_QC_NO}, + {0xFC69, UNICODE_NORM_QC_NO}, + {0xFC6A, UNICODE_NORM_QC_NO}, + {0xFC6B, UNICODE_NORM_QC_NO}, + {0xFC6C, UNICODE_NORM_QC_NO}, + {0xFC6D, UNICODE_NORM_QC_NO}, + {0xFC6E, UNICODE_NORM_QC_NO}, + {0xFC6F, UNICODE_NORM_QC_NO}, + {0xFC70, UNICODE_NORM_QC_NO}, + {0xFC71, UNICODE_NORM_QC_NO}, + {0xFC72, UNICODE_NORM_QC_NO}, + {0xFC73, UNICODE_NORM_QC_NO}, + {0xFC74, UNICODE_NORM_QC_NO}, + {0xFC75, UNICODE_NORM_QC_NO}, + {0xFC76, UNICODE_NORM_QC_NO}, + {0xFC77, UNICODE_NORM_QC_NO}, + {0xFC78, UNICODE_NORM_QC_NO}, + {0xFC79, UNICODE_NORM_QC_NO}, + {0xFC7A, UNICODE_NORM_QC_NO}, + {0xFC7B, UNICODE_NORM_QC_NO}, + {0xFC7C, UNICODE_NORM_QC_NO}, + {0xFC7D, UNICODE_NORM_QC_NO}, + {0xFC7E, UNICODE_NORM_QC_NO}, + {0xFC7F, UNICODE_NORM_QC_NO}, + {0xFC80, UNICODE_NORM_QC_NO}, + {0xFC81, UNICODE_NORM_QC_NO}, + {0xFC82, UNICODE_NORM_QC_NO}, + {0xFC83, UNICODE_NORM_QC_NO}, + {0xFC84, UNICODE_NORM_QC_NO}, + {0xFC85, UNICODE_NORM_QC_NO}, + {0xFC86, UNICODE_NORM_QC_NO}, + {0xFC87, UNICODE_NORM_QC_NO}, + {0xFC88, UNICODE_NORM_QC_NO}, + {0xFC89, UNICODE_NORM_QC_NO}, + {0xFC8A, UNICODE_NORM_QC_NO}, + {0xFC8B, UNICODE_NORM_QC_NO}, + {0xFC8C, UNICODE_NORM_QC_NO}, + {0xFC8D, UNICODE_NORM_QC_NO}, + {0xFC8E, UNICODE_NORM_QC_NO}, + {0xFC8F, UNICODE_NORM_QC_NO}, + {0xFC90, UNICODE_NORM_QC_NO}, + {0xFC91, UNICODE_NORM_QC_NO}, + {0xFC92, UNICODE_NORM_QC_NO}, + {0xFC93, UNICODE_NORM_QC_NO}, + {0xFC94, UNICODE_NORM_QC_NO}, + {0xFC95, UNICODE_NORM_QC_NO}, + {0xFC96, UNICODE_NORM_QC_NO}, + {0xFC97, UNICODE_NORM_QC_NO}, + {0xFC98, UNICODE_NORM_QC_NO}, + {0xFC99, UNICODE_NORM_QC_NO}, + {0xFC9A, UNICODE_NORM_QC_NO}, + {0xFC9B, UNICODE_NORM_QC_NO}, + {0xFC9C, UNICODE_NORM_QC_NO}, + {0xFC9D, UNICODE_NORM_QC_NO}, + {0xFC9E, UNICODE_NORM_QC_NO}, + {0xFC9F, UNICODE_NORM_QC_NO}, + {0xFCA0, UNICODE_NORM_QC_NO}, + {0xFCA1, UNICODE_NORM_QC_NO}, + {0xFCA2, UNICODE_NORM_QC_NO}, + {0xFCA3, UNICODE_NORM_QC_NO}, + {0xFCA4, UNICODE_NORM_QC_NO}, + {0xFCA5, UNICODE_NORM_QC_NO}, + {0xFCA6, UNICODE_NORM_QC_NO}, + {0xFCA7, UNICODE_NORM_QC_NO}, + {0xFCA8, UNICODE_NORM_QC_NO}, + {0xFCA9, UNICODE_NORM_QC_NO}, + {0xFCAA, UNICODE_NORM_QC_NO}, + {0xFCAB, UNICODE_NORM_QC_NO}, + {0xFCAC, UNICODE_NORM_QC_NO}, + {0xFCAD, UNICODE_NORM_QC_NO}, + {0xFCAE, UNICODE_NORM_QC_NO}, + {0xFCAF, UNICODE_NORM_QC_NO}, + {0xFCB0, UNICODE_NORM_QC_NO}, + {0xFCB1, UNICODE_NORM_QC_NO}, + {0xFCB2, UNICODE_NORM_QC_NO}, + {0xFCB3, UNICODE_NORM_QC_NO}, + {0xFCB4, UNICODE_NORM_QC_NO}, + {0xFCB5, UNICODE_NORM_QC_NO}, + {0xFCB6, UNICODE_NORM_QC_NO}, + {0xFCB7, UNICODE_NORM_QC_NO}, + {0xFCB8, UNICODE_NORM_QC_NO}, + {0xFCB9, UNICODE_NORM_QC_NO}, + {0xFCBA, UNICODE_NORM_QC_NO}, + {0xFCBB, UNICODE_NORM_QC_NO}, + {0xFCBC, UNICODE_NORM_QC_NO}, + {0xFCBD, UNICODE_NORM_QC_NO}, + {0xFCBE, UNICODE_NORM_QC_NO}, + {0xFCBF, UNICODE_NORM_QC_NO}, + {0xFCC0, UNICODE_NORM_QC_NO}, + {0xFCC1, UNICODE_NORM_QC_NO}, + {0xFCC2, UNICODE_NORM_QC_NO}, + {0xFCC3, UNICODE_NORM_QC_NO}, + {0xFCC4, UNICODE_NORM_QC_NO}, + {0xFCC5, UNICODE_NORM_QC_NO}, + {0xFCC6, UNICODE_NORM_QC_NO}, + {0xFCC7, UNICODE_NORM_QC_NO}, + {0xFCC8, UNICODE_NORM_QC_NO}, + {0xFCC9, UNICODE_NORM_QC_NO}, + {0xFCCA, UNICODE_NORM_QC_NO}, + {0xFCCB, UNICODE_NORM_QC_NO}, + {0xFCCC, UNICODE_NORM_QC_NO}, + {0xFCCD, UNICODE_NORM_QC_NO}, + {0xFCCE, UNICODE_NORM_QC_NO}, + {0xFCCF, UNICODE_NORM_QC_NO}, + {0xFCD0, UNICODE_NORM_QC_NO}, + {0xFCD1, UNICODE_NORM_QC_NO}, + {0xFCD2, UNICODE_NORM_QC_NO}, + {0xFCD3, UNICODE_NORM_QC_NO}, + {0xFCD4, UNICODE_NORM_QC_NO}, + {0xFCD5, UNICODE_NORM_QC_NO}, + {0xFCD6, UNICODE_NORM_QC_NO}, + {0xFCD7, UNICODE_NORM_QC_NO}, + {0xFCD8, UNICODE_NORM_QC_NO}, + {0xFCD9, UNICODE_NORM_QC_NO}, + {0xFCDA, UNICODE_NORM_QC_NO}, + {0xFCDB, UNICODE_NORM_QC_NO}, + {0xFCDC, UNICODE_NORM_QC_NO}, + {0xFCDD, UNICODE_NORM_QC_NO}, + {0xFCDE, UNICODE_NORM_QC_NO}, + {0xFCDF, UNICODE_NORM_QC_NO}, + {0xFCE0, UNICODE_NORM_QC_NO}, + {0xFCE1, UNICODE_NORM_QC_NO}, + {0xFCE2, UNICODE_NORM_QC_NO}, + {0xFCE3, UNICODE_NORM_QC_NO}, + {0xFCE4, UNICODE_NORM_QC_NO}, + {0xFCE5, UNICODE_NORM_QC_NO}, + {0xFCE6, UNICODE_NORM_QC_NO}, + {0xFCE7, UNICODE_NORM_QC_NO}, + {0xFCE8, UNICODE_NORM_QC_NO}, + {0xFCE9, UNICODE_NORM_QC_NO}, + {0xFCEA, UNICODE_NORM_QC_NO}, + {0xFCEB, UNICODE_NORM_QC_NO}, + {0xFCEC, UNICODE_NORM_QC_NO}, + {0xFCED, UNICODE_NORM_QC_NO}, + {0xFCEE, UNICODE_NORM_QC_NO}, + {0xFCEF, UNICODE_NORM_QC_NO}, + {0xFCF0, UNICODE_NORM_QC_NO}, + {0xFCF1, UNICODE_NORM_QC_NO}, + {0xFCF2, UNICODE_NORM_QC_NO}, + {0xFCF3, UNICODE_NORM_QC_NO}, + {0xFCF4, UNICODE_NORM_QC_NO}, + {0xFCF5, UNICODE_NORM_QC_NO}, + {0xFCF6, UNICODE_NORM_QC_NO}, + {0xFCF7, UNICODE_NORM_QC_NO}, + {0xFCF8, UNICODE_NORM_QC_NO}, + {0xFCF9, UNICODE_NORM_QC_NO}, + {0xFCFA, UNICODE_NORM_QC_NO}, + {0xFCFB, UNICODE_NORM_QC_NO}, + {0xFCFC, UNICODE_NORM_QC_NO}, + {0xFCFD, UNICODE_NORM_QC_NO}, + {0xFCFE, UNICODE_NORM_QC_NO}, + {0xFCFF, UNICODE_NORM_QC_NO}, + {0xFD00, UNICODE_NORM_QC_NO}, + {0xFD01, UNICODE_NORM_QC_NO}, + {0xFD02, UNICODE_NORM_QC_NO}, + {0xFD03, UNICODE_NORM_QC_NO}, + {0xFD04, UNICODE_NORM_QC_NO}, + {0xFD05, UNICODE_NORM_QC_NO}, + {0xFD06, UNICODE_NORM_QC_NO}, + {0xFD07, UNICODE_NORM_QC_NO}, + {0xFD08, UNICODE_NORM_QC_NO}, + {0xFD09, UNICODE_NORM_QC_NO}, + {0xFD0A, UNICODE_NORM_QC_NO}, + {0xFD0B, UNICODE_NORM_QC_NO}, + {0xFD0C, UNICODE_NORM_QC_NO}, + {0xFD0D, UNICODE_NORM_QC_NO}, + {0xFD0E, UNICODE_NORM_QC_NO}, + {0xFD0F, UNICODE_NORM_QC_NO}, + {0xFD10, UNICODE_NORM_QC_NO}, + {0xFD11, UNICODE_NORM_QC_NO}, + {0xFD12, UNICODE_NORM_QC_NO}, + {0xFD13, UNICODE_NORM_QC_NO}, + {0xFD14, UNICODE_NORM_QC_NO}, + {0xFD15, UNICODE_NORM_QC_NO}, + {0xFD16, UNICODE_NORM_QC_NO}, + {0xFD17, UNICODE_NORM_QC_NO}, + {0xFD18, UNICODE_NORM_QC_NO}, + {0xFD19, UNICODE_NORM_QC_NO}, + {0xFD1A, UNICODE_NORM_QC_NO}, + {0xFD1B, UNICODE_NORM_QC_NO}, + {0xFD1C, UNICODE_NORM_QC_NO}, + {0xFD1D, UNICODE_NORM_QC_NO}, + {0xFD1E, UNICODE_NORM_QC_NO}, + {0xFD1F, UNICODE_NORM_QC_NO}, + {0xFD20, UNICODE_NORM_QC_NO}, + {0xFD21, UNICODE_NORM_QC_NO}, + {0xFD22, UNICODE_NORM_QC_NO}, + {0xFD23, UNICODE_NORM_QC_NO}, + {0xFD24, UNICODE_NORM_QC_NO}, + {0xFD25, UNICODE_NORM_QC_NO}, + {0xFD26, UNICODE_NORM_QC_NO}, + {0xFD27, UNICODE_NORM_QC_NO}, + {0xFD28, UNICODE_NORM_QC_NO}, + {0xFD29, UNICODE_NORM_QC_NO}, + {0xFD2A, UNICODE_NORM_QC_NO}, + {0xFD2B, UNICODE_NORM_QC_NO}, + {0xFD2C, UNICODE_NORM_QC_NO}, + {0xFD2D, UNICODE_NORM_QC_NO}, + {0xFD2E, UNICODE_NORM_QC_NO}, + {0xFD2F, UNICODE_NORM_QC_NO}, + {0xFD30, UNICODE_NORM_QC_NO}, + {0xFD31, UNICODE_NORM_QC_NO}, + {0xFD32, UNICODE_NORM_QC_NO}, + {0xFD33, UNICODE_NORM_QC_NO}, + {0xFD34, UNICODE_NORM_QC_NO}, + {0xFD35, UNICODE_NORM_QC_NO}, + {0xFD36, UNICODE_NORM_QC_NO}, + {0xFD37, UNICODE_NORM_QC_NO}, + {0xFD38, UNICODE_NORM_QC_NO}, + {0xFD39, UNICODE_NORM_QC_NO}, + {0xFD3A, UNICODE_NORM_QC_NO}, + {0xFD3B, UNICODE_NORM_QC_NO}, + {0xFD3C, UNICODE_NORM_QC_NO}, + {0xFD3D, UNICODE_NORM_QC_NO}, + {0xFD50, UNICODE_NORM_QC_NO}, + {0xFD51, UNICODE_NORM_QC_NO}, + {0xFD52, UNICODE_NORM_QC_NO}, + {0xFD53, UNICODE_NORM_QC_NO}, + {0xFD54, UNICODE_NORM_QC_NO}, + {0xFD55, UNICODE_NORM_QC_NO}, + {0xFD56, UNICODE_NORM_QC_NO}, + {0xFD57, UNICODE_NORM_QC_NO}, + {0xFD58, UNICODE_NORM_QC_NO}, + {0xFD59, UNICODE_NORM_QC_NO}, + {0xFD5A, UNICODE_NORM_QC_NO}, + {0xFD5B, UNICODE_NORM_QC_NO}, + {0xFD5C, UNICODE_NORM_QC_NO}, + {0xFD5D, UNICODE_NORM_QC_NO}, + {0xFD5E, UNICODE_NORM_QC_NO}, + {0xFD5F, UNICODE_NORM_QC_NO}, + {0xFD60, UNICODE_NORM_QC_NO}, + {0xFD61, UNICODE_NORM_QC_NO}, + {0xFD62, UNICODE_NORM_QC_NO}, + {0xFD63, UNICODE_NORM_QC_NO}, + {0xFD64, UNICODE_NORM_QC_NO}, + {0xFD65, UNICODE_NORM_QC_NO}, + {0xFD66, UNICODE_NORM_QC_NO}, + {0xFD67, UNICODE_NORM_QC_NO}, + {0xFD68, UNICODE_NORM_QC_NO}, + {0xFD69, UNICODE_NORM_QC_NO}, + {0xFD6A, UNICODE_NORM_QC_NO}, + {0xFD6B, UNICODE_NORM_QC_NO}, + {0xFD6C, UNICODE_NORM_QC_NO}, + {0xFD6D, UNICODE_NORM_QC_NO}, + {0xFD6E, UNICODE_NORM_QC_NO}, + {0xFD6F, UNICODE_NORM_QC_NO}, + {0xFD70, UNICODE_NORM_QC_NO}, + {0xFD71, UNICODE_NORM_QC_NO}, + {0xFD72, UNICODE_NORM_QC_NO}, + {0xFD73, UNICODE_NORM_QC_NO}, + {0xFD74, UNICODE_NORM_QC_NO}, + {0xFD75, UNICODE_NORM_QC_NO}, + {0xFD76, UNICODE_NORM_QC_NO}, + {0xFD77, UNICODE_NORM_QC_NO}, + {0xFD78, UNICODE_NORM_QC_NO}, + {0xFD79, UNICODE_NORM_QC_NO}, + {0xFD7A, UNICODE_NORM_QC_NO}, + {0xFD7B, UNICODE_NORM_QC_NO}, + {0xFD7C, UNICODE_NORM_QC_NO}, + {0xFD7D, UNICODE_NORM_QC_NO}, + {0xFD7E, UNICODE_NORM_QC_NO}, + {0xFD7F, UNICODE_NORM_QC_NO}, + {0xFD80, UNICODE_NORM_QC_NO}, + {0xFD81, UNICODE_NORM_QC_NO}, + {0xFD82, UNICODE_NORM_QC_NO}, + {0xFD83, UNICODE_NORM_QC_NO}, + {0xFD84, UNICODE_NORM_QC_NO}, + {0xFD85, UNICODE_NORM_QC_NO}, + {0xFD86, UNICODE_NORM_QC_NO}, + {0xFD87, UNICODE_NORM_QC_NO}, + {0xFD88, UNICODE_NORM_QC_NO}, + {0xFD89, UNICODE_NORM_QC_NO}, + {0xFD8A, UNICODE_NORM_QC_NO}, + {0xFD8B, UNICODE_NORM_QC_NO}, + {0xFD8C, UNICODE_NORM_QC_NO}, + {0xFD8D, UNICODE_NORM_QC_NO}, + {0xFD8E, UNICODE_NORM_QC_NO}, + {0xFD8F, UNICODE_NORM_QC_NO}, + {0xFD92, UNICODE_NORM_QC_NO}, + {0xFD93, UNICODE_NORM_QC_NO}, + {0xFD94, UNICODE_NORM_QC_NO}, + {0xFD95, UNICODE_NORM_QC_NO}, + {0xFD96, UNICODE_NORM_QC_NO}, + {0xFD97, UNICODE_NORM_QC_NO}, + {0xFD98, UNICODE_NORM_QC_NO}, + {0xFD99, UNICODE_NORM_QC_NO}, + {0xFD9A, UNICODE_NORM_QC_NO}, + {0xFD9B, UNICODE_NORM_QC_NO}, + {0xFD9C, UNICODE_NORM_QC_NO}, + {0xFD9D, UNICODE_NORM_QC_NO}, + {0xFD9E, UNICODE_NORM_QC_NO}, + {0xFD9F, UNICODE_NORM_QC_NO}, + {0xFDA0, UNICODE_NORM_QC_NO}, + {0xFDA1, UNICODE_NORM_QC_NO}, + {0xFDA2, UNICODE_NORM_QC_NO}, + {0xFDA3, UNICODE_NORM_QC_NO}, + {0xFDA4, UNICODE_NORM_QC_NO}, + {0xFDA5, UNICODE_NORM_QC_NO}, + {0xFDA6, UNICODE_NORM_QC_NO}, + {0xFDA7, UNICODE_NORM_QC_NO}, + {0xFDA8, UNICODE_NORM_QC_NO}, + {0xFDA9, UNICODE_NORM_QC_NO}, + {0xFDAA, UNICODE_NORM_QC_NO}, + {0xFDAB, UNICODE_NORM_QC_NO}, + {0xFDAC, UNICODE_NORM_QC_NO}, + {0xFDAD, UNICODE_NORM_QC_NO}, + {0xFDAE, UNICODE_NORM_QC_NO}, + {0xFDAF, UNICODE_NORM_QC_NO}, + {0xFDB0, UNICODE_NORM_QC_NO}, + {0xFDB1, UNICODE_NORM_QC_NO}, + {0xFDB2, UNICODE_NORM_QC_NO}, + {0xFDB3, UNICODE_NORM_QC_NO}, + {0xFDB4, UNICODE_NORM_QC_NO}, + {0xFDB5, UNICODE_NORM_QC_NO}, + {0xFDB6, UNICODE_NORM_QC_NO}, + {0xFDB7, UNICODE_NORM_QC_NO}, + {0xFDB8, UNICODE_NORM_QC_NO}, + {0xFDB9, UNICODE_NORM_QC_NO}, + {0xFDBA, UNICODE_NORM_QC_NO}, + {0xFDBB, UNICODE_NORM_QC_NO}, + {0xFDBC, UNICODE_NORM_QC_NO}, + {0xFDBD, UNICODE_NORM_QC_NO}, + {0xFDBE, UNICODE_NORM_QC_NO}, + {0xFDBF, UNICODE_NORM_QC_NO}, + {0xFDC0, UNICODE_NORM_QC_NO}, + {0xFDC1, UNICODE_NORM_QC_NO}, + {0xFDC2, UNICODE_NORM_QC_NO}, + {0xFDC3, UNICODE_NORM_QC_NO}, + {0xFDC4, UNICODE_NORM_QC_NO}, + {0xFDC5, UNICODE_NORM_QC_NO}, + {0xFDC6, UNICODE_NORM_QC_NO}, + {0xFDC7, UNICODE_NORM_QC_NO}, + {0xFDF0, UNICODE_NORM_QC_NO}, + {0xFDF1, UNICODE_NORM_QC_NO}, + {0xFDF2, UNICODE_NORM_QC_NO}, + {0xFDF3, UNICODE_NORM_QC_NO}, + {0xFDF4, UNICODE_NORM_QC_NO}, + {0xFDF5, UNICODE_NORM_QC_NO}, + {0xFDF6, UNICODE_NORM_QC_NO}, + {0xFDF7, UNICODE_NORM_QC_NO}, + {0xFDF8, UNICODE_NORM_QC_NO}, + {0xFDF9, UNICODE_NORM_QC_NO}, + {0xFDFA, UNICODE_NORM_QC_NO}, + {0xFDFB, UNICODE_NORM_QC_NO}, + {0xFDFC, UNICODE_NORM_QC_NO}, + {0xFE10, UNICODE_NORM_QC_NO}, + {0xFE11, UNICODE_NORM_QC_NO}, + {0xFE12, UNICODE_NORM_QC_NO}, + {0xFE13, UNICODE_NORM_QC_NO}, + {0xFE14, UNICODE_NORM_QC_NO}, + {0xFE15, UNICODE_NORM_QC_NO}, + {0xFE16, UNICODE_NORM_QC_NO}, + {0xFE17, UNICODE_NORM_QC_NO}, + {0xFE18, UNICODE_NORM_QC_NO}, + {0xFE19, UNICODE_NORM_QC_NO}, + {0xFE30, UNICODE_NORM_QC_NO}, + {0xFE31, UNICODE_NORM_QC_NO}, + {0xFE32, UNICODE_NORM_QC_NO}, + {0xFE33, UNICODE_NORM_QC_NO}, + {0xFE34, UNICODE_NORM_QC_NO}, + {0xFE35, UNICODE_NORM_QC_NO}, + {0xFE36, UNICODE_NORM_QC_NO}, + {0xFE37, UNICODE_NORM_QC_NO}, + {0xFE38, UNICODE_NORM_QC_NO}, + {0xFE39, UNICODE_NORM_QC_NO}, + {0xFE3A, UNICODE_NORM_QC_NO}, + {0xFE3B, UNICODE_NORM_QC_NO}, + {0xFE3C, UNICODE_NORM_QC_NO}, + {0xFE3D, UNICODE_NORM_QC_NO}, + {0xFE3E, UNICODE_NORM_QC_NO}, + {0xFE3F, UNICODE_NORM_QC_NO}, + {0xFE40, UNICODE_NORM_QC_NO}, + {0xFE41, UNICODE_NORM_QC_NO}, + {0xFE42, UNICODE_NORM_QC_NO}, + {0xFE43, UNICODE_NORM_QC_NO}, + {0xFE44, UNICODE_NORM_QC_NO}, + {0xFE47, UNICODE_NORM_QC_NO}, + {0xFE48, UNICODE_NORM_QC_NO}, + {0xFE49, UNICODE_NORM_QC_NO}, + {0xFE4A, UNICODE_NORM_QC_NO}, + {0xFE4B, UNICODE_NORM_QC_NO}, + {0xFE4C, UNICODE_NORM_QC_NO}, + {0xFE4D, UNICODE_NORM_QC_NO}, + {0xFE4E, UNICODE_NORM_QC_NO}, + {0xFE4F, UNICODE_NORM_QC_NO}, + {0xFE50, UNICODE_NORM_QC_NO}, + {0xFE51, UNICODE_NORM_QC_NO}, + {0xFE52, UNICODE_NORM_QC_NO}, + {0xFE54, UNICODE_NORM_QC_NO}, + {0xFE55, UNICODE_NORM_QC_NO}, + {0xFE56, UNICODE_NORM_QC_NO}, + {0xFE57, UNICODE_NORM_QC_NO}, + {0xFE58, UNICODE_NORM_QC_NO}, + {0xFE59, UNICODE_NORM_QC_NO}, + {0xFE5A, UNICODE_NORM_QC_NO}, + {0xFE5B, UNICODE_NORM_QC_NO}, + {0xFE5C, UNICODE_NORM_QC_NO}, + {0xFE5D, UNICODE_NORM_QC_NO}, + {0xFE5E, UNICODE_NORM_QC_NO}, + {0xFE5F, UNICODE_NORM_QC_NO}, + {0xFE60, UNICODE_NORM_QC_NO}, + {0xFE61, UNICODE_NORM_QC_NO}, + {0xFE62, UNICODE_NORM_QC_NO}, + {0xFE63, UNICODE_NORM_QC_NO}, + {0xFE64, UNICODE_NORM_QC_NO}, + {0xFE65, UNICODE_NORM_QC_NO}, + {0xFE66, UNICODE_NORM_QC_NO}, + {0xFE68, UNICODE_NORM_QC_NO}, + {0xFE69, UNICODE_NORM_QC_NO}, + {0xFE6A, UNICODE_NORM_QC_NO}, + {0xFE6B, UNICODE_NORM_QC_NO}, + {0xFE70, UNICODE_NORM_QC_NO}, + {0xFE71, UNICODE_NORM_QC_NO}, + {0xFE72, UNICODE_NORM_QC_NO}, + {0xFE74, UNICODE_NORM_QC_NO}, + {0xFE76, UNICODE_NORM_QC_NO}, + {0xFE77, UNICODE_NORM_QC_NO}, + {0xFE78, UNICODE_NORM_QC_NO}, + {0xFE79, UNICODE_NORM_QC_NO}, + {0xFE7A, UNICODE_NORM_QC_NO}, + {0xFE7B, UNICODE_NORM_QC_NO}, + {0xFE7C, UNICODE_NORM_QC_NO}, + {0xFE7D, UNICODE_NORM_QC_NO}, + {0xFE7E, UNICODE_NORM_QC_NO}, + {0xFE7F, UNICODE_NORM_QC_NO}, + {0xFE80, UNICODE_NORM_QC_NO}, + {0xFE81, UNICODE_NORM_QC_NO}, + {0xFE82, UNICODE_NORM_QC_NO}, + {0xFE83, UNICODE_NORM_QC_NO}, + {0xFE84, UNICODE_NORM_QC_NO}, + {0xFE85, UNICODE_NORM_QC_NO}, + {0xFE86, UNICODE_NORM_QC_NO}, + {0xFE87, UNICODE_NORM_QC_NO}, + {0xFE88, UNICODE_NORM_QC_NO}, + {0xFE89, UNICODE_NORM_QC_NO}, + {0xFE8A, UNICODE_NORM_QC_NO}, + {0xFE8B, UNICODE_NORM_QC_NO}, + {0xFE8C, UNICODE_NORM_QC_NO}, + {0xFE8D, UNICODE_NORM_QC_NO}, + {0xFE8E, UNICODE_NORM_QC_NO}, + {0xFE8F, UNICODE_NORM_QC_NO}, + {0xFE90, UNICODE_NORM_QC_NO}, + {0xFE91, UNICODE_NORM_QC_NO}, + {0xFE92, UNICODE_NORM_QC_NO}, + {0xFE93, UNICODE_NORM_QC_NO}, + {0xFE94, UNICODE_NORM_QC_NO}, + {0xFE95, UNICODE_NORM_QC_NO}, + {0xFE96, UNICODE_NORM_QC_NO}, + {0xFE97, UNICODE_NORM_QC_NO}, + {0xFE98, UNICODE_NORM_QC_NO}, + {0xFE99, UNICODE_NORM_QC_NO}, + {0xFE9A, UNICODE_NORM_QC_NO}, + {0xFE9B, UNICODE_NORM_QC_NO}, + {0xFE9C, UNICODE_NORM_QC_NO}, + {0xFE9D, UNICODE_NORM_QC_NO}, + {0xFE9E, UNICODE_NORM_QC_NO}, + {0xFE9F, UNICODE_NORM_QC_NO}, + {0xFEA0, UNICODE_NORM_QC_NO}, + {0xFEA1, UNICODE_NORM_QC_NO}, + {0xFEA2, UNICODE_NORM_QC_NO}, + {0xFEA3, UNICODE_NORM_QC_NO}, + {0xFEA4, UNICODE_NORM_QC_NO}, + {0xFEA5, UNICODE_NORM_QC_NO}, + {0xFEA6, UNICODE_NORM_QC_NO}, + {0xFEA7, UNICODE_NORM_QC_NO}, + {0xFEA8, UNICODE_NORM_QC_NO}, + {0xFEA9, UNICODE_NORM_QC_NO}, + {0xFEAA, UNICODE_NORM_QC_NO}, + {0xFEAB, UNICODE_NORM_QC_NO}, + {0xFEAC, UNICODE_NORM_QC_NO}, + {0xFEAD, UNICODE_NORM_QC_NO}, + {0xFEAE, UNICODE_NORM_QC_NO}, + {0xFEAF, UNICODE_NORM_QC_NO}, + {0xFEB0, UNICODE_NORM_QC_NO}, + {0xFEB1, UNICODE_NORM_QC_NO}, + {0xFEB2, UNICODE_NORM_QC_NO}, + {0xFEB3, UNICODE_NORM_QC_NO}, + {0xFEB4, UNICODE_NORM_QC_NO}, + {0xFEB5, UNICODE_NORM_QC_NO}, + {0xFEB6, UNICODE_NORM_QC_NO}, + {0xFEB7, UNICODE_NORM_QC_NO}, + {0xFEB8, UNICODE_NORM_QC_NO}, + {0xFEB9, UNICODE_NORM_QC_NO}, + {0xFEBA, UNICODE_NORM_QC_NO}, + {0xFEBB, UNICODE_NORM_QC_NO}, + {0xFEBC, UNICODE_NORM_QC_NO}, + {0xFEBD, UNICODE_NORM_QC_NO}, + {0xFEBE, UNICODE_NORM_QC_NO}, + {0xFEBF, UNICODE_NORM_QC_NO}, + {0xFEC0, UNICODE_NORM_QC_NO}, + {0xFEC1, UNICODE_NORM_QC_NO}, + {0xFEC2, UNICODE_NORM_QC_NO}, + {0xFEC3, UNICODE_NORM_QC_NO}, + {0xFEC4, UNICODE_NORM_QC_NO}, + {0xFEC5, UNICODE_NORM_QC_NO}, + {0xFEC6, UNICODE_NORM_QC_NO}, + {0xFEC7, UNICODE_NORM_QC_NO}, + {0xFEC8, UNICODE_NORM_QC_NO}, + {0xFEC9, UNICODE_NORM_QC_NO}, + {0xFECA, UNICODE_NORM_QC_NO}, + {0xFECB, UNICODE_NORM_QC_NO}, + {0xFECC, UNICODE_NORM_QC_NO}, + {0xFECD, UNICODE_NORM_QC_NO}, + {0xFECE, UNICODE_NORM_QC_NO}, + {0xFECF, UNICODE_NORM_QC_NO}, + {0xFED0, UNICODE_NORM_QC_NO}, + {0xFED1, UNICODE_NORM_QC_NO}, + {0xFED2, UNICODE_NORM_QC_NO}, + {0xFED3, UNICODE_NORM_QC_NO}, + {0xFED4, UNICODE_NORM_QC_NO}, + {0xFED5, UNICODE_NORM_QC_NO}, + {0xFED6, UNICODE_NORM_QC_NO}, + {0xFED7, UNICODE_NORM_QC_NO}, + {0xFED8, UNICODE_NORM_QC_NO}, + {0xFED9, UNICODE_NORM_QC_NO}, + {0xFEDA, UNICODE_NORM_QC_NO}, + {0xFEDB, UNICODE_NORM_QC_NO}, + {0xFEDC, UNICODE_NORM_QC_NO}, + {0xFEDD, UNICODE_NORM_QC_NO}, + {0xFEDE, UNICODE_NORM_QC_NO}, + {0xFEDF, UNICODE_NORM_QC_NO}, + {0xFEE0, UNICODE_NORM_QC_NO}, + {0xFEE1, UNICODE_NORM_QC_NO}, + {0xFEE2, UNICODE_NORM_QC_NO}, + {0xFEE3, UNICODE_NORM_QC_NO}, + {0xFEE4, UNICODE_NORM_QC_NO}, + {0xFEE5, UNICODE_NORM_QC_NO}, + {0xFEE6, UNICODE_NORM_QC_NO}, + {0xFEE7, UNICODE_NORM_QC_NO}, + {0xFEE8, UNICODE_NORM_QC_NO}, + {0xFEE9, UNICODE_NORM_QC_NO}, + {0xFEEA, UNICODE_NORM_QC_NO}, + {0xFEEB, UNICODE_NORM_QC_NO}, + {0xFEEC, UNICODE_NORM_QC_NO}, + {0xFEED, UNICODE_NORM_QC_NO}, + {0xFEEE, UNICODE_NORM_QC_NO}, + {0xFEEF, UNICODE_NORM_QC_NO}, + {0xFEF0, UNICODE_NORM_QC_NO}, + {0xFEF1, UNICODE_NORM_QC_NO}, + {0xFEF2, UNICODE_NORM_QC_NO}, + {0xFEF3, UNICODE_NORM_QC_NO}, + {0xFEF4, UNICODE_NORM_QC_NO}, + {0xFEF5, UNICODE_NORM_QC_NO}, + {0xFEF6, UNICODE_NORM_QC_NO}, + {0xFEF7, UNICODE_NORM_QC_NO}, + {0xFEF8, UNICODE_NORM_QC_NO}, + {0xFEF9, UNICODE_NORM_QC_NO}, + {0xFEFA, UNICODE_NORM_QC_NO}, + {0xFEFB, UNICODE_NORM_QC_NO}, + {0xFEFC, UNICODE_NORM_QC_NO}, + {0xFF01, UNICODE_NORM_QC_NO}, + {0xFF02, UNICODE_NORM_QC_NO}, + {0xFF03, UNICODE_NORM_QC_NO}, + {0xFF04, UNICODE_NORM_QC_NO}, + {0xFF05, UNICODE_NORM_QC_NO}, + {0xFF06, UNICODE_NORM_QC_NO}, + {0xFF07, UNICODE_NORM_QC_NO}, + {0xFF08, UNICODE_NORM_QC_NO}, + {0xFF09, UNICODE_NORM_QC_NO}, + {0xFF0A, UNICODE_NORM_QC_NO}, + {0xFF0B, UNICODE_NORM_QC_NO}, + {0xFF0C, UNICODE_NORM_QC_NO}, + {0xFF0D, UNICODE_NORM_QC_NO}, + {0xFF0E, UNICODE_NORM_QC_NO}, + {0xFF0F, UNICODE_NORM_QC_NO}, + {0xFF10, UNICODE_NORM_QC_NO}, + {0xFF11, UNICODE_NORM_QC_NO}, + {0xFF12, UNICODE_NORM_QC_NO}, + {0xFF13, UNICODE_NORM_QC_NO}, + {0xFF14, UNICODE_NORM_QC_NO}, + {0xFF15, UNICODE_NORM_QC_NO}, + {0xFF16, UNICODE_NORM_QC_NO}, + {0xFF17, UNICODE_NORM_QC_NO}, + {0xFF18, UNICODE_NORM_QC_NO}, + {0xFF19, UNICODE_NORM_QC_NO}, + {0xFF1A, UNICODE_NORM_QC_NO}, + {0xFF1B, UNICODE_NORM_QC_NO}, + {0xFF1C, UNICODE_NORM_QC_NO}, + {0xFF1D, UNICODE_NORM_QC_NO}, + {0xFF1E, UNICODE_NORM_QC_NO}, + {0xFF1F, UNICODE_NORM_QC_NO}, + {0xFF20, UNICODE_NORM_QC_NO}, + {0xFF21, UNICODE_NORM_QC_NO}, + {0xFF22, UNICODE_NORM_QC_NO}, + {0xFF23, UNICODE_NORM_QC_NO}, + {0xFF24, UNICODE_NORM_QC_NO}, + {0xFF25, UNICODE_NORM_QC_NO}, + {0xFF26, UNICODE_NORM_QC_NO}, + {0xFF27, UNICODE_NORM_QC_NO}, + {0xFF28, UNICODE_NORM_QC_NO}, + {0xFF29, UNICODE_NORM_QC_NO}, + {0xFF2A, UNICODE_NORM_QC_NO}, + {0xFF2B, UNICODE_NORM_QC_NO}, + {0xFF2C, UNICODE_NORM_QC_NO}, + {0xFF2D, UNICODE_NORM_QC_NO}, + {0xFF2E, UNICODE_NORM_QC_NO}, + {0xFF2F, UNICODE_NORM_QC_NO}, + {0xFF30, UNICODE_NORM_QC_NO}, + {0xFF31, UNICODE_NORM_QC_NO}, + {0xFF32, UNICODE_NORM_QC_NO}, + {0xFF33, UNICODE_NORM_QC_NO}, + {0xFF34, UNICODE_NORM_QC_NO}, + {0xFF35, UNICODE_NORM_QC_NO}, + {0xFF36, UNICODE_NORM_QC_NO}, + {0xFF37, UNICODE_NORM_QC_NO}, + {0xFF38, UNICODE_NORM_QC_NO}, + {0xFF39, UNICODE_NORM_QC_NO}, + {0xFF3A, UNICODE_NORM_QC_NO}, + {0xFF3B, UNICODE_NORM_QC_NO}, + {0xFF3C, UNICODE_NORM_QC_NO}, + {0xFF3D, UNICODE_NORM_QC_NO}, + {0xFF3E, UNICODE_NORM_QC_NO}, + {0xFF3F, UNICODE_NORM_QC_NO}, + {0xFF40, UNICODE_NORM_QC_NO}, + {0xFF41, UNICODE_NORM_QC_NO}, + {0xFF42, UNICODE_NORM_QC_NO}, + {0xFF43, UNICODE_NORM_QC_NO}, + {0xFF44, UNICODE_NORM_QC_NO}, + {0xFF45, UNICODE_NORM_QC_NO}, + {0xFF46, UNICODE_NORM_QC_NO}, + {0xFF47, UNICODE_NORM_QC_NO}, + {0xFF48, UNICODE_NORM_QC_NO}, + {0xFF49, UNICODE_NORM_QC_NO}, + {0xFF4A, UNICODE_NORM_QC_NO}, + {0xFF4B, UNICODE_NORM_QC_NO}, + {0xFF4C, UNICODE_NORM_QC_NO}, + {0xFF4D, UNICODE_NORM_QC_NO}, + {0xFF4E, UNICODE_NORM_QC_NO}, + {0xFF4F, UNICODE_NORM_QC_NO}, + {0xFF50, UNICODE_NORM_QC_NO}, + {0xFF51, UNICODE_NORM_QC_NO}, + {0xFF52, UNICODE_NORM_QC_NO}, + {0xFF53, UNICODE_NORM_QC_NO}, + {0xFF54, UNICODE_NORM_QC_NO}, + {0xFF55, UNICODE_NORM_QC_NO}, + {0xFF56, UNICODE_NORM_QC_NO}, + {0xFF57, UNICODE_NORM_QC_NO}, + {0xFF58, UNICODE_NORM_QC_NO}, + {0xFF59, UNICODE_NORM_QC_NO}, + {0xFF5A, UNICODE_NORM_QC_NO}, + {0xFF5B, UNICODE_NORM_QC_NO}, + {0xFF5C, UNICODE_NORM_QC_NO}, + {0xFF5D, UNICODE_NORM_QC_NO}, + {0xFF5E, UNICODE_NORM_QC_NO}, + {0xFF5F, UNICODE_NORM_QC_NO}, + {0xFF60, UNICODE_NORM_QC_NO}, + {0xFF61, UNICODE_NORM_QC_NO}, + {0xFF62, UNICODE_NORM_QC_NO}, + {0xFF63, UNICODE_NORM_QC_NO}, + {0xFF64, UNICODE_NORM_QC_NO}, + {0xFF65, UNICODE_NORM_QC_NO}, + {0xFF66, UNICODE_NORM_QC_NO}, + {0xFF67, UNICODE_NORM_QC_NO}, + {0xFF68, UNICODE_NORM_QC_NO}, + {0xFF69, UNICODE_NORM_QC_NO}, + {0xFF6A, UNICODE_NORM_QC_NO}, + {0xFF6B, UNICODE_NORM_QC_NO}, + {0xFF6C, UNICODE_NORM_QC_NO}, + {0xFF6D, UNICODE_NORM_QC_NO}, + {0xFF6E, UNICODE_NORM_QC_NO}, + {0xFF6F, UNICODE_NORM_QC_NO}, + {0xFF70, UNICODE_NORM_QC_NO}, + {0xFF71, UNICODE_NORM_QC_NO}, + {0xFF72, UNICODE_NORM_QC_NO}, + {0xFF73, UNICODE_NORM_QC_NO}, + {0xFF74, UNICODE_NORM_QC_NO}, + {0xFF75, UNICODE_NORM_QC_NO}, + {0xFF76, UNICODE_NORM_QC_NO}, + {0xFF77, UNICODE_NORM_QC_NO}, + {0xFF78, UNICODE_NORM_QC_NO}, + {0xFF79, UNICODE_NORM_QC_NO}, + {0xFF7A, UNICODE_NORM_QC_NO}, + {0xFF7B, UNICODE_NORM_QC_NO}, + {0xFF7C, UNICODE_NORM_QC_NO}, + {0xFF7D, UNICODE_NORM_QC_NO}, + {0xFF7E, UNICODE_NORM_QC_NO}, + {0xFF7F, UNICODE_NORM_QC_NO}, + {0xFF80, UNICODE_NORM_QC_NO}, + {0xFF81, UNICODE_NORM_QC_NO}, + {0xFF82, UNICODE_NORM_QC_NO}, + {0xFF83, UNICODE_NORM_QC_NO}, + {0xFF84, UNICODE_NORM_QC_NO}, + {0xFF85, UNICODE_NORM_QC_NO}, + {0xFF86, UNICODE_NORM_QC_NO}, + {0xFF87, UNICODE_NORM_QC_NO}, + {0xFF88, UNICODE_NORM_QC_NO}, + {0xFF89, UNICODE_NORM_QC_NO}, + {0xFF8A, UNICODE_NORM_QC_NO}, + {0xFF8B, UNICODE_NORM_QC_NO}, + {0xFF8C, UNICODE_NORM_QC_NO}, + {0xFF8D, UNICODE_NORM_QC_NO}, + {0xFF8E, UNICODE_NORM_QC_NO}, + {0xFF8F, UNICODE_NORM_QC_NO}, + {0xFF90, UNICODE_NORM_QC_NO}, + {0xFF91, UNICODE_NORM_QC_NO}, + {0xFF92, UNICODE_NORM_QC_NO}, + {0xFF93, UNICODE_NORM_QC_NO}, + {0xFF94, UNICODE_NORM_QC_NO}, + {0xFF95, UNICODE_NORM_QC_NO}, + {0xFF96, UNICODE_NORM_QC_NO}, + {0xFF97, UNICODE_NORM_QC_NO}, + {0xFF98, UNICODE_NORM_QC_NO}, + {0xFF99, UNICODE_NORM_QC_NO}, + {0xFF9A, UNICODE_NORM_QC_NO}, + {0xFF9B, UNICODE_NORM_QC_NO}, + {0xFF9C, UNICODE_NORM_QC_NO}, + {0xFF9D, UNICODE_NORM_QC_NO}, + {0xFF9E, UNICODE_NORM_QC_NO}, + {0xFF9F, UNICODE_NORM_QC_NO}, + {0xFFA0, UNICODE_NORM_QC_NO}, + {0xFFA1, UNICODE_NORM_QC_NO}, + {0xFFA2, UNICODE_NORM_QC_NO}, + {0xFFA3, UNICODE_NORM_QC_NO}, + {0xFFA4, UNICODE_NORM_QC_NO}, + {0xFFA5, UNICODE_NORM_QC_NO}, + {0xFFA6, UNICODE_NORM_QC_NO}, + {0xFFA7, UNICODE_NORM_QC_NO}, + {0xFFA8, UNICODE_NORM_QC_NO}, + {0xFFA9, UNICODE_NORM_QC_NO}, + {0xFFAA, UNICODE_NORM_QC_NO}, + {0xFFAB, UNICODE_NORM_QC_NO}, + {0xFFAC, UNICODE_NORM_QC_NO}, + {0xFFAD, UNICODE_NORM_QC_NO}, + {0xFFAE, UNICODE_NORM_QC_NO}, + {0xFFAF, UNICODE_NORM_QC_NO}, + {0xFFB0, UNICODE_NORM_QC_NO}, + {0xFFB1, UNICODE_NORM_QC_NO}, + {0xFFB2, UNICODE_NORM_QC_NO}, + {0xFFB3, UNICODE_NORM_QC_NO}, + {0xFFB4, UNICODE_NORM_QC_NO}, + {0xFFB5, UNICODE_NORM_QC_NO}, + {0xFFB6, UNICODE_NORM_QC_NO}, + {0xFFB7, UNICODE_NORM_QC_NO}, + {0xFFB8, UNICODE_NORM_QC_NO}, + {0xFFB9, UNICODE_NORM_QC_NO}, + {0xFFBA, UNICODE_NORM_QC_NO}, + {0xFFBB, UNICODE_NORM_QC_NO}, + {0xFFBC, UNICODE_NORM_QC_NO}, + {0xFFBD, UNICODE_NORM_QC_NO}, + {0xFFBE, UNICODE_NORM_QC_NO}, + {0xFFC2, UNICODE_NORM_QC_NO}, + {0xFFC3, UNICODE_NORM_QC_NO}, + {0xFFC4, UNICODE_NORM_QC_NO}, + {0xFFC5, UNICODE_NORM_QC_NO}, + {0xFFC6, UNICODE_NORM_QC_NO}, + {0xFFC7, UNICODE_NORM_QC_NO}, + {0xFFCA, UNICODE_NORM_QC_NO}, + {0xFFCB, UNICODE_NORM_QC_NO}, + {0xFFCC, UNICODE_NORM_QC_NO}, + {0xFFCD, UNICODE_NORM_QC_NO}, + {0xFFCE, UNICODE_NORM_QC_NO}, + {0xFFCF, UNICODE_NORM_QC_NO}, + {0xFFD2, UNICODE_NORM_QC_NO}, + {0xFFD3, UNICODE_NORM_QC_NO}, + {0xFFD4, UNICODE_NORM_QC_NO}, + {0xFFD5, UNICODE_NORM_QC_NO}, + {0xFFD6, UNICODE_NORM_QC_NO}, + {0xFFD7, UNICODE_NORM_QC_NO}, + {0xFFDA, UNICODE_NORM_QC_NO}, + {0xFFDB, UNICODE_NORM_QC_NO}, + {0xFFDC, UNICODE_NORM_QC_NO}, + {0xFFE0, UNICODE_NORM_QC_NO}, + {0xFFE1, UNICODE_NORM_QC_NO}, + {0xFFE2, UNICODE_NORM_QC_NO}, + {0xFFE3, UNICODE_NORM_QC_NO}, + {0xFFE4, UNICODE_NORM_QC_NO}, + {0xFFE5, UNICODE_NORM_QC_NO}, + {0xFFE6, UNICODE_NORM_QC_NO}, + {0xFFE8, UNICODE_NORM_QC_NO}, + {0xFFE9, UNICODE_NORM_QC_NO}, + {0xFFEA, UNICODE_NORM_QC_NO}, + {0xFFEB, UNICODE_NORM_QC_NO}, + {0xFFEC, UNICODE_NORM_QC_NO}, + {0xFFED, UNICODE_NORM_QC_NO}, + {0xFFEE, UNICODE_NORM_QC_NO}, + {0x10781, UNICODE_NORM_QC_NO}, + {0x10782, UNICODE_NORM_QC_NO}, + {0x10783, UNICODE_NORM_QC_NO}, + {0x10784, UNICODE_NORM_QC_NO}, + {0x10785, UNICODE_NORM_QC_NO}, + {0x10787, UNICODE_NORM_QC_NO}, + {0x10788, UNICODE_NORM_QC_NO}, + {0x10789, UNICODE_NORM_QC_NO}, + {0x1078A, UNICODE_NORM_QC_NO}, + {0x1078B, UNICODE_NORM_QC_NO}, + {0x1078C, UNICODE_NORM_QC_NO}, + {0x1078D, UNICODE_NORM_QC_NO}, + {0x1078E, UNICODE_NORM_QC_NO}, + {0x1078F, UNICODE_NORM_QC_NO}, + {0x10790, UNICODE_NORM_QC_NO}, + {0x10791, UNICODE_NORM_QC_NO}, + {0x10792, UNICODE_NORM_QC_NO}, + {0x10793, UNICODE_NORM_QC_NO}, + {0x10794, UNICODE_NORM_QC_NO}, + {0x10795, UNICODE_NORM_QC_NO}, + {0x10796, UNICODE_NORM_QC_NO}, + {0x10797, UNICODE_NORM_QC_NO}, + {0x10798, UNICODE_NORM_QC_NO}, + {0x10799, UNICODE_NORM_QC_NO}, + {0x1079A, UNICODE_NORM_QC_NO}, + {0x1079B, UNICODE_NORM_QC_NO}, + {0x1079C, UNICODE_NORM_QC_NO}, + {0x1079D, UNICODE_NORM_QC_NO}, + {0x1079E, UNICODE_NORM_QC_NO}, + {0x1079F, UNICODE_NORM_QC_NO}, + {0x107A0, UNICODE_NORM_QC_NO}, + {0x107A1, UNICODE_NORM_QC_NO}, + {0x107A2, UNICODE_NORM_QC_NO}, + {0x107A3, UNICODE_NORM_QC_NO}, + {0x107A4, UNICODE_NORM_QC_NO}, + {0x107A5, UNICODE_NORM_QC_NO}, + {0x107A6, UNICODE_NORM_QC_NO}, + {0x107A7, UNICODE_NORM_QC_NO}, + {0x107A8, UNICODE_NORM_QC_NO}, + {0x107A9, UNICODE_NORM_QC_NO}, + {0x107AA, UNICODE_NORM_QC_NO}, + {0x107AB, UNICODE_NORM_QC_NO}, + {0x107AC, UNICODE_NORM_QC_NO}, + {0x107AD, UNICODE_NORM_QC_NO}, + {0x107AE, UNICODE_NORM_QC_NO}, + {0x107AF, UNICODE_NORM_QC_NO}, + {0x107B0, UNICODE_NORM_QC_NO}, + {0x107B2, UNICODE_NORM_QC_NO}, + {0x107B3, UNICODE_NORM_QC_NO}, + {0x107B4, UNICODE_NORM_QC_NO}, + {0x107B5, UNICODE_NORM_QC_NO}, + {0x107B6, UNICODE_NORM_QC_NO}, + {0x107B7, UNICODE_NORM_QC_NO}, + {0x107B8, UNICODE_NORM_QC_NO}, + {0x107B9, UNICODE_NORM_QC_NO}, + {0x107BA, UNICODE_NORM_QC_NO}, + {0x110BA, UNICODE_NORM_QC_MAYBE}, + {0x11127, UNICODE_NORM_QC_MAYBE}, + {0x1133E, UNICODE_NORM_QC_MAYBE}, + {0x11357, UNICODE_NORM_QC_MAYBE}, + {0x114B0, UNICODE_NORM_QC_MAYBE}, + {0x114BA, UNICODE_NORM_QC_MAYBE}, + {0x114BD, UNICODE_NORM_QC_MAYBE}, + {0x115AF, UNICODE_NORM_QC_MAYBE}, + {0x11930, UNICODE_NORM_QC_MAYBE}, + {0x1D15E, UNICODE_NORM_QC_NO}, + {0x1D15F, UNICODE_NORM_QC_NO}, + {0x1D160, UNICODE_NORM_QC_NO}, + {0x1D161, UNICODE_NORM_QC_NO}, + {0x1D162, UNICODE_NORM_QC_NO}, + {0x1D163, UNICODE_NORM_QC_NO}, + {0x1D164, UNICODE_NORM_QC_NO}, + {0x1D1BB, UNICODE_NORM_QC_NO}, + {0x1D1BC, UNICODE_NORM_QC_NO}, + {0x1D1BD, UNICODE_NORM_QC_NO}, + {0x1D1BE, UNICODE_NORM_QC_NO}, + {0x1D1BF, UNICODE_NORM_QC_NO}, + {0x1D1C0, UNICODE_NORM_QC_NO}, + {0x1D400, UNICODE_NORM_QC_NO}, + {0x1D401, UNICODE_NORM_QC_NO}, + {0x1D402, UNICODE_NORM_QC_NO}, + {0x1D403, UNICODE_NORM_QC_NO}, + {0x1D404, UNICODE_NORM_QC_NO}, + {0x1D405, UNICODE_NORM_QC_NO}, + {0x1D406, UNICODE_NORM_QC_NO}, + {0x1D407, UNICODE_NORM_QC_NO}, + {0x1D408, UNICODE_NORM_QC_NO}, + {0x1D409, UNICODE_NORM_QC_NO}, + {0x1D40A, UNICODE_NORM_QC_NO}, + {0x1D40B, UNICODE_NORM_QC_NO}, + {0x1D40C, UNICODE_NORM_QC_NO}, + {0x1D40D, UNICODE_NORM_QC_NO}, + {0x1D40E, UNICODE_NORM_QC_NO}, + {0x1D40F, UNICODE_NORM_QC_NO}, + {0x1D410, UNICODE_NORM_QC_NO}, + {0x1D411, UNICODE_NORM_QC_NO}, + {0x1D412, UNICODE_NORM_QC_NO}, + {0x1D413, UNICODE_NORM_QC_NO}, + {0x1D414, UNICODE_NORM_QC_NO}, + {0x1D415, UNICODE_NORM_QC_NO}, + {0x1D416, UNICODE_NORM_QC_NO}, + {0x1D417, UNICODE_NORM_QC_NO}, + {0x1D418, UNICODE_NORM_QC_NO}, + {0x1D419, UNICODE_NORM_QC_NO}, + {0x1D41A, UNICODE_NORM_QC_NO}, + {0x1D41B, UNICODE_NORM_QC_NO}, + {0x1D41C, UNICODE_NORM_QC_NO}, + {0x1D41D, UNICODE_NORM_QC_NO}, + {0x1D41E, UNICODE_NORM_QC_NO}, + {0x1D41F, UNICODE_NORM_QC_NO}, + {0x1D420, UNICODE_NORM_QC_NO}, + {0x1D421, UNICODE_NORM_QC_NO}, + {0x1D422, UNICODE_NORM_QC_NO}, + {0x1D423, UNICODE_NORM_QC_NO}, + {0x1D424, UNICODE_NORM_QC_NO}, + {0x1D425, UNICODE_NORM_QC_NO}, + {0x1D426, UNICODE_NORM_QC_NO}, + {0x1D427, UNICODE_NORM_QC_NO}, + {0x1D428, UNICODE_NORM_QC_NO}, + {0x1D429, UNICODE_NORM_QC_NO}, + {0x1D42A, UNICODE_NORM_QC_NO}, + {0x1D42B, UNICODE_NORM_QC_NO}, + {0x1D42C, UNICODE_NORM_QC_NO}, + {0x1D42D, UNICODE_NORM_QC_NO}, + {0x1D42E, UNICODE_NORM_QC_NO}, + {0x1D42F, UNICODE_NORM_QC_NO}, + {0x1D430, UNICODE_NORM_QC_NO}, + {0x1D431, UNICODE_NORM_QC_NO}, + {0x1D432, UNICODE_NORM_QC_NO}, + {0x1D433, UNICODE_NORM_QC_NO}, + {0x1D434, UNICODE_NORM_QC_NO}, + {0x1D435, UNICODE_NORM_QC_NO}, + {0x1D436, UNICODE_NORM_QC_NO}, + {0x1D437, UNICODE_NORM_QC_NO}, + {0x1D438, UNICODE_NORM_QC_NO}, + {0x1D439, UNICODE_NORM_QC_NO}, + {0x1D43A, UNICODE_NORM_QC_NO}, + {0x1D43B, UNICODE_NORM_QC_NO}, + {0x1D43C, UNICODE_NORM_QC_NO}, + {0x1D43D, UNICODE_NORM_QC_NO}, + {0x1D43E, UNICODE_NORM_QC_NO}, + {0x1D43F, UNICODE_NORM_QC_NO}, + {0x1D440, UNICODE_NORM_QC_NO}, + {0x1D441, UNICODE_NORM_QC_NO}, + {0x1D442, UNICODE_NORM_QC_NO}, + {0x1D443, UNICODE_NORM_QC_NO}, + {0x1D444, UNICODE_NORM_QC_NO}, + {0x1D445, UNICODE_NORM_QC_NO}, + {0x1D446, UNICODE_NORM_QC_NO}, + {0x1D447, UNICODE_NORM_QC_NO}, + {0x1D448, UNICODE_NORM_QC_NO}, + {0x1D449, UNICODE_NORM_QC_NO}, + {0x1D44A, UNICODE_NORM_QC_NO}, + {0x1D44B, UNICODE_NORM_QC_NO}, + {0x1D44C, UNICODE_NORM_QC_NO}, + {0x1D44D, UNICODE_NORM_QC_NO}, + {0x1D44E, UNICODE_NORM_QC_NO}, + {0x1D44F, UNICODE_NORM_QC_NO}, + {0x1D450, UNICODE_NORM_QC_NO}, + {0x1D451, UNICODE_NORM_QC_NO}, + {0x1D452, UNICODE_NORM_QC_NO}, + {0x1D453, UNICODE_NORM_QC_NO}, + {0x1D454, UNICODE_NORM_QC_NO}, + {0x1D456, UNICODE_NORM_QC_NO}, + {0x1D457, UNICODE_NORM_QC_NO}, + {0x1D458, UNICODE_NORM_QC_NO}, + {0x1D459, UNICODE_NORM_QC_NO}, + {0x1D45A, UNICODE_NORM_QC_NO}, + {0x1D45B, UNICODE_NORM_QC_NO}, + {0x1D45C, UNICODE_NORM_QC_NO}, + {0x1D45D, UNICODE_NORM_QC_NO}, + {0x1D45E, UNICODE_NORM_QC_NO}, + {0x1D45F, UNICODE_NORM_QC_NO}, + {0x1D460, UNICODE_NORM_QC_NO}, + {0x1D461, UNICODE_NORM_QC_NO}, + {0x1D462, UNICODE_NORM_QC_NO}, + {0x1D463, UNICODE_NORM_QC_NO}, + {0x1D464, UNICODE_NORM_QC_NO}, + {0x1D465, UNICODE_NORM_QC_NO}, + {0x1D466, UNICODE_NORM_QC_NO}, + {0x1D467, UNICODE_NORM_QC_NO}, + {0x1D468, UNICODE_NORM_QC_NO}, + {0x1D469, UNICODE_NORM_QC_NO}, + {0x1D46A, UNICODE_NORM_QC_NO}, + {0x1D46B, UNICODE_NORM_QC_NO}, + {0x1D46C, UNICODE_NORM_QC_NO}, + {0x1D46D, UNICODE_NORM_QC_NO}, + {0x1D46E, UNICODE_NORM_QC_NO}, + {0x1D46F, UNICODE_NORM_QC_NO}, + {0x1D470, UNICODE_NORM_QC_NO}, + {0x1D471, UNICODE_NORM_QC_NO}, + {0x1D472, UNICODE_NORM_QC_NO}, + {0x1D473, UNICODE_NORM_QC_NO}, + {0x1D474, UNICODE_NORM_QC_NO}, + {0x1D475, UNICODE_NORM_QC_NO}, + {0x1D476, UNICODE_NORM_QC_NO}, + {0x1D477, UNICODE_NORM_QC_NO}, + {0x1D478, UNICODE_NORM_QC_NO}, + {0x1D479, UNICODE_NORM_QC_NO}, + {0x1D47A, UNICODE_NORM_QC_NO}, + {0x1D47B, UNICODE_NORM_QC_NO}, + {0x1D47C, UNICODE_NORM_QC_NO}, + {0x1D47D, UNICODE_NORM_QC_NO}, + {0x1D47E, UNICODE_NORM_QC_NO}, + {0x1D47F, UNICODE_NORM_QC_NO}, + {0x1D480, UNICODE_NORM_QC_NO}, + {0x1D481, UNICODE_NORM_QC_NO}, + {0x1D482, UNICODE_NORM_QC_NO}, + {0x1D483, UNICODE_NORM_QC_NO}, + {0x1D484, UNICODE_NORM_QC_NO}, + {0x1D485, UNICODE_NORM_QC_NO}, + {0x1D486, UNICODE_NORM_QC_NO}, + {0x1D487, UNICODE_NORM_QC_NO}, + {0x1D488, UNICODE_NORM_QC_NO}, + {0x1D489, UNICODE_NORM_QC_NO}, + {0x1D48A, UNICODE_NORM_QC_NO}, + {0x1D48B, UNICODE_NORM_QC_NO}, + {0x1D48C, UNICODE_NORM_QC_NO}, + {0x1D48D, UNICODE_NORM_QC_NO}, + {0x1D48E, UNICODE_NORM_QC_NO}, + {0x1D48F, UNICODE_NORM_QC_NO}, + {0x1D490, UNICODE_NORM_QC_NO}, + {0x1D491, UNICODE_NORM_QC_NO}, + {0x1D492, UNICODE_NORM_QC_NO}, + {0x1D493, UNICODE_NORM_QC_NO}, + {0x1D494, UNICODE_NORM_QC_NO}, + {0x1D495, UNICODE_NORM_QC_NO}, + {0x1D496, UNICODE_NORM_QC_NO}, + {0x1D497, UNICODE_NORM_QC_NO}, + {0x1D498, UNICODE_NORM_QC_NO}, + {0x1D499, UNICODE_NORM_QC_NO}, + {0x1D49A, UNICODE_NORM_QC_NO}, + {0x1D49B, UNICODE_NORM_QC_NO}, + {0x1D49C, UNICODE_NORM_QC_NO}, + {0x1D49E, UNICODE_NORM_QC_NO}, + {0x1D49F, UNICODE_NORM_QC_NO}, + {0x1D4A2, UNICODE_NORM_QC_NO}, + {0x1D4A5, UNICODE_NORM_QC_NO}, + {0x1D4A6, UNICODE_NORM_QC_NO}, + {0x1D4A9, UNICODE_NORM_QC_NO}, + {0x1D4AA, UNICODE_NORM_QC_NO}, + {0x1D4AB, UNICODE_NORM_QC_NO}, + {0x1D4AC, UNICODE_NORM_QC_NO}, + {0x1D4AE, UNICODE_NORM_QC_NO}, + {0x1D4AF, UNICODE_NORM_QC_NO}, + {0x1D4B0, UNICODE_NORM_QC_NO}, + {0x1D4B1, UNICODE_NORM_QC_NO}, + {0x1D4B2, UNICODE_NORM_QC_NO}, + {0x1D4B3, UNICODE_NORM_QC_NO}, + {0x1D4B4, UNICODE_NORM_QC_NO}, + {0x1D4B5, UNICODE_NORM_QC_NO}, + {0x1D4B6, UNICODE_NORM_QC_NO}, + {0x1D4B7, UNICODE_NORM_QC_NO}, + {0x1D4B8, UNICODE_NORM_QC_NO}, + {0x1D4B9, UNICODE_NORM_QC_NO}, + {0x1D4BB, UNICODE_NORM_QC_NO}, + {0x1D4BD, UNICODE_NORM_QC_NO}, + {0x1D4BE, UNICODE_NORM_QC_NO}, + {0x1D4BF, UNICODE_NORM_QC_NO}, + {0x1D4C0, UNICODE_NORM_QC_NO}, + {0x1D4C1, UNICODE_NORM_QC_NO}, + {0x1D4C2, UNICODE_NORM_QC_NO}, + {0x1D4C3, UNICODE_NORM_QC_NO}, + {0x1D4C5, UNICODE_NORM_QC_NO}, + {0x1D4C6, UNICODE_NORM_QC_NO}, + {0x1D4C7, UNICODE_NORM_QC_NO}, + {0x1D4C8, UNICODE_NORM_QC_NO}, + {0x1D4C9, UNICODE_NORM_QC_NO}, + {0x1D4CA, UNICODE_NORM_QC_NO}, + {0x1D4CB, UNICODE_NORM_QC_NO}, + {0x1D4CC, UNICODE_NORM_QC_NO}, + {0x1D4CD, UNICODE_NORM_QC_NO}, + {0x1D4CE, UNICODE_NORM_QC_NO}, + {0x1D4CF, UNICODE_NORM_QC_NO}, + {0x1D4D0, UNICODE_NORM_QC_NO}, + {0x1D4D1, UNICODE_NORM_QC_NO}, + {0x1D4D2, UNICODE_NORM_QC_NO}, + {0x1D4D3, UNICODE_NORM_QC_NO}, + {0x1D4D4, UNICODE_NORM_QC_NO}, + {0x1D4D5, UNICODE_NORM_QC_NO}, + {0x1D4D6, UNICODE_NORM_QC_NO}, + {0x1D4D7, UNICODE_NORM_QC_NO}, + {0x1D4D8, UNICODE_NORM_QC_NO}, + {0x1D4D9, UNICODE_NORM_QC_NO}, + {0x1D4DA, UNICODE_NORM_QC_NO}, + {0x1D4DB, UNICODE_NORM_QC_NO}, + {0x1D4DC, UNICODE_NORM_QC_NO}, + {0x1D4DD, UNICODE_NORM_QC_NO}, + {0x1D4DE, UNICODE_NORM_QC_NO}, + {0x1D4DF, UNICODE_NORM_QC_NO}, + {0x1D4E0, UNICODE_NORM_QC_NO}, + {0x1D4E1, UNICODE_NORM_QC_NO}, + {0x1D4E2, UNICODE_NORM_QC_NO}, + {0x1D4E3, UNICODE_NORM_QC_NO}, + {0x1D4E4, UNICODE_NORM_QC_NO}, + {0x1D4E5, UNICODE_NORM_QC_NO}, + {0x1D4E6, UNICODE_NORM_QC_NO}, + {0x1D4E7, UNICODE_NORM_QC_NO}, + {0x1D4E8, UNICODE_NORM_QC_NO}, + {0x1D4E9, UNICODE_NORM_QC_NO}, + {0x1D4EA, UNICODE_NORM_QC_NO}, + {0x1D4EB, UNICODE_NORM_QC_NO}, + {0x1D4EC, UNICODE_NORM_QC_NO}, + {0x1D4ED, UNICODE_NORM_QC_NO}, + {0x1D4EE, UNICODE_NORM_QC_NO}, + {0x1D4EF, UNICODE_NORM_QC_NO}, + {0x1D4F0, UNICODE_NORM_QC_NO}, + {0x1D4F1, UNICODE_NORM_QC_NO}, + {0x1D4F2, UNICODE_NORM_QC_NO}, + {0x1D4F3, UNICODE_NORM_QC_NO}, + {0x1D4F4, UNICODE_NORM_QC_NO}, + {0x1D4F5, UNICODE_NORM_QC_NO}, + {0x1D4F6, UNICODE_NORM_QC_NO}, + {0x1D4F7, UNICODE_NORM_QC_NO}, + {0x1D4F8, UNICODE_NORM_QC_NO}, + {0x1D4F9, UNICODE_NORM_QC_NO}, + {0x1D4FA, UNICODE_NORM_QC_NO}, + {0x1D4FB, UNICODE_NORM_QC_NO}, + {0x1D4FC, UNICODE_NORM_QC_NO}, + {0x1D4FD, UNICODE_NORM_QC_NO}, + {0x1D4FE, UNICODE_NORM_QC_NO}, + {0x1D4FF, UNICODE_NORM_QC_NO}, + {0x1D500, UNICODE_NORM_QC_NO}, + {0x1D501, UNICODE_NORM_QC_NO}, + {0x1D502, UNICODE_NORM_QC_NO}, + {0x1D503, UNICODE_NORM_QC_NO}, + {0x1D504, UNICODE_NORM_QC_NO}, + {0x1D505, UNICODE_NORM_QC_NO}, + {0x1D507, UNICODE_NORM_QC_NO}, + {0x1D508, UNICODE_NORM_QC_NO}, + {0x1D509, UNICODE_NORM_QC_NO}, + {0x1D50A, UNICODE_NORM_QC_NO}, + {0x1D50D, UNICODE_NORM_QC_NO}, + {0x1D50E, UNICODE_NORM_QC_NO}, + {0x1D50F, UNICODE_NORM_QC_NO}, + {0x1D510, UNICODE_NORM_QC_NO}, + {0x1D511, UNICODE_NORM_QC_NO}, + {0x1D512, UNICODE_NORM_QC_NO}, + {0x1D513, UNICODE_NORM_QC_NO}, + {0x1D514, UNICODE_NORM_QC_NO}, + {0x1D516, UNICODE_NORM_QC_NO}, + {0x1D517, UNICODE_NORM_QC_NO}, + {0x1D518, UNICODE_NORM_QC_NO}, + {0x1D519, UNICODE_NORM_QC_NO}, + {0x1D51A, UNICODE_NORM_QC_NO}, + {0x1D51B, UNICODE_NORM_QC_NO}, + {0x1D51C, UNICODE_NORM_QC_NO}, + {0x1D51E, UNICODE_NORM_QC_NO}, + {0x1D51F, UNICODE_NORM_QC_NO}, + {0x1D520, UNICODE_NORM_QC_NO}, + {0x1D521, UNICODE_NORM_QC_NO}, + {0x1D522, UNICODE_NORM_QC_NO}, + {0x1D523, UNICODE_NORM_QC_NO}, + {0x1D524, UNICODE_NORM_QC_NO}, + {0x1D525, UNICODE_NORM_QC_NO}, + {0x1D526, UNICODE_NORM_QC_NO}, + {0x1D527, UNICODE_NORM_QC_NO}, + {0x1D528, UNICODE_NORM_QC_NO}, + {0x1D529, UNICODE_NORM_QC_NO}, + {0x1D52A, UNICODE_NORM_QC_NO}, + {0x1D52B, UNICODE_NORM_QC_NO}, + {0x1D52C, UNICODE_NORM_QC_NO}, + {0x1D52D, UNICODE_NORM_QC_NO}, + {0x1D52E, UNICODE_NORM_QC_NO}, + {0x1D52F, UNICODE_NORM_QC_NO}, + {0x1D530, UNICODE_NORM_QC_NO}, + {0x1D531, UNICODE_NORM_QC_NO}, + {0x1D532, UNICODE_NORM_QC_NO}, + {0x1D533, UNICODE_NORM_QC_NO}, + {0x1D534, UNICODE_NORM_QC_NO}, + {0x1D535, UNICODE_NORM_QC_NO}, + {0x1D536, UNICODE_NORM_QC_NO}, + {0x1D537, UNICODE_NORM_QC_NO}, + {0x1D538, UNICODE_NORM_QC_NO}, + {0x1D539, UNICODE_NORM_QC_NO}, + {0x1D53B, UNICODE_NORM_QC_NO}, + {0x1D53C, UNICODE_NORM_QC_NO}, + {0x1D53D, UNICODE_NORM_QC_NO}, + {0x1D53E, UNICODE_NORM_QC_NO}, + {0x1D540, UNICODE_NORM_QC_NO}, + {0x1D541, UNICODE_NORM_QC_NO}, + {0x1D542, UNICODE_NORM_QC_NO}, + {0x1D543, UNICODE_NORM_QC_NO}, + {0x1D544, UNICODE_NORM_QC_NO}, + {0x1D546, UNICODE_NORM_QC_NO}, + {0x1D54A, UNICODE_NORM_QC_NO}, + {0x1D54B, UNICODE_NORM_QC_NO}, + {0x1D54C, UNICODE_NORM_QC_NO}, + {0x1D54D, UNICODE_NORM_QC_NO}, + {0x1D54E, UNICODE_NORM_QC_NO}, + {0x1D54F, UNICODE_NORM_QC_NO}, + {0x1D550, UNICODE_NORM_QC_NO}, + {0x1D552, UNICODE_NORM_QC_NO}, + {0x1D553, UNICODE_NORM_QC_NO}, + {0x1D554, UNICODE_NORM_QC_NO}, + {0x1D555, UNICODE_NORM_QC_NO}, + {0x1D556, UNICODE_NORM_QC_NO}, + {0x1D557, UNICODE_NORM_QC_NO}, + {0x1D558, UNICODE_NORM_QC_NO}, + {0x1D559, UNICODE_NORM_QC_NO}, + {0x1D55A, UNICODE_NORM_QC_NO}, + {0x1D55B, UNICODE_NORM_QC_NO}, + {0x1D55C, UNICODE_NORM_QC_NO}, + {0x1D55D, UNICODE_NORM_QC_NO}, + {0x1D55E, UNICODE_NORM_QC_NO}, + {0x1D55F, UNICODE_NORM_QC_NO}, + {0x1D560, UNICODE_NORM_QC_NO}, + {0x1D561, UNICODE_NORM_QC_NO}, + {0x1D562, UNICODE_NORM_QC_NO}, + {0x1D563, UNICODE_NORM_QC_NO}, + {0x1D564, UNICODE_NORM_QC_NO}, + {0x1D565, UNICODE_NORM_QC_NO}, + {0x1D566, UNICODE_NORM_QC_NO}, + {0x1D567, UNICODE_NORM_QC_NO}, + {0x1D568, UNICODE_NORM_QC_NO}, + {0x1D569, UNICODE_NORM_QC_NO}, + {0x1D56A, UNICODE_NORM_QC_NO}, + {0x1D56B, UNICODE_NORM_QC_NO}, + {0x1D56C, UNICODE_NORM_QC_NO}, + {0x1D56D, UNICODE_NORM_QC_NO}, + {0x1D56E, UNICODE_NORM_QC_NO}, + {0x1D56F, UNICODE_NORM_QC_NO}, + {0x1D570, UNICODE_NORM_QC_NO}, + {0x1D571, UNICODE_NORM_QC_NO}, + {0x1D572, UNICODE_NORM_QC_NO}, + {0x1D573, UNICODE_NORM_QC_NO}, + {0x1D574, UNICODE_NORM_QC_NO}, + {0x1D575, UNICODE_NORM_QC_NO}, + {0x1D576, UNICODE_NORM_QC_NO}, + {0x1D577, UNICODE_NORM_QC_NO}, + {0x1D578, UNICODE_NORM_QC_NO}, + {0x1D579, UNICODE_NORM_QC_NO}, + {0x1D57A, UNICODE_NORM_QC_NO}, + {0x1D57B, UNICODE_NORM_QC_NO}, + {0x1D57C, UNICODE_NORM_QC_NO}, + {0x1D57D, UNICODE_NORM_QC_NO}, + {0x1D57E, UNICODE_NORM_QC_NO}, + {0x1D57F, UNICODE_NORM_QC_NO}, + {0x1D580, UNICODE_NORM_QC_NO}, + {0x1D581, UNICODE_NORM_QC_NO}, + {0x1D582, UNICODE_NORM_QC_NO}, + {0x1D583, UNICODE_NORM_QC_NO}, + {0x1D584, UNICODE_NORM_QC_NO}, + {0x1D585, UNICODE_NORM_QC_NO}, + {0x1D586, UNICODE_NORM_QC_NO}, + {0x1D587, UNICODE_NORM_QC_NO}, + {0x1D588, UNICODE_NORM_QC_NO}, + {0x1D589, UNICODE_NORM_QC_NO}, + {0x1D58A, UNICODE_NORM_QC_NO}, + {0x1D58B, UNICODE_NORM_QC_NO}, + {0x1D58C, UNICODE_NORM_QC_NO}, + {0x1D58D, UNICODE_NORM_QC_NO}, + {0x1D58E, UNICODE_NORM_QC_NO}, + {0x1D58F, UNICODE_NORM_QC_NO}, + {0x1D590, UNICODE_NORM_QC_NO}, + {0x1D591, UNICODE_NORM_QC_NO}, + {0x1D592, UNICODE_NORM_QC_NO}, + {0x1D593, UNICODE_NORM_QC_NO}, + {0x1D594, UNICODE_NORM_QC_NO}, + {0x1D595, UNICODE_NORM_QC_NO}, + {0x1D596, UNICODE_NORM_QC_NO}, + {0x1D597, UNICODE_NORM_QC_NO}, + {0x1D598, UNICODE_NORM_QC_NO}, + {0x1D599, UNICODE_NORM_QC_NO}, + {0x1D59A, UNICODE_NORM_QC_NO}, + {0x1D59B, UNICODE_NORM_QC_NO}, + {0x1D59C, UNICODE_NORM_QC_NO}, + {0x1D59D, UNICODE_NORM_QC_NO}, + {0x1D59E, UNICODE_NORM_QC_NO}, + {0x1D59F, UNICODE_NORM_QC_NO}, + {0x1D5A0, UNICODE_NORM_QC_NO}, + {0x1D5A1, UNICODE_NORM_QC_NO}, + {0x1D5A2, UNICODE_NORM_QC_NO}, + {0x1D5A3, UNICODE_NORM_QC_NO}, + {0x1D5A4, UNICODE_NORM_QC_NO}, + {0x1D5A5, UNICODE_NORM_QC_NO}, + {0x1D5A6, UNICODE_NORM_QC_NO}, + {0x1D5A7, UNICODE_NORM_QC_NO}, + {0x1D5A8, UNICODE_NORM_QC_NO}, + {0x1D5A9, UNICODE_NORM_QC_NO}, + {0x1D5AA, UNICODE_NORM_QC_NO}, + {0x1D5AB, UNICODE_NORM_QC_NO}, + {0x1D5AC, UNICODE_NORM_QC_NO}, + {0x1D5AD, UNICODE_NORM_QC_NO}, + {0x1D5AE, UNICODE_NORM_QC_NO}, + {0x1D5AF, UNICODE_NORM_QC_NO}, + {0x1D5B0, UNICODE_NORM_QC_NO}, + {0x1D5B1, UNICODE_NORM_QC_NO}, + {0x1D5B2, UNICODE_NORM_QC_NO}, + {0x1D5B3, UNICODE_NORM_QC_NO}, + {0x1D5B4, UNICODE_NORM_QC_NO}, + {0x1D5B5, UNICODE_NORM_QC_NO}, + {0x1D5B6, UNICODE_NORM_QC_NO}, + {0x1D5B7, UNICODE_NORM_QC_NO}, + {0x1D5B8, UNICODE_NORM_QC_NO}, + {0x1D5B9, UNICODE_NORM_QC_NO}, + {0x1D5BA, UNICODE_NORM_QC_NO}, + {0x1D5BB, UNICODE_NORM_QC_NO}, + {0x1D5BC, UNICODE_NORM_QC_NO}, + {0x1D5BD, UNICODE_NORM_QC_NO}, + {0x1D5BE, UNICODE_NORM_QC_NO}, + {0x1D5BF, UNICODE_NORM_QC_NO}, + {0x1D5C0, UNICODE_NORM_QC_NO}, + {0x1D5C1, UNICODE_NORM_QC_NO}, + {0x1D5C2, UNICODE_NORM_QC_NO}, + {0x1D5C3, UNICODE_NORM_QC_NO}, + {0x1D5C4, UNICODE_NORM_QC_NO}, + {0x1D5C5, UNICODE_NORM_QC_NO}, + {0x1D5C6, UNICODE_NORM_QC_NO}, + {0x1D5C7, UNICODE_NORM_QC_NO}, + {0x1D5C8, UNICODE_NORM_QC_NO}, + {0x1D5C9, UNICODE_NORM_QC_NO}, + {0x1D5CA, UNICODE_NORM_QC_NO}, + {0x1D5CB, UNICODE_NORM_QC_NO}, + {0x1D5CC, UNICODE_NORM_QC_NO}, + {0x1D5CD, UNICODE_NORM_QC_NO}, + {0x1D5CE, UNICODE_NORM_QC_NO}, + {0x1D5CF, UNICODE_NORM_QC_NO}, + {0x1D5D0, UNICODE_NORM_QC_NO}, + {0x1D5D1, UNICODE_NORM_QC_NO}, + {0x1D5D2, UNICODE_NORM_QC_NO}, + {0x1D5D3, UNICODE_NORM_QC_NO}, + {0x1D5D4, UNICODE_NORM_QC_NO}, + {0x1D5D5, UNICODE_NORM_QC_NO}, + {0x1D5D6, UNICODE_NORM_QC_NO}, + {0x1D5D7, UNICODE_NORM_QC_NO}, + {0x1D5D8, UNICODE_NORM_QC_NO}, + {0x1D5D9, UNICODE_NORM_QC_NO}, + {0x1D5DA, UNICODE_NORM_QC_NO}, + {0x1D5DB, UNICODE_NORM_QC_NO}, + {0x1D5DC, UNICODE_NORM_QC_NO}, + {0x1D5DD, UNICODE_NORM_QC_NO}, + {0x1D5DE, UNICODE_NORM_QC_NO}, + {0x1D5DF, UNICODE_NORM_QC_NO}, + {0x1D5E0, UNICODE_NORM_QC_NO}, + {0x1D5E1, UNICODE_NORM_QC_NO}, + {0x1D5E2, UNICODE_NORM_QC_NO}, + {0x1D5E3, UNICODE_NORM_QC_NO}, + {0x1D5E4, UNICODE_NORM_QC_NO}, + {0x1D5E5, UNICODE_NORM_QC_NO}, + {0x1D5E6, UNICODE_NORM_QC_NO}, + {0x1D5E7, UNICODE_NORM_QC_NO}, + {0x1D5E8, UNICODE_NORM_QC_NO}, + {0x1D5E9, UNICODE_NORM_QC_NO}, + {0x1D5EA, UNICODE_NORM_QC_NO}, + {0x1D5EB, UNICODE_NORM_QC_NO}, + {0x1D5EC, UNICODE_NORM_QC_NO}, + {0x1D5ED, UNICODE_NORM_QC_NO}, + {0x1D5EE, UNICODE_NORM_QC_NO}, + {0x1D5EF, UNICODE_NORM_QC_NO}, + {0x1D5F0, UNICODE_NORM_QC_NO}, + {0x1D5F1, UNICODE_NORM_QC_NO}, + {0x1D5F2, UNICODE_NORM_QC_NO}, + {0x1D5F3, UNICODE_NORM_QC_NO}, + {0x1D5F4, UNICODE_NORM_QC_NO}, + {0x1D5F5, UNICODE_NORM_QC_NO}, + {0x1D5F6, UNICODE_NORM_QC_NO}, + {0x1D5F7, UNICODE_NORM_QC_NO}, + {0x1D5F8, UNICODE_NORM_QC_NO}, + {0x1D5F9, UNICODE_NORM_QC_NO}, + {0x1D5FA, UNICODE_NORM_QC_NO}, + {0x1D5FB, UNICODE_NORM_QC_NO}, + {0x1D5FC, UNICODE_NORM_QC_NO}, + {0x1D5FD, UNICODE_NORM_QC_NO}, + {0x1D5FE, UNICODE_NORM_QC_NO}, + {0x1D5FF, UNICODE_NORM_QC_NO}, + {0x1D600, UNICODE_NORM_QC_NO}, + {0x1D601, UNICODE_NORM_QC_NO}, + {0x1D602, UNICODE_NORM_QC_NO}, + {0x1D603, UNICODE_NORM_QC_NO}, + {0x1D604, UNICODE_NORM_QC_NO}, + {0x1D605, UNICODE_NORM_QC_NO}, + {0x1D606, UNICODE_NORM_QC_NO}, + {0x1D607, UNICODE_NORM_QC_NO}, + {0x1D608, UNICODE_NORM_QC_NO}, + {0x1D609, UNICODE_NORM_QC_NO}, + {0x1D60A, UNICODE_NORM_QC_NO}, + {0x1D60B, UNICODE_NORM_QC_NO}, + {0x1D60C, UNICODE_NORM_QC_NO}, + {0x1D60D, UNICODE_NORM_QC_NO}, + {0x1D60E, UNICODE_NORM_QC_NO}, + {0x1D60F, UNICODE_NORM_QC_NO}, + {0x1D610, UNICODE_NORM_QC_NO}, + {0x1D611, UNICODE_NORM_QC_NO}, + {0x1D612, UNICODE_NORM_QC_NO}, + {0x1D613, UNICODE_NORM_QC_NO}, + {0x1D614, UNICODE_NORM_QC_NO}, + {0x1D615, UNICODE_NORM_QC_NO}, + {0x1D616, UNICODE_NORM_QC_NO}, + {0x1D617, UNICODE_NORM_QC_NO}, + {0x1D618, UNICODE_NORM_QC_NO}, + {0x1D619, UNICODE_NORM_QC_NO}, + {0x1D61A, UNICODE_NORM_QC_NO}, + {0x1D61B, UNICODE_NORM_QC_NO}, + {0x1D61C, UNICODE_NORM_QC_NO}, + {0x1D61D, UNICODE_NORM_QC_NO}, + {0x1D61E, UNICODE_NORM_QC_NO}, + {0x1D61F, UNICODE_NORM_QC_NO}, + {0x1D620, UNICODE_NORM_QC_NO}, + {0x1D621, UNICODE_NORM_QC_NO}, + {0x1D622, UNICODE_NORM_QC_NO}, + {0x1D623, UNICODE_NORM_QC_NO}, + {0x1D624, UNICODE_NORM_QC_NO}, + {0x1D625, UNICODE_NORM_QC_NO}, + {0x1D626, UNICODE_NORM_QC_NO}, + {0x1D627, UNICODE_NORM_QC_NO}, + {0x1D628, UNICODE_NORM_QC_NO}, + {0x1D629, UNICODE_NORM_QC_NO}, + {0x1D62A, UNICODE_NORM_QC_NO}, + {0x1D62B, UNICODE_NORM_QC_NO}, + {0x1D62C, UNICODE_NORM_QC_NO}, + {0x1D62D, UNICODE_NORM_QC_NO}, + {0x1D62E, UNICODE_NORM_QC_NO}, + {0x1D62F, UNICODE_NORM_QC_NO}, + {0x1D630, UNICODE_NORM_QC_NO}, + {0x1D631, UNICODE_NORM_QC_NO}, + {0x1D632, UNICODE_NORM_QC_NO}, + {0x1D633, UNICODE_NORM_QC_NO}, + {0x1D634, UNICODE_NORM_QC_NO}, + {0x1D635, UNICODE_NORM_QC_NO}, + {0x1D636, UNICODE_NORM_QC_NO}, + {0x1D637, UNICODE_NORM_QC_NO}, + {0x1D638, UNICODE_NORM_QC_NO}, + {0x1D639, UNICODE_NORM_QC_NO}, + {0x1D63A, UNICODE_NORM_QC_NO}, + {0x1D63B, UNICODE_NORM_QC_NO}, + {0x1D63C, UNICODE_NORM_QC_NO}, + {0x1D63D, UNICODE_NORM_QC_NO}, + {0x1D63E, UNICODE_NORM_QC_NO}, + {0x1D63F, UNICODE_NORM_QC_NO}, + {0x1D640, UNICODE_NORM_QC_NO}, + {0x1D641, UNICODE_NORM_QC_NO}, + {0x1D642, UNICODE_NORM_QC_NO}, + {0x1D643, UNICODE_NORM_QC_NO}, + {0x1D644, UNICODE_NORM_QC_NO}, + {0x1D645, UNICODE_NORM_QC_NO}, + {0x1D646, UNICODE_NORM_QC_NO}, + {0x1D647, UNICODE_NORM_QC_NO}, + {0x1D648, UNICODE_NORM_QC_NO}, + {0x1D649, UNICODE_NORM_QC_NO}, + {0x1D64A, UNICODE_NORM_QC_NO}, + {0x1D64B, UNICODE_NORM_QC_NO}, + {0x1D64C, UNICODE_NORM_QC_NO}, + {0x1D64D, UNICODE_NORM_QC_NO}, + {0x1D64E, UNICODE_NORM_QC_NO}, + {0x1D64F, UNICODE_NORM_QC_NO}, + {0x1D650, UNICODE_NORM_QC_NO}, + {0x1D651, UNICODE_NORM_QC_NO}, + {0x1D652, UNICODE_NORM_QC_NO}, + {0x1D653, UNICODE_NORM_QC_NO}, + {0x1D654, UNICODE_NORM_QC_NO}, + {0x1D655, UNICODE_NORM_QC_NO}, + {0x1D656, UNICODE_NORM_QC_NO}, + {0x1D657, UNICODE_NORM_QC_NO}, + {0x1D658, UNICODE_NORM_QC_NO}, + {0x1D659, UNICODE_NORM_QC_NO}, + {0x1D65A, UNICODE_NORM_QC_NO}, + {0x1D65B, UNICODE_NORM_QC_NO}, + {0x1D65C, UNICODE_NORM_QC_NO}, + {0x1D65D, UNICODE_NORM_QC_NO}, + {0x1D65E, UNICODE_NORM_QC_NO}, + {0x1D65F, UNICODE_NORM_QC_NO}, + {0x1D660, UNICODE_NORM_QC_NO}, + {0x1D661, UNICODE_NORM_QC_NO}, + {0x1D662, UNICODE_NORM_QC_NO}, + {0x1D663, UNICODE_NORM_QC_NO}, + {0x1D664, UNICODE_NORM_QC_NO}, + {0x1D665, UNICODE_NORM_QC_NO}, + {0x1D666, UNICODE_NORM_QC_NO}, + {0x1D667, UNICODE_NORM_QC_NO}, + {0x1D668, UNICODE_NORM_QC_NO}, + {0x1D669, UNICODE_NORM_QC_NO}, + {0x1D66A, UNICODE_NORM_QC_NO}, + {0x1D66B, UNICODE_NORM_QC_NO}, + {0x1D66C, UNICODE_NORM_QC_NO}, + {0x1D66D, UNICODE_NORM_QC_NO}, + {0x1D66E, UNICODE_NORM_QC_NO}, + {0x1D66F, UNICODE_NORM_QC_NO}, + {0x1D670, UNICODE_NORM_QC_NO}, + {0x1D671, UNICODE_NORM_QC_NO}, + {0x1D672, UNICODE_NORM_QC_NO}, + {0x1D673, UNICODE_NORM_QC_NO}, + {0x1D674, UNICODE_NORM_QC_NO}, + {0x1D675, UNICODE_NORM_QC_NO}, + {0x1D676, UNICODE_NORM_QC_NO}, + {0x1D677, UNICODE_NORM_QC_NO}, + {0x1D678, UNICODE_NORM_QC_NO}, + {0x1D679, UNICODE_NORM_QC_NO}, + {0x1D67A, UNICODE_NORM_QC_NO}, + {0x1D67B, UNICODE_NORM_QC_NO}, + {0x1D67C, UNICODE_NORM_QC_NO}, + {0x1D67D, UNICODE_NORM_QC_NO}, + {0x1D67E, UNICODE_NORM_QC_NO}, + {0x1D67F, UNICODE_NORM_QC_NO}, + {0x1D680, UNICODE_NORM_QC_NO}, + {0x1D681, UNICODE_NORM_QC_NO}, + {0x1D682, UNICODE_NORM_QC_NO}, + {0x1D683, UNICODE_NORM_QC_NO}, + {0x1D684, UNICODE_NORM_QC_NO}, + {0x1D685, UNICODE_NORM_QC_NO}, + {0x1D686, UNICODE_NORM_QC_NO}, + {0x1D687, UNICODE_NORM_QC_NO}, + {0x1D688, UNICODE_NORM_QC_NO}, + {0x1D689, UNICODE_NORM_QC_NO}, + {0x1D68A, UNICODE_NORM_QC_NO}, + {0x1D68B, UNICODE_NORM_QC_NO}, + {0x1D68C, UNICODE_NORM_QC_NO}, + {0x1D68D, UNICODE_NORM_QC_NO}, + {0x1D68E, UNICODE_NORM_QC_NO}, + {0x1D68F, UNICODE_NORM_QC_NO}, + {0x1D690, UNICODE_NORM_QC_NO}, + {0x1D691, UNICODE_NORM_QC_NO}, + {0x1D692, UNICODE_NORM_QC_NO}, + {0x1D693, UNICODE_NORM_QC_NO}, + {0x1D694, UNICODE_NORM_QC_NO}, + {0x1D695, UNICODE_NORM_QC_NO}, + {0x1D696, UNICODE_NORM_QC_NO}, + {0x1D697, UNICODE_NORM_QC_NO}, + {0x1D698, UNICODE_NORM_QC_NO}, + {0x1D699, UNICODE_NORM_QC_NO}, + {0x1D69A, UNICODE_NORM_QC_NO}, + {0x1D69B, UNICODE_NORM_QC_NO}, + {0x1D69C, UNICODE_NORM_QC_NO}, + {0x1D69D, UNICODE_NORM_QC_NO}, + {0x1D69E, UNICODE_NORM_QC_NO}, + {0x1D69F, UNICODE_NORM_QC_NO}, + {0x1D6A0, UNICODE_NORM_QC_NO}, + {0x1D6A1, UNICODE_NORM_QC_NO}, + {0x1D6A2, UNICODE_NORM_QC_NO}, + {0x1D6A3, UNICODE_NORM_QC_NO}, + {0x1D6A4, UNICODE_NORM_QC_NO}, + {0x1D6A5, UNICODE_NORM_QC_NO}, + {0x1D6A8, UNICODE_NORM_QC_NO}, + {0x1D6A9, UNICODE_NORM_QC_NO}, + {0x1D6AA, UNICODE_NORM_QC_NO}, + {0x1D6AB, UNICODE_NORM_QC_NO}, + {0x1D6AC, UNICODE_NORM_QC_NO}, + {0x1D6AD, UNICODE_NORM_QC_NO}, + {0x1D6AE, UNICODE_NORM_QC_NO}, + {0x1D6AF, UNICODE_NORM_QC_NO}, + {0x1D6B0, UNICODE_NORM_QC_NO}, + {0x1D6B1, UNICODE_NORM_QC_NO}, + {0x1D6B2, UNICODE_NORM_QC_NO}, + {0x1D6B3, UNICODE_NORM_QC_NO}, + {0x1D6B4, UNICODE_NORM_QC_NO}, + {0x1D6B5, UNICODE_NORM_QC_NO}, + {0x1D6B6, UNICODE_NORM_QC_NO}, + {0x1D6B7, UNICODE_NORM_QC_NO}, + {0x1D6B8, UNICODE_NORM_QC_NO}, + {0x1D6B9, UNICODE_NORM_QC_NO}, + {0x1D6BA, UNICODE_NORM_QC_NO}, + {0x1D6BB, UNICODE_NORM_QC_NO}, + {0x1D6BC, UNICODE_NORM_QC_NO}, + {0x1D6BD, UNICODE_NORM_QC_NO}, + {0x1D6BE, UNICODE_NORM_QC_NO}, + {0x1D6BF, UNICODE_NORM_QC_NO}, + {0x1D6C0, UNICODE_NORM_QC_NO}, + {0x1D6C1, UNICODE_NORM_QC_NO}, + {0x1D6C2, UNICODE_NORM_QC_NO}, + {0x1D6C3, UNICODE_NORM_QC_NO}, + {0x1D6C4, UNICODE_NORM_QC_NO}, + {0x1D6C5, UNICODE_NORM_QC_NO}, + {0x1D6C6, UNICODE_NORM_QC_NO}, + {0x1D6C7, UNICODE_NORM_QC_NO}, + {0x1D6C8, UNICODE_NORM_QC_NO}, + {0x1D6C9, UNICODE_NORM_QC_NO}, + {0x1D6CA, UNICODE_NORM_QC_NO}, + {0x1D6CB, UNICODE_NORM_QC_NO}, + {0x1D6CC, UNICODE_NORM_QC_NO}, + {0x1D6CD, UNICODE_NORM_QC_NO}, + {0x1D6CE, UNICODE_NORM_QC_NO}, + {0x1D6CF, UNICODE_NORM_QC_NO}, + {0x1D6D0, UNICODE_NORM_QC_NO}, + {0x1D6D1, UNICODE_NORM_QC_NO}, + {0x1D6D2, UNICODE_NORM_QC_NO}, + {0x1D6D3, UNICODE_NORM_QC_NO}, + {0x1D6D4, UNICODE_NORM_QC_NO}, + {0x1D6D5, UNICODE_NORM_QC_NO}, + {0x1D6D6, UNICODE_NORM_QC_NO}, + {0x1D6D7, UNICODE_NORM_QC_NO}, + {0x1D6D8, UNICODE_NORM_QC_NO}, + {0x1D6D9, UNICODE_NORM_QC_NO}, + {0x1D6DA, UNICODE_NORM_QC_NO}, + {0x1D6DB, UNICODE_NORM_QC_NO}, + {0x1D6DC, UNICODE_NORM_QC_NO}, + {0x1D6DD, UNICODE_NORM_QC_NO}, + {0x1D6DE, UNICODE_NORM_QC_NO}, + {0x1D6DF, UNICODE_NORM_QC_NO}, + {0x1D6E0, UNICODE_NORM_QC_NO}, + {0x1D6E1, UNICODE_NORM_QC_NO}, + {0x1D6E2, UNICODE_NORM_QC_NO}, + {0x1D6E3, UNICODE_NORM_QC_NO}, + {0x1D6E4, UNICODE_NORM_QC_NO}, + {0x1D6E5, UNICODE_NORM_QC_NO}, + {0x1D6E6, UNICODE_NORM_QC_NO}, + {0x1D6E7, UNICODE_NORM_QC_NO}, + {0x1D6E8, UNICODE_NORM_QC_NO}, + {0x1D6E9, UNICODE_NORM_QC_NO}, + {0x1D6EA, UNICODE_NORM_QC_NO}, + {0x1D6EB, UNICODE_NORM_QC_NO}, + {0x1D6EC, UNICODE_NORM_QC_NO}, + {0x1D6ED, UNICODE_NORM_QC_NO}, + {0x1D6EE, UNICODE_NORM_QC_NO}, + {0x1D6EF, UNICODE_NORM_QC_NO}, + {0x1D6F0, UNICODE_NORM_QC_NO}, + {0x1D6F1, UNICODE_NORM_QC_NO}, + {0x1D6F2, UNICODE_NORM_QC_NO}, + {0x1D6F3, UNICODE_NORM_QC_NO}, + {0x1D6F4, UNICODE_NORM_QC_NO}, + {0x1D6F5, UNICODE_NORM_QC_NO}, + {0x1D6F6, UNICODE_NORM_QC_NO}, + {0x1D6F7, UNICODE_NORM_QC_NO}, + {0x1D6F8, UNICODE_NORM_QC_NO}, + {0x1D6F9, UNICODE_NORM_QC_NO}, + {0x1D6FA, UNICODE_NORM_QC_NO}, + {0x1D6FB, UNICODE_NORM_QC_NO}, + {0x1D6FC, UNICODE_NORM_QC_NO}, + {0x1D6FD, UNICODE_NORM_QC_NO}, + {0x1D6FE, UNICODE_NORM_QC_NO}, + {0x1D6FF, UNICODE_NORM_QC_NO}, + {0x1D700, UNICODE_NORM_QC_NO}, + {0x1D701, UNICODE_NORM_QC_NO}, + {0x1D702, UNICODE_NORM_QC_NO}, + {0x1D703, UNICODE_NORM_QC_NO}, + {0x1D704, UNICODE_NORM_QC_NO}, + {0x1D705, UNICODE_NORM_QC_NO}, + {0x1D706, UNICODE_NORM_QC_NO}, + {0x1D707, UNICODE_NORM_QC_NO}, + {0x1D708, UNICODE_NORM_QC_NO}, + {0x1D709, UNICODE_NORM_QC_NO}, + {0x1D70A, UNICODE_NORM_QC_NO}, + {0x1D70B, UNICODE_NORM_QC_NO}, + {0x1D70C, UNICODE_NORM_QC_NO}, + {0x1D70D, UNICODE_NORM_QC_NO}, + {0x1D70E, UNICODE_NORM_QC_NO}, + {0x1D70F, UNICODE_NORM_QC_NO}, + {0x1D710, UNICODE_NORM_QC_NO}, + {0x1D711, UNICODE_NORM_QC_NO}, + {0x1D712, UNICODE_NORM_QC_NO}, + {0x1D713, UNICODE_NORM_QC_NO}, + {0x1D714, UNICODE_NORM_QC_NO}, + {0x1D715, UNICODE_NORM_QC_NO}, + {0x1D716, UNICODE_NORM_QC_NO}, + {0x1D717, UNICODE_NORM_QC_NO}, + {0x1D718, UNICODE_NORM_QC_NO}, + {0x1D719, UNICODE_NORM_QC_NO}, + {0x1D71A, UNICODE_NORM_QC_NO}, + {0x1D71B, UNICODE_NORM_QC_NO}, + {0x1D71C, UNICODE_NORM_QC_NO}, + {0x1D71D, UNICODE_NORM_QC_NO}, + {0x1D71E, UNICODE_NORM_QC_NO}, + {0x1D71F, UNICODE_NORM_QC_NO}, + {0x1D720, UNICODE_NORM_QC_NO}, + {0x1D721, UNICODE_NORM_QC_NO}, + {0x1D722, UNICODE_NORM_QC_NO}, + {0x1D723, UNICODE_NORM_QC_NO}, + {0x1D724, UNICODE_NORM_QC_NO}, + {0x1D725, UNICODE_NORM_QC_NO}, + {0x1D726, UNICODE_NORM_QC_NO}, + {0x1D727, UNICODE_NORM_QC_NO}, + {0x1D728, UNICODE_NORM_QC_NO}, + {0x1D729, UNICODE_NORM_QC_NO}, + {0x1D72A, UNICODE_NORM_QC_NO}, + {0x1D72B, UNICODE_NORM_QC_NO}, + {0x1D72C, UNICODE_NORM_QC_NO}, + {0x1D72D, UNICODE_NORM_QC_NO}, + {0x1D72E, UNICODE_NORM_QC_NO}, + {0x1D72F, UNICODE_NORM_QC_NO}, + {0x1D730, UNICODE_NORM_QC_NO}, + {0x1D731, UNICODE_NORM_QC_NO}, + {0x1D732, UNICODE_NORM_QC_NO}, + {0x1D733, UNICODE_NORM_QC_NO}, + {0x1D734, UNICODE_NORM_QC_NO}, + {0x1D735, UNICODE_NORM_QC_NO}, + {0x1D736, UNICODE_NORM_QC_NO}, + {0x1D737, UNICODE_NORM_QC_NO}, + {0x1D738, UNICODE_NORM_QC_NO}, + {0x1D739, UNICODE_NORM_QC_NO}, + {0x1D73A, UNICODE_NORM_QC_NO}, + {0x1D73B, UNICODE_NORM_QC_NO}, + {0x1D73C, UNICODE_NORM_QC_NO}, + {0x1D73D, UNICODE_NORM_QC_NO}, + {0x1D73E, UNICODE_NORM_QC_NO}, + {0x1D73F, UNICODE_NORM_QC_NO}, + {0x1D740, UNICODE_NORM_QC_NO}, + {0x1D741, UNICODE_NORM_QC_NO}, + {0x1D742, UNICODE_NORM_QC_NO}, + {0x1D743, UNICODE_NORM_QC_NO}, + {0x1D744, UNICODE_NORM_QC_NO}, + {0x1D745, UNICODE_NORM_QC_NO}, + {0x1D746, UNICODE_NORM_QC_NO}, + {0x1D747, UNICODE_NORM_QC_NO}, + {0x1D748, UNICODE_NORM_QC_NO}, + {0x1D749, UNICODE_NORM_QC_NO}, + {0x1D74A, UNICODE_NORM_QC_NO}, + {0x1D74B, UNICODE_NORM_QC_NO}, + {0x1D74C, UNICODE_NORM_QC_NO}, + {0x1D74D, UNICODE_NORM_QC_NO}, + {0x1D74E, UNICODE_NORM_QC_NO}, + {0x1D74F, UNICODE_NORM_QC_NO}, + {0x1D750, UNICODE_NORM_QC_NO}, + {0x1D751, UNICODE_NORM_QC_NO}, + {0x1D752, UNICODE_NORM_QC_NO}, + {0x1D753, UNICODE_NORM_QC_NO}, + {0x1D754, UNICODE_NORM_QC_NO}, + {0x1D755, UNICODE_NORM_QC_NO}, + {0x1D756, UNICODE_NORM_QC_NO}, + {0x1D757, UNICODE_NORM_QC_NO}, + {0x1D758, UNICODE_NORM_QC_NO}, + {0x1D759, UNICODE_NORM_QC_NO}, + {0x1D75A, UNICODE_NORM_QC_NO}, + {0x1D75B, UNICODE_NORM_QC_NO}, + {0x1D75C, UNICODE_NORM_QC_NO}, + {0x1D75D, UNICODE_NORM_QC_NO}, + {0x1D75E, UNICODE_NORM_QC_NO}, + {0x1D75F, UNICODE_NORM_QC_NO}, + {0x1D760, UNICODE_NORM_QC_NO}, + {0x1D761, UNICODE_NORM_QC_NO}, + {0x1D762, UNICODE_NORM_QC_NO}, + {0x1D763, UNICODE_NORM_QC_NO}, + {0x1D764, UNICODE_NORM_QC_NO}, + {0x1D765, UNICODE_NORM_QC_NO}, + {0x1D766, UNICODE_NORM_QC_NO}, + {0x1D767, UNICODE_NORM_QC_NO}, + {0x1D768, UNICODE_NORM_QC_NO}, + {0x1D769, UNICODE_NORM_QC_NO}, + {0x1D76A, UNICODE_NORM_QC_NO}, + {0x1D76B, UNICODE_NORM_QC_NO}, + {0x1D76C, UNICODE_NORM_QC_NO}, + {0x1D76D, UNICODE_NORM_QC_NO}, + {0x1D76E, UNICODE_NORM_QC_NO}, + {0x1D76F, UNICODE_NORM_QC_NO}, + {0x1D770, UNICODE_NORM_QC_NO}, + {0x1D771, UNICODE_NORM_QC_NO}, + {0x1D772, UNICODE_NORM_QC_NO}, + {0x1D773, UNICODE_NORM_QC_NO}, + {0x1D774, UNICODE_NORM_QC_NO}, + {0x1D775, UNICODE_NORM_QC_NO}, + {0x1D776, UNICODE_NORM_QC_NO}, + {0x1D777, UNICODE_NORM_QC_NO}, + {0x1D778, UNICODE_NORM_QC_NO}, + {0x1D779, UNICODE_NORM_QC_NO}, + {0x1D77A, UNICODE_NORM_QC_NO}, + {0x1D77B, UNICODE_NORM_QC_NO}, + {0x1D77C, UNICODE_NORM_QC_NO}, + {0x1D77D, UNICODE_NORM_QC_NO}, + {0x1D77E, UNICODE_NORM_QC_NO}, + {0x1D77F, UNICODE_NORM_QC_NO}, + {0x1D780, UNICODE_NORM_QC_NO}, + {0x1D781, UNICODE_NORM_QC_NO}, + {0x1D782, UNICODE_NORM_QC_NO}, + {0x1D783, UNICODE_NORM_QC_NO}, + {0x1D784, UNICODE_NORM_QC_NO}, + {0x1D785, UNICODE_NORM_QC_NO}, + {0x1D786, UNICODE_NORM_QC_NO}, + {0x1D787, UNICODE_NORM_QC_NO}, + {0x1D788, UNICODE_NORM_QC_NO}, + {0x1D789, UNICODE_NORM_QC_NO}, + {0x1D78A, UNICODE_NORM_QC_NO}, + {0x1D78B, UNICODE_NORM_QC_NO}, + {0x1D78C, UNICODE_NORM_QC_NO}, + {0x1D78D, UNICODE_NORM_QC_NO}, + {0x1D78E, UNICODE_NORM_QC_NO}, + {0x1D78F, UNICODE_NORM_QC_NO}, + {0x1D790, UNICODE_NORM_QC_NO}, + {0x1D791, UNICODE_NORM_QC_NO}, + {0x1D792, UNICODE_NORM_QC_NO}, + {0x1D793, UNICODE_NORM_QC_NO}, + {0x1D794, UNICODE_NORM_QC_NO}, + {0x1D795, UNICODE_NORM_QC_NO}, + {0x1D796, UNICODE_NORM_QC_NO}, + {0x1D797, UNICODE_NORM_QC_NO}, + {0x1D798, UNICODE_NORM_QC_NO}, + {0x1D799, UNICODE_NORM_QC_NO}, + {0x1D79A, UNICODE_NORM_QC_NO}, + {0x1D79B, UNICODE_NORM_QC_NO}, + {0x1D79C, UNICODE_NORM_QC_NO}, + {0x1D79D, UNICODE_NORM_QC_NO}, + {0x1D79E, UNICODE_NORM_QC_NO}, + {0x1D79F, UNICODE_NORM_QC_NO}, + {0x1D7A0, UNICODE_NORM_QC_NO}, + {0x1D7A1, UNICODE_NORM_QC_NO}, + {0x1D7A2, UNICODE_NORM_QC_NO}, + {0x1D7A3, UNICODE_NORM_QC_NO}, + {0x1D7A4, UNICODE_NORM_QC_NO}, + {0x1D7A5, UNICODE_NORM_QC_NO}, + {0x1D7A6, UNICODE_NORM_QC_NO}, + {0x1D7A7, UNICODE_NORM_QC_NO}, + {0x1D7A8, UNICODE_NORM_QC_NO}, + {0x1D7A9, UNICODE_NORM_QC_NO}, + {0x1D7AA, UNICODE_NORM_QC_NO}, + {0x1D7AB, UNICODE_NORM_QC_NO}, + {0x1D7AC, UNICODE_NORM_QC_NO}, + {0x1D7AD, UNICODE_NORM_QC_NO}, + {0x1D7AE, UNICODE_NORM_QC_NO}, + {0x1D7AF, UNICODE_NORM_QC_NO}, + {0x1D7B0, UNICODE_NORM_QC_NO}, + {0x1D7B1, UNICODE_NORM_QC_NO}, + {0x1D7B2, UNICODE_NORM_QC_NO}, + {0x1D7B3, UNICODE_NORM_QC_NO}, + {0x1D7B4, UNICODE_NORM_QC_NO}, + {0x1D7B5, UNICODE_NORM_QC_NO}, + {0x1D7B6, UNICODE_NORM_QC_NO}, + {0x1D7B7, UNICODE_NORM_QC_NO}, + {0x1D7B8, UNICODE_NORM_QC_NO}, + {0x1D7B9, UNICODE_NORM_QC_NO}, + {0x1D7BA, UNICODE_NORM_QC_NO}, + {0x1D7BB, UNICODE_NORM_QC_NO}, + {0x1D7BC, UNICODE_NORM_QC_NO}, + {0x1D7BD, UNICODE_NORM_QC_NO}, + {0x1D7BE, UNICODE_NORM_QC_NO}, + {0x1D7BF, UNICODE_NORM_QC_NO}, + {0x1D7C0, UNICODE_NORM_QC_NO}, + {0x1D7C1, UNICODE_NORM_QC_NO}, + {0x1D7C2, UNICODE_NORM_QC_NO}, + {0x1D7C3, UNICODE_NORM_QC_NO}, + {0x1D7C4, UNICODE_NORM_QC_NO}, + {0x1D7C5, UNICODE_NORM_QC_NO}, + {0x1D7C6, UNICODE_NORM_QC_NO}, + {0x1D7C7, UNICODE_NORM_QC_NO}, + {0x1D7C8, UNICODE_NORM_QC_NO}, + {0x1D7C9, UNICODE_NORM_QC_NO}, + {0x1D7CA, UNICODE_NORM_QC_NO}, + {0x1D7CB, UNICODE_NORM_QC_NO}, + {0x1D7CE, UNICODE_NORM_QC_NO}, + {0x1D7CF, UNICODE_NORM_QC_NO}, + {0x1D7D0, UNICODE_NORM_QC_NO}, + {0x1D7D1, UNICODE_NORM_QC_NO}, + {0x1D7D2, UNICODE_NORM_QC_NO}, + {0x1D7D3, UNICODE_NORM_QC_NO}, + {0x1D7D4, UNICODE_NORM_QC_NO}, + {0x1D7D5, UNICODE_NORM_QC_NO}, + {0x1D7D6, UNICODE_NORM_QC_NO}, + {0x1D7D7, UNICODE_NORM_QC_NO}, + {0x1D7D8, UNICODE_NORM_QC_NO}, + {0x1D7D9, UNICODE_NORM_QC_NO}, + {0x1D7DA, UNICODE_NORM_QC_NO}, + {0x1D7DB, UNICODE_NORM_QC_NO}, + {0x1D7DC, UNICODE_NORM_QC_NO}, + {0x1D7DD, UNICODE_NORM_QC_NO}, + {0x1D7DE, UNICODE_NORM_QC_NO}, + {0x1D7DF, UNICODE_NORM_QC_NO}, + {0x1D7E0, UNICODE_NORM_QC_NO}, + {0x1D7E1, UNICODE_NORM_QC_NO}, + {0x1D7E2, UNICODE_NORM_QC_NO}, + {0x1D7E3, UNICODE_NORM_QC_NO}, + {0x1D7E4, UNICODE_NORM_QC_NO}, + {0x1D7E5, UNICODE_NORM_QC_NO}, + {0x1D7E6, UNICODE_NORM_QC_NO}, + {0x1D7E7, UNICODE_NORM_QC_NO}, + {0x1D7E8, UNICODE_NORM_QC_NO}, + {0x1D7E9, UNICODE_NORM_QC_NO}, + {0x1D7EA, UNICODE_NORM_QC_NO}, + {0x1D7EB, UNICODE_NORM_QC_NO}, + {0x1D7EC, UNICODE_NORM_QC_NO}, + {0x1D7ED, UNICODE_NORM_QC_NO}, + {0x1D7EE, UNICODE_NORM_QC_NO}, + {0x1D7EF, UNICODE_NORM_QC_NO}, + {0x1D7F0, UNICODE_NORM_QC_NO}, + {0x1D7F1, UNICODE_NORM_QC_NO}, + {0x1D7F2, UNICODE_NORM_QC_NO}, + {0x1D7F3, UNICODE_NORM_QC_NO}, + {0x1D7F4, UNICODE_NORM_QC_NO}, + {0x1D7F5, UNICODE_NORM_QC_NO}, + {0x1D7F6, UNICODE_NORM_QC_NO}, + {0x1D7F7, UNICODE_NORM_QC_NO}, + {0x1D7F8, UNICODE_NORM_QC_NO}, + {0x1D7F9, UNICODE_NORM_QC_NO}, + {0x1D7FA, UNICODE_NORM_QC_NO}, + {0x1D7FB, UNICODE_NORM_QC_NO}, + {0x1D7FC, UNICODE_NORM_QC_NO}, + {0x1D7FD, UNICODE_NORM_QC_NO}, + {0x1D7FE, UNICODE_NORM_QC_NO}, + {0x1D7FF, UNICODE_NORM_QC_NO}, + {0x1EE00, UNICODE_NORM_QC_NO}, + {0x1EE01, UNICODE_NORM_QC_NO}, + {0x1EE02, UNICODE_NORM_QC_NO}, + {0x1EE03, UNICODE_NORM_QC_NO}, + {0x1EE05, UNICODE_NORM_QC_NO}, + {0x1EE06, UNICODE_NORM_QC_NO}, + {0x1EE07, UNICODE_NORM_QC_NO}, + {0x1EE08, UNICODE_NORM_QC_NO}, + {0x1EE09, UNICODE_NORM_QC_NO}, + {0x1EE0A, UNICODE_NORM_QC_NO}, + {0x1EE0B, UNICODE_NORM_QC_NO}, + {0x1EE0C, UNICODE_NORM_QC_NO}, + {0x1EE0D, UNICODE_NORM_QC_NO}, + {0x1EE0E, UNICODE_NORM_QC_NO}, + {0x1EE0F, UNICODE_NORM_QC_NO}, + {0x1EE10, UNICODE_NORM_QC_NO}, + {0x1EE11, UNICODE_NORM_QC_NO}, + {0x1EE12, UNICODE_NORM_QC_NO}, + {0x1EE13, UNICODE_NORM_QC_NO}, + {0x1EE14, UNICODE_NORM_QC_NO}, + {0x1EE15, UNICODE_NORM_QC_NO}, + {0x1EE16, UNICODE_NORM_QC_NO}, + {0x1EE17, UNICODE_NORM_QC_NO}, + {0x1EE18, UNICODE_NORM_QC_NO}, + {0x1EE19, UNICODE_NORM_QC_NO}, + {0x1EE1A, UNICODE_NORM_QC_NO}, + {0x1EE1B, UNICODE_NORM_QC_NO}, + {0x1EE1C, UNICODE_NORM_QC_NO}, + {0x1EE1D, UNICODE_NORM_QC_NO}, + {0x1EE1E, UNICODE_NORM_QC_NO}, + {0x1EE1F, UNICODE_NORM_QC_NO}, + {0x1EE21, UNICODE_NORM_QC_NO}, + {0x1EE22, UNICODE_NORM_QC_NO}, + {0x1EE24, UNICODE_NORM_QC_NO}, + {0x1EE27, UNICODE_NORM_QC_NO}, + {0x1EE29, UNICODE_NORM_QC_NO}, + {0x1EE2A, UNICODE_NORM_QC_NO}, + {0x1EE2B, UNICODE_NORM_QC_NO}, + {0x1EE2C, UNICODE_NORM_QC_NO}, + {0x1EE2D, UNICODE_NORM_QC_NO}, + {0x1EE2E, UNICODE_NORM_QC_NO}, + {0x1EE2F, UNICODE_NORM_QC_NO}, + {0x1EE30, UNICODE_NORM_QC_NO}, + {0x1EE31, UNICODE_NORM_QC_NO}, + {0x1EE32, UNICODE_NORM_QC_NO}, + {0x1EE34, UNICODE_NORM_QC_NO}, + {0x1EE35, UNICODE_NORM_QC_NO}, + {0x1EE36, UNICODE_NORM_QC_NO}, + {0x1EE37, UNICODE_NORM_QC_NO}, + {0x1EE39, UNICODE_NORM_QC_NO}, + {0x1EE3B, UNICODE_NORM_QC_NO}, + {0x1EE42, UNICODE_NORM_QC_NO}, + {0x1EE47, UNICODE_NORM_QC_NO}, + {0x1EE49, UNICODE_NORM_QC_NO}, + {0x1EE4B, UNICODE_NORM_QC_NO}, + {0x1EE4D, UNICODE_NORM_QC_NO}, + {0x1EE4E, UNICODE_NORM_QC_NO}, + {0x1EE4F, UNICODE_NORM_QC_NO}, + {0x1EE51, UNICODE_NORM_QC_NO}, + {0x1EE52, UNICODE_NORM_QC_NO}, + {0x1EE54, UNICODE_NORM_QC_NO}, + {0x1EE57, UNICODE_NORM_QC_NO}, + {0x1EE59, UNICODE_NORM_QC_NO}, + {0x1EE5B, UNICODE_NORM_QC_NO}, + {0x1EE5D, UNICODE_NORM_QC_NO}, + {0x1EE5F, UNICODE_NORM_QC_NO}, + {0x1EE61, UNICODE_NORM_QC_NO}, + {0x1EE62, UNICODE_NORM_QC_NO}, + {0x1EE64, UNICODE_NORM_QC_NO}, + {0x1EE67, UNICODE_NORM_QC_NO}, + {0x1EE68, UNICODE_NORM_QC_NO}, + {0x1EE69, UNICODE_NORM_QC_NO}, + {0x1EE6A, UNICODE_NORM_QC_NO}, + {0x1EE6C, UNICODE_NORM_QC_NO}, + {0x1EE6D, UNICODE_NORM_QC_NO}, + {0x1EE6E, UNICODE_NORM_QC_NO}, + {0x1EE6F, UNICODE_NORM_QC_NO}, + {0x1EE70, UNICODE_NORM_QC_NO}, + {0x1EE71, UNICODE_NORM_QC_NO}, + {0x1EE72, UNICODE_NORM_QC_NO}, + {0x1EE74, UNICODE_NORM_QC_NO}, + {0x1EE75, UNICODE_NORM_QC_NO}, + {0x1EE76, UNICODE_NORM_QC_NO}, + {0x1EE77, UNICODE_NORM_QC_NO}, + {0x1EE79, UNICODE_NORM_QC_NO}, + {0x1EE7A, UNICODE_NORM_QC_NO}, + {0x1EE7B, UNICODE_NORM_QC_NO}, + {0x1EE7C, UNICODE_NORM_QC_NO}, + {0x1EE7E, UNICODE_NORM_QC_NO}, + {0x1EE80, UNICODE_NORM_QC_NO}, + {0x1EE81, UNICODE_NORM_QC_NO}, + {0x1EE82, UNICODE_NORM_QC_NO}, + {0x1EE83, UNICODE_NORM_QC_NO}, + {0x1EE84, UNICODE_NORM_QC_NO}, + {0x1EE85, UNICODE_NORM_QC_NO}, + {0x1EE86, UNICODE_NORM_QC_NO}, + {0x1EE87, UNICODE_NORM_QC_NO}, + {0x1EE88, UNICODE_NORM_QC_NO}, + {0x1EE89, UNICODE_NORM_QC_NO}, + {0x1EE8B, UNICODE_NORM_QC_NO}, + {0x1EE8C, UNICODE_NORM_QC_NO}, + {0x1EE8D, UNICODE_NORM_QC_NO}, + {0x1EE8E, UNICODE_NORM_QC_NO}, + {0x1EE8F, UNICODE_NORM_QC_NO}, + {0x1EE90, UNICODE_NORM_QC_NO}, + {0x1EE91, UNICODE_NORM_QC_NO}, + {0x1EE92, UNICODE_NORM_QC_NO}, + {0x1EE93, UNICODE_NORM_QC_NO}, + {0x1EE94, UNICODE_NORM_QC_NO}, + {0x1EE95, UNICODE_NORM_QC_NO}, + {0x1EE96, UNICODE_NORM_QC_NO}, + {0x1EE97, UNICODE_NORM_QC_NO}, + {0x1EE98, UNICODE_NORM_QC_NO}, + {0x1EE99, UNICODE_NORM_QC_NO}, + {0x1EE9A, UNICODE_NORM_QC_NO}, + {0x1EE9B, UNICODE_NORM_QC_NO}, + {0x1EEA1, UNICODE_NORM_QC_NO}, + {0x1EEA2, UNICODE_NORM_QC_NO}, + {0x1EEA3, UNICODE_NORM_QC_NO}, + {0x1EEA5, UNICODE_NORM_QC_NO}, + {0x1EEA6, UNICODE_NORM_QC_NO}, + {0x1EEA7, UNICODE_NORM_QC_NO}, + {0x1EEA8, UNICODE_NORM_QC_NO}, + {0x1EEA9, UNICODE_NORM_QC_NO}, + {0x1EEAB, UNICODE_NORM_QC_NO}, + {0x1EEAC, UNICODE_NORM_QC_NO}, + {0x1EEAD, UNICODE_NORM_QC_NO}, + {0x1EEAE, UNICODE_NORM_QC_NO}, + {0x1EEAF, UNICODE_NORM_QC_NO}, + {0x1EEB0, UNICODE_NORM_QC_NO}, + {0x1EEB1, UNICODE_NORM_QC_NO}, + {0x1EEB2, UNICODE_NORM_QC_NO}, + {0x1EEB3, UNICODE_NORM_QC_NO}, + {0x1EEB4, UNICODE_NORM_QC_NO}, + {0x1EEB5, UNICODE_NORM_QC_NO}, + {0x1EEB6, UNICODE_NORM_QC_NO}, + {0x1EEB7, UNICODE_NORM_QC_NO}, + {0x1EEB8, UNICODE_NORM_QC_NO}, + {0x1EEB9, UNICODE_NORM_QC_NO}, + {0x1EEBA, UNICODE_NORM_QC_NO}, + {0x1EEBB, UNICODE_NORM_QC_NO}, + {0x1F100, UNICODE_NORM_QC_NO}, + {0x1F101, UNICODE_NORM_QC_NO}, + {0x1F102, UNICODE_NORM_QC_NO}, + {0x1F103, UNICODE_NORM_QC_NO}, + {0x1F104, UNICODE_NORM_QC_NO}, + {0x1F105, UNICODE_NORM_QC_NO}, + {0x1F106, UNICODE_NORM_QC_NO}, + {0x1F107, UNICODE_NORM_QC_NO}, + {0x1F108, UNICODE_NORM_QC_NO}, + {0x1F109, UNICODE_NORM_QC_NO}, + {0x1F10A, UNICODE_NORM_QC_NO}, + {0x1F110, UNICODE_NORM_QC_NO}, + {0x1F111, UNICODE_NORM_QC_NO}, + {0x1F112, UNICODE_NORM_QC_NO}, + {0x1F113, UNICODE_NORM_QC_NO}, + {0x1F114, UNICODE_NORM_QC_NO}, + {0x1F115, UNICODE_NORM_QC_NO}, + {0x1F116, UNICODE_NORM_QC_NO}, + {0x1F117, UNICODE_NORM_QC_NO}, + {0x1F118, UNICODE_NORM_QC_NO}, + {0x1F119, UNICODE_NORM_QC_NO}, + {0x1F11A, UNICODE_NORM_QC_NO}, + {0x1F11B, UNICODE_NORM_QC_NO}, + {0x1F11C, UNICODE_NORM_QC_NO}, + {0x1F11D, UNICODE_NORM_QC_NO}, + {0x1F11E, UNICODE_NORM_QC_NO}, + {0x1F11F, UNICODE_NORM_QC_NO}, + {0x1F120, UNICODE_NORM_QC_NO}, + {0x1F121, UNICODE_NORM_QC_NO}, + {0x1F122, UNICODE_NORM_QC_NO}, + {0x1F123, UNICODE_NORM_QC_NO}, + {0x1F124, UNICODE_NORM_QC_NO}, + {0x1F125, UNICODE_NORM_QC_NO}, + {0x1F126, UNICODE_NORM_QC_NO}, + {0x1F127, UNICODE_NORM_QC_NO}, + {0x1F128, UNICODE_NORM_QC_NO}, + {0x1F129, UNICODE_NORM_QC_NO}, + {0x1F12A, UNICODE_NORM_QC_NO}, + {0x1F12B, UNICODE_NORM_QC_NO}, + {0x1F12C, UNICODE_NORM_QC_NO}, + {0x1F12D, UNICODE_NORM_QC_NO}, + {0x1F12E, UNICODE_NORM_QC_NO}, + {0x1F130, UNICODE_NORM_QC_NO}, + {0x1F131, UNICODE_NORM_QC_NO}, + {0x1F132, UNICODE_NORM_QC_NO}, + {0x1F133, UNICODE_NORM_QC_NO}, + {0x1F134, UNICODE_NORM_QC_NO}, + {0x1F135, UNICODE_NORM_QC_NO}, + {0x1F136, UNICODE_NORM_QC_NO}, + {0x1F137, UNICODE_NORM_QC_NO}, + {0x1F138, UNICODE_NORM_QC_NO}, + {0x1F139, UNICODE_NORM_QC_NO}, + {0x1F13A, UNICODE_NORM_QC_NO}, + {0x1F13B, UNICODE_NORM_QC_NO}, + {0x1F13C, UNICODE_NORM_QC_NO}, + {0x1F13D, UNICODE_NORM_QC_NO}, + {0x1F13E, UNICODE_NORM_QC_NO}, + {0x1F13F, UNICODE_NORM_QC_NO}, + {0x1F140, UNICODE_NORM_QC_NO}, + {0x1F141, UNICODE_NORM_QC_NO}, + {0x1F142, UNICODE_NORM_QC_NO}, + {0x1F143, UNICODE_NORM_QC_NO}, + {0x1F144, UNICODE_NORM_QC_NO}, + {0x1F145, UNICODE_NORM_QC_NO}, + {0x1F146, UNICODE_NORM_QC_NO}, + {0x1F147, UNICODE_NORM_QC_NO}, + {0x1F148, UNICODE_NORM_QC_NO}, + {0x1F149, UNICODE_NORM_QC_NO}, + {0x1F14A, UNICODE_NORM_QC_NO}, + {0x1F14B, UNICODE_NORM_QC_NO}, + {0x1F14C, UNICODE_NORM_QC_NO}, + {0x1F14D, UNICODE_NORM_QC_NO}, + {0x1F14E, UNICODE_NORM_QC_NO}, + {0x1F14F, UNICODE_NORM_QC_NO}, + {0x1F16A, UNICODE_NORM_QC_NO}, + {0x1F16B, UNICODE_NORM_QC_NO}, + {0x1F16C, UNICODE_NORM_QC_NO}, + {0x1F190, UNICODE_NORM_QC_NO}, + {0x1F200, UNICODE_NORM_QC_NO}, + {0x1F201, UNICODE_NORM_QC_NO}, + {0x1F202, UNICODE_NORM_QC_NO}, + {0x1F210, UNICODE_NORM_QC_NO}, + {0x1F211, UNICODE_NORM_QC_NO}, + {0x1F212, UNICODE_NORM_QC_NO}, + {0x1F213, UNICODE_NORM_QC_NO}, + {0x1F214, UNICODE_NORM_QC_NO}, + {0x1F215, UNICODE_NORM_QC_NO}, + {0x1F216, UNICODE_NORM_QC_NO}, + {0x1F217, UNICODE_NORM_QC_NO}, + {0x1F218, UNICODE_NORM_QC_NO}, + {0x1F219, UNICODE_NORM_QC_NO}, + {0x1F21A, UNICODE_NORM_QC_NO}, + {0x1F21B, UNICODE_NORM_QC_NO}, + {0x1F21C, UNICODE_NORM_QC_NO}, + {0x1F21D, UNICODE_NORM_QC_NO}, + {0x1F21E, UNICODE_NORM_QC_NO}, + {0x1F21F, UNICODE_NORM_QC_NO}, + {0x1F220, UNICODE_NORM_QC_NO}, + {0x1F221, UNICODE_NORM_QC_NO}, + {0x1F222, UNICODE_NORM_QC_NO}, + {0x1F223, UNICODE_NORM_QC_NO}, + {0x1F224, UNICODE_NORM_QC_NO}, + {0x1F225, UNICODE_NORM_QC_NO}, + {0x1F226, UNICODE_NORM_QC_NO}, + {0x1F227, UNICODE_NORM_QC_NO}, + {0x1F228, UNICODE_NORM_QC_NO}, + {0x1F229, UNICODE_NORM_QC_NO}, + {0x1F22A, UNICODE_NORM_QC_NO}, + {0x1F22B, UNICODE_NORM_QC_NO}, + {0x1F22C, UNICODE_NORM_QC_NO}, + {0x1F22D, UNICODE_NORM_QC_NO}, + {0x1F22E, UNICODE_NORM_QC_NO}, + {0x1F22F, UNICODE_NORM_QC_NO}, + {0x1F230, UNICODE_NORM_QC_NO}, + {0x1F231, UNICODE_NORM_QC_NO}, + {0x1F232, UNICODE_NORM_QC_NO}, + {0x1F233, UNICODE_NORM_QC_NO}, + {0x1F234, UNICODE_NORM_QC_NO}, + {0x1F235, UNICODE_NORM_QC_NO}, + {0x1F236, UNICODE_NORM_QC_NO}, + {0x1F237, UNICODE_NORM_QC_NO}, + {0x1F238, UNICODE_NORM_QC_NO}, + {0x1F239, UNICODE_NORM_QC_NO}, + {0x1F23A, UNICODE_NORM_QC_NO}, + {0x1F23B, UNICODE_NORM_QC_NO}, + {0x1F240, UNICODE_NORM_QC_NO}, + {0x1F241, UNICODE_NORM_QC_NO}, + {0x1F242, UNICODE_NORM_QC_NO}, + {0x1F243, UNICODE_NORM_QC_NO}, + {0x1F244, UNICODE_NORM_QC_NO}, + {0x1F245, UNICODE_NORM_QC_NO}, + {0x1F246, UNICODE_NORM_QC_NO}, + {0x1F247, UNICODE_NORM_QC_NO}, + {0x1F248, UNICODE_NORM_QC_NO}, + {0x1F250, UNICODE_NORM_QC_NO}, + {0x1F251, UNICODE_NORM_QC_NO}, + {0x1FBF0, UNICODE_NORM_QC_NO}, + {0x1FBF1, UNICODE_NORM_QC_NO}, + {0x1FBF2, UNICODE_NORM_QC_NO}, + {0x1FBF3, UNICODE_NORM_QC_NO}, + {0x1FBF4, UNICODE_NORM_QC_NO}, + {0x1FBF5, UNICODE_NORM_QC_NO}, + {0x1FBF6, UNICODE_NORM_QC_NO}, + {0x1FBF7, UNICODE_NORM_QC_NO}, + {0x1FBF8, UNICODE_NORM_QC_NO}, + {0x1FBF9, UNICODE_NORM_QC_NO}, + {0x2F800, UNICODE_NORM_QC_NO}, + {0x2F801, UNICODE_NORM_QC_NO}, + {0x2F802, UNICODE_NORM_QC_NO}, + {0x2F803, UNICODE_NORM_QC_NO}, + {0x2F804, UNICODE_NORM_QC_NO}, + {0x2F805, UNICODE_NORM_QC_NO}, + {0x2F806, UNICODE_NORM_QC_NO}, + {0x2F807, UNICODE_NORM_QC_NO}, + {0x2F808, UNICODE_NORM_QC_NO}, + {0x2F809, UNICODE_NORM_QC_NO}, + {0x2F80A, UNICODE_NORM_QC_NO}, + {0x2F80B, UNICODE_NORM_QC_NO}, + {0x2F80C, UNICODE_NORM_QC_NO}, + {0x2F80D, UNICODE_NORM_QC_NO}, + {0x2F80E, UNICODE_NORM_QC_NO}, + {0x2F80F, UNICODE_NORM_QC_NO}, + {0x2F810, UNICODE_NORM_QC_NO}, + {0x2F811, UNICODE_NORM_QC_NO}, + {0x2F812, UNICODE_NORM_QC_NO}, + {0x2F813, UNICODE_NORM_QC_NO}, + {0x2F814, UNICODE_NORM_QC_NO}, + {0x2F815, UNICODE_NORM_QC_NO}, + {0x2F816, UNICODE_NORM_QC_NO}, + {0x2F817, UNICODE_NORM_QC_NO}, + {0x2F818, UNICODE_NORM_QC_NO}, + {0x2F819, UNICODE_NORM_QC_NO}, + {0x2F81A, UNICODE_NORM_QC_NO}, + {0x2F81B, UNICODE_NORM_QC_NO}, + {0x2F81C, UNICODE_NORM_QC_NO}, + {0x2F81D, UNICODE_NORM_QC_NO}, + {0x2F81E, UNICODE_NORM_QC_NO}, + {0x2F81F, UNICODE_NORM_QC_NO}, + {0x2F820, UNICODE_NORM_QC_NO}, + {0x2F821, UNICODE_NORM_QC_NO}, + {0x2F822, UNICODE_NORM_QC_NO}, + {0x2F823, UNICODE_NORM_QC_NO}, + {0x2F824, UNICODE_NORM_QC_NO}, + {0x2F825, UNICODE_NORM_QC_NO}, + {0x2F826, UNICODE_NORM_QC_NO}, + {0x2F827, UNICODE_NORM_QC_NO}, + {0x2F828, UNICODE_NORM_QC_NO}, + {0x2F829, UNICODE_NORM_QC_NO}, + {0x2F82A, UNICODE_NORM_QC_NO}, + {0x2F82B, UNICODE_NORM_QC_NO}, + {0x2F82C, UNICODE_NORM_QC_NO}, + {0x2F82D, UNICODE_NORM_QC_NO}, + {0x2F82E, UNICODE_NORM_QC_NO}, + {0x2F82F, UNICODE_NORM_QC_NO}, + {0x2F830, UNICODE_NORM_QC_NO}, + {0x2F831, UNICODE_NORM_QC_NO}, + {0x2F832, UNICODE_NORM_QC_NO}, + {0x2F833, UNICODE_NORM_QC_NO}, + {0x2F834, UNICODE_NORM_QC_NO}, + {0x2F835, UNICODE_NORM_QC_NO}, + {0x2F836, UNICODE_NORM_QC_NO}, + {0x2F837, UNICODE_NORM_QC_NO}, + {0x2F838, UNICODE_NORM_QC_NO}, + {0x2F839, UNICODE_NORM_QC_NO}, + {0x2F83A, UNICODE_NORM_QC_NO}, + {0x2F83B, UNICODE_NORM_QC_NO}, + {0x2F83C, UNICODE_NORM_QC_NO}, + {0x2F83D, UNICODE_NORM_QC_NO}, + {0x2F83E, UNICODE_NORM_QC_NO}, + {0x2F83F, UNICODE_NORM_QC_NO}, + {0x2F840, UNICODE_NORM_QC_NO}, + {0x2F841, UNICODE_NORM_QC_NO}, + {0x2F842, UNICODE_NORM_QC_NO}, + {0x2F843, UNICODE_NORM_QC_NO}, + {0x2F844, UNICODE_NORM_QC_NO}, + {0x2F845, UNICODE_NORM_QC_NO}, + {0x2F846, UNICODE_NORM_QC_NO}, + {0x2F847, UNICODE_NORM_QC_NO}, + {0x2F848, UNICODE_NORM_QC_NO}, + {0x2F849, UNICODE_NORM_QC_NO}, + {0x2F84A, UNICODE_NORM_QC_NO}, + {0x2F84B, UNICODE_NORM_QC_NO}, + {0x2F84C, UNICODE_NORM_QC_NO}, + {0x2F84D, UNICODE_NORM_QC_NO}, + {0x2F84E, UNICODE_NORM_QC_NO}, + {0x2F84F, UNICODE_NORM_QC_NO}, + {0x2F850, UNICODE_NORM_QC_NO}, + {0x2F851, UNICODE_NORM_QC_NO}, + {0x2F852, UNICODE_NORM_QC_NO}, + {0x2F853, UNICODE_NORM_QC_NO}, + {0x2F854, UNICODE_NORM_QC_NO}, + {0x2F855, UNICODE_NORM_QC_NO}, + {0x2F856, UNICODE_NORM_QC_NO}, + {0x2F857, UNICODE_NORM_QC_NO}, + {0x2F858, UNICODE_NORM_QC_NO}, + {0x2F859, UNICODE_NORM_QC_NO}, + {0x2F85A, UNICODE_NORM_QC_NO}, + {0x2F85B, UNICODE_NORM_QC_NO}, + {0x2F85C, UNICODE_NORM_QC_NO}, + {0x2F85D, UNICODE_NORM_QC_NO}, + {0x2F85E, UNICODE_NORM_QC_NO}, + {0x2F85F, UNICODE_NORM_QC_NO}, + {0x2F860, UNICODE_NORM_QC_NO}, + {0x2F861, UNICODE_NORM_QC_NO}, + {0x2F862, UNICODE_NORM_QC_NO}, + {0x2F863, UNICODE_NORM_QC_NO}, + {0x2F864, UNICODE_NORM_QC_NO}, + {0x2F865, UNICODE_NORM_QC_NO}, + {0x2F866, UNICODE_NORM_QC_NO}, + {0x2F867, UNICODE_NORM_QC_NO}, + {0x2F868, UNICODE_NORM_QC_NO}, + {0x2F869, UNICODE_NORM_QC_NO}, + {0x2F86A, UNICODE_NORM_QC_NO}, + {0x2F86B, UNICODE_NORM_QC_NO}, + {0x2F86C, UNICODE_NORM_QC_NO}, + {0x2F86D, UNICODE_NORM_QC_NO}, + {0x2F86E, UNICODE_NORM_QC_NO}, + {0x2F86F, UNICODE_NORM_QC_NO}, + {0x2F870, UNICODE_NORM_QC_NO}, + {0x2F871, UNICODE_NORM_QC_NO}, + {0x2F872, UNICODE_NORM_QC_NO}, + {0x2F873, UNICODE_NORM_QC_NO}, + {0x2F874, UNICODE_NORM_QC_NO}, + {0x2F875, UNICODE_NORM_QC_NO}, + {0x2F876, UNICODE_NORM_QC_NO}, + {0x2F877, UNICODE_NORM_QC_NO}, + {0x2F878, UNICODE_NORM_QC_NO}, + {0x2F879, UNICODE_NORM_QC_NO}, + {0x2F87A, UNICODE_NORM_QC_NO}, + {0x2F87B, UNICODE_NORM_QC_NO}, + {0x2F87C, UNICODE_NORM_QC_NO}, + {0x2F87D, UNICODE_NORM_QC_NO}, + {0x2F87E, UNICODE_NORM_QC_NO}, + {0x2F87F, UNICODE_NORM_QC_NO}, + {0x2F880, UNICODE_NORM_QC_NO}, + {0x2F881, UNICODE_NORM_QC_NO}, + {0x2F882, UNICODE_NORM_QC_NO}, + {0x2F883, UNICODE_NORM_QC_NO}, + {0x2F884, UNICODE_NORM_QC_NO}, + {0x2F885, UNICODE_NORM_QC_NO}, + {0x2F886, UNICODE_NORM_QC_NO}, + {0x2F887, UNICODE_NORM_QC_NO}, + {0x2F888, UNICODE_NORM_QC_NO}, + {0x2F889, UNICODE_NORM_QC_NO}, + {0x2F88A, UNICODE_NORM_QC_NO}, + {0x2F88B, UNICODE_NORM_QC_NO}, + {0x2F88C, UNICODE_NORM_QC_NO}, + {0x2F88D, UNICODE_NORM_QC_NO}, + {0x2F88E, UNICODE_NORM_QC_NO}, + {0x2F88F, UNICODE_NORM_QC_NO}, + {0x2F890, UNICODE_NORM_QC_NO}, + {0x2F891, UNICODE_NORM_QC_NO}, + {0x2F892, UNICODE_NORM_QC_NO}, + {0x2F893, UNICODE_NORM_QC_NO}, + {0x2F894, UNICODE_NORM_QC_NO}, + {0x2F895, UNICODE_NORM_QC_NO}, + {0x2F896, UNICODE_NORM_QC_NO}, + {0x2F897, UNICODE_NORM_QC_NO}, + {0x2F898, UNICODE_NORM_QC_NO}, + {0x2F899, UNICODE_NORM_QC_NO}, + {0x2F89A, UNICODE_NORM_QC_NO}, + {0x2F89B, UNICODE_NORM_QC_NO}, + {0x2F89C, UNICODE_NORM_QC_NO}, + {0x2F89D, UNICODE_NORM_QC_NO}, + {0x2F89E, UNICODE_NORM_QC_NO}, + {0x2F89F, UNICODE_NORM_QC_NO}, + {0x2F8A0, UNICODE_NORM_QC_NO}, + {0x2F8A1, UNICODE_NORM_QC_NO}, + {0x2F8A2, UNICODE_NORM_QC_NO}, + {0x2F8A3, UNICODE_NORM_QC_NO}, + {0x2F8A4, UNICODE_NORM_QC_NO}, + {0x2F8A5, UNICODE_NORM_QC_NO}, + {0x2F8A6, UNICODE_NORM_QC_NO}, + {0x2F8A7, UNICODE_NORM_QC_NO}, + {0x2F8A8, UNICODE_NORM_QC_NO}, + {0x2F8A9, UNICODE_NORM_QC_NO}, + {0x2F8AA, UNICODE_NORM_QC_NO}, + {0x2F8AB, UNICODE_NORM_QC_NO}, + {0x2F8AC, UNICODE_NORM_QC_NO}, + {0x2F8AD, UNICODE_NORM_QC_NO}, + {0x2F8AE, UNICODE_NORM_QC_NO}, + {0x2F8AF, UNICODE_NORM_QC_NO}, + {0x2F8B0, UNICODE_NORM_QC_NO}, + {0x2F8B1, UNICODE_NORM_QC_NO}, + {0x2F8B2, UNICODE_NORM_QC_NO}, + {0x2F8B3, UNICODE_NORM_QC_NO}, + {0x2F8B4, UNICODE_NORM_QC_NO}, + {0x2F8B5, UNICODE_NORM_QC_NO}, + {0x2F8B6, UNICODE_NORM_QC_NO}, + {0x2F8B7, UNICODE_NORM_QC_NO}, + {0x2F8B8, UNICODE_NORM_QC_NO}, + {0x2F8B9, UNICODE_NORM_QC_NO}, + {0x2F8BA, UNICODE_NORM_QC_NO}, + {0x2F8BB, UNICODE_NORM_QC_NO}, + {0x2F8BC, UNICODE_NORM_QC_NO}, + {0x2F8BD, UNICODE_NORM_QC_NO}, + {0x2F8BE, UNICODE_NORM_QC_NO}, + {0x2F8BF, UNICODE_NORM_QC_NO}, + {0x2F8C0, UNICODE_NORM_QC_NO}, + {0x2F8C1, UNICODE_NORM_QC_NO}, + {0x2F8C2, UNICODE_NORM_QC_NO}, + {0x2F8C3, UNICODE_NORM_QC_NO}, + {0x2F8C4, UNICODE_NORM_QC_NO}, + {0x2F8C5, UNICODE_NORM_QC_NO}, + {0x2F8C6, UNICODE_NORM_QC_NO}, + {0x2F8C7, UNICODE_NORM_QC_NO}, + {0x2F8C8, UNICODE_NORM_QC_NO}, + {0x2F8C9, UNICODE_NORM_QC_NO}, + {0x2F8CA, UNICODE_NORM_QC_NO}, + {0x2F8CB, UNICODE_NORM_QC_NO}, + {0x2F8CC, UNICODE_NORM_QC_NO}, + {0x2F8CD, UNICODE_NORM_QC_NO}, + {0x2F8CE, UNICODE_NORM_QC_NO}, + {0x2F8CF, UNICODE_NORM_QC_NO}, + {0x2F8D0, UNICODE_NORM_QC_NO}, + {0x2F8D1, UNICODE_NORM_QC_NO}, + {0x2F8D2, UNICODE_NORM_QC_NO}, + {0x2F8D3, UNICODE_NORM_QC_NO}, + {0x2F8D4, UNICODE_NORM_QC_NO}, + {0x2F8D5, UNICODE_NORM_QC_NO}, + {0x2F8D6, UNICODE_NORM_QC_NO}, + {0x2F8D7, UNICODE_NORM_QC_NO}, + {0x2F8D8, UNICODE_NORM_QC_NO}, + {0x2F8D9, UNICODE_NORM_QC_NO}, + {0x2F8DA, UNICODE_NORM_QC_NO}, + {0x2F8DB, UNICODE_NORM_QC_NO}, + {0x2F8DC, UNICODE_NORM_QC_NO}, + {0x2F8DD, UNICODE_NORM_QC_NO}, + {0x2F8DE, UNICODE_NORM_QC_NO}, + {0x2F8DF, UNICODE_NORM_QC_NO}, + {0x2F8E0, UNICODE_NORM_QC_NO}, + {0x2F8E1, UNICODE_NORM_QC_NO}, + {0x2F8E2, UNICODE_NORM_QC_NO}, + {0x2F8E3, UNICODE_NORM_QC_NO}, + {0x2F8E4, UNICODE_NORM_QC_NO}, + {0x2F8E5, UNICODE_NORM_QC_NO}, + {0x2F8E6, UNICODE_NORM_QC_NO}, + {0x2F8E7, UNICODE_NORM_QC_NO}, + {0x2F8E8, UNICODE_NORM_QC_NO}, + {0x2F8E9, UNICODE_NORM_QC_NO}, + {0x2F8EA, UNICODE_NORM_QC_NO}, + {0x2F8EB, UNICODE_NORM_QC_NO}, + {0x2F8EC, UNICODE_NORM_QC_NO}, + {0x2F8ED, UNICODE_NORM_QC_NO}, + {0x2F8EE, UNICODE_NORM_QC_NO}, + {0x2F8EF, UNICODE_NORM_QC_NO}, + {0x2F8F0, UNICODE_NORM_QC_NO}, + {0x2F8F1, UNICODE_NORM_QC_NO}, + {0x2F8F2, UNICODE_NORM_QC_NO}, + {0x2F8F3, UNICODE_NORM_QC_NO}, + {0x2F8F4, UNICODE_NORM_QC_NO}, + {0x2F8F5, UNICODE_NORM_QC_NO}, + {0x2F8F6, UNICODE_NORM_QC_NO}, + {0x2F8F7, UNICODE_NORM_QC_NO}, + {0x2F8F8, UNICODE_NORM_QC_NO}, + {0x2F8F9, UNICODE_NORM_QC_NO}, + {0x2F8FA, UNICODE_NORM_QC_NO}, + {0x2F8FB, UNICODE_NORM_QC_NO}, + {0x2F8FC, UNICODE_NORM_QC_NO}, + {0x2F8FD, UNICODE_NORM_QC_NO}, + {0x2F8FE, UNICODE_NORM_QC_NO}, + {0x2F8FF, UNICODE_NORM_QC_NO}, + {0x2F900, UNICODE_NORM_QC_NO}, + {0x2F901, UNICODE_NORM_QC_NO}, + {0x2F902, UNICODE_NORM_QC_NO}, + {0x2F903, UNICODE_NORM_QC_NO}, + {0x2F904, UNICODE_NORM_QC_NO}, + {0x2F905, UNICODE_NORM_QC_NO}, + {0x2F906, UNICODE_NORM_QC_NO}, + {0x2F907, UNICODE_NORM_QC_NO}, + {0x2F908, UNICODE_NORM_QC_NO}, + {0x2F909, UNICODE_NORM_QC_NO}, + {0x2F90A, UNICODE_NORM_QC_NO}, + {0x2F90B, UNICODE_NORM_QC_NO}, + {0x2F90C, UNICODE_NORM_QC_NO}, + {0x2F90D, UNICODE_NORM_QC_NO}, + {0x2F90E, UNICODE_NORM_QC_NO}, + {0x2F90F, UNICODE_NORM_QC_NO}, + {0x2F910, UNICODE_NORM_QC_NO}, + {0x2F911, UNICODE_NORM_QC_NO}, + {0x2F912, UNICODE_NORM_QC_NO}, + {0x2F913, UNICODE_NORM_QC_NO}, + {0x2F914, UNICODE_NORM_QC_NO}, + {0x2F915, UNICODE_NORM_QC_NO}, + {0x2F916, UNICODE_NORM_QC_NO}, + {0x2F917, UNICODE_NORM_QC_NO}, + {0x2F918, UNICODE_NORM_QC_NO}, + {0x2F919, UNICODE_NORM_QC_NO}, + {0x2F91A, UNICODE_NORM_QC_NO}, + {0x2F91B, UNICODE_NORM_QC_NO}, + {0x2F91C, UNICODE_NORM_QC_NO}, + {0x2F91D, UNICODE_NORM_QC_NO}, + {0x2F91E, UNICODE_NORM_QC_NO}, + {0x2F91F, UNICODE_NORM_QC_NO}, + {0x2F920, UNICODE_NORM_QC_NO}, + {0x2F921, UNICODE_NORM_QC_NO}, + {0x2F922, UNICODE_NORM_QC_NO}, + {0x2F923, UNICODE_NORM_QC_NO}, + {0x2F924, UNICODE_NORM_QC_NO}, + {0x2F925, UNICODE_NORM_QC_NO}, + {0x2F926, UNICODE_NORM_QC_NO}, + {0x2F927, UNICODE_NORM_QC_NO}, + {0x2F928, UNICODE_NORM_QC_NO}, + {0x2F929, UNICODE_NORM_QC_NO}, + {0x2F92A, UNICODE_NORM_QC_NO}, + {0x2F92B, UNICODE_NORM_QC_NO}, + {0x2F92C, UNICODE_NORM_QC_NO}, + {0x2F92D, UNICODE_NORM_QC_NO}, + {0x2F92E, UNICODE_NORM_QC_NO}, + {0x2F92F, UNICODE_NORM_QC_NO}, + {0x2F930, UNICODE_NORM_QC_NO}, + {0x2F931, UNICODE_NORM_QC_NO}, + {0x2F932, UNICODE_NORM_QC_NO}, + {0x2F933, UNICODE_NORM_QC_NO}, + {0x2F934, UNICODE_NORM_QC_NO}, + {0x2F935, UNICODE_NORM_QC_NO}, + {0x2F936, UNICODE_NORM_QC_NO}, + {0x2F937, UNICODE_NORM_QC_NO}, + {0x2F938, UNICODE_NORM_QC_NO}, + {0x2F939, UNICODE_NORM_QC_NO}, + {0x2F93A, UNICODE_NORM_QC_NO}, + {0x2F93B, UNICODE_NORM_QC_NO}, + {0x2F93C, UNICODE_NORM_QC_NO}, + {0x2F93D, UNICODE_NORM_QC_NO}, + {0x2F93E, UNICODE_NORM_QC_NO}, + {0x2F93F, UNICODE_NORM_QC_NO}, + {0x2F940, UNICODE_NORM_QC_NO}, + {0x2F941, UNICODE_NORM_QC_NO}, + {0x2F942, UNICODE_NORM_QC_NO}, + {0x2F943, UNICODE_NORM_QC_NO}, + {0x2F944, UNICODE_NORM_QC_NO}, + {0x2F945, UNICODE_NORM_QC_NO}, + {0x2F946, UNICODE_NORM_QC_NO}, + {0x2F947, UNICODE_NORM_QC_NO}, + {0x2F948, UNICODE_NORM_QC_NO}, + {0x2F949, UNICODE_NORM_QC_NO}, + {0x2F94A, UNICODE_NORM_QC_NO}, + {0x2F94B, UNICODE_NORM_QC_NO}, + {0x2F94C, UNICODE_NORM_QC_NO}, + {0x2F94D, UNICODE_NORM_QC_NO}, + {0x2F94E, UNICODE_NORM_QC_NO}, + {0x2F94F, UNICODE_NORM_QC_NO}, + {0x2F950, UNICODE_NORM_QC_NO}, + {0x2F951, UNICODE_NORM_QC_NO}, + {0x2F952, UNICODE_NORM_QC_NO}, + {0x2F953, UNICODE_NORM_QC_NO}, + {0x2F954, UNICODE_NORM_QC_NO}, + {0x2F955, UNICODE_NORM_QC_NO}, + {0x2F956, UNICODE_NORM_QC_NO}, + {0x2F957, UNICODE_NORM_QC_NO}, + {0x2F958, UNICODE_NORM_QC_NO}, + {0x2F959, UNICODE_NORM_QC_NO}, + {0x2F95A, UNICODE_NORM_QC_NO}, + {0x2F95B, UNICODE_NORM_QC_NO}, + {0x2F95C, UNICODE_NORM_QC_NO}, + {0x2F95D, UNICODE_NORM_QC_NO}, + {0x2F95E, UNICODE_NORM_QC_NO}, + {0x2F95F, UNICODE_NORM_QC_NO}, + {0x2F960, UNICODE_NORM_QC_NO}, + {0x2F961, UNICODE_NORM_QC_NO}, + {0x2F962, UNICODE_NORM_QC_NO}, + {0x2F963, UNICODE_NORM_QC_NO}, + {0x2F964, UNICODE_NORM_QC_NO}, + {0x2F965, UNICODE_NORM_QC_NO}, + {0x2F966, UNICODE_NORM_QC_NO}, + {0x2F967, UNICODE_NORM_QC_NO}, + {0x2F968, UNICODE_NORM_QC_NO}, + {0x2F969, UNICODE_NORM_QC_NO}, + {0x2F96A, UNICODE_NORM_QC_NO}, + {0x2F96B, UNICODE_NORM_QC_NO}, + {0x2F96C, UNICODE_NORM_QC_NO}, + {0x2F96D, UNICODE_NORM_QC_NO}, + {0x2F96E, UNICODE_NORM_QC_NO}, + {0x2F96F, UNICODE_NORM_QC_NO}, + {0x2F970, UNICODE_NORM_QC_NO}, + {0x2F971, UNICODE_NORM_QC_NO}, + {0x2F972, UNICODE_NORM_QC_NO}, + {0x2F973, UNICODE_NORM_QC_NO}, + {0x2F974, UNICODE_NORM_QC_NO}, + {0x2F975, UNICODE_NORM_QC_NO}, + {0x2F976, UNICODE_NORM_QC_NO}, + {0x2F977, UNICODE_NORM_QC_NO}, + {0x2F978, UNICODE_NORM_QC_NO}, + {0x2F979, UNICODE_NORM_QC_NO}, + {0x2F97A, UNICODE_NORM_QC_NO}, + {0x2F97B, UNICODE_NORM_QC_NO}, + {0x2F97C, UNICODE_NORM_QC_NO}, + {0x2F97D, UNICODE_NORM_QC_NO}, + {0x2F97E, UNICODE_NORM_QC_NO}, + {0x2F97F, UNICODE_NORM_QC_NO}, + {0x2F980, UNICODE_NORM_QC_NO}, + {0x2F981, UNICODE_NORM_QC_NO}, + {0x2F982, UNICODE_NORM_QC_NO}, + {0x2F983, UNICODE_NORM_QC_NO}, + {0x2F984, UNICODE_NORM_QC_NO}, + {0x2F985, UNICODE_NORM_QC_NO}, + {0x2F986, UNICODE_NORM_QC_NO}, + {0x2F987, UNICODE_NORM_QC_NO}, + {0x2F988, UNICODE_NORM_QC_NO}, + {0x2F989, UNICODE_NORM_QC_NO}, + {0x2F98A, UNICODE_NORM_QC_NO}, + {0x2F98B, UNICODE_NORM_QC_NO}, + {0x2F98C, UNICODE_NORM_QC_NO}, + {0x2F98D, UNICODE_NORM_QC_NO}, + {0x2F98E, UNICODE_NORM_QC_NO}, + {0x2F98F, UNICODE_NORM_QC_NO}, + {0x2F990, UNICODE_NORM_QC_NO}, + {0x2F991, UNICODE_NORM_QC_NO}, + {0x2F992, UNICODE_NORM_QC_NO}, + {0x2F993, UNICODE_NORM_QC_NO}, + {0x2F994, UNICODE_NORM_QC_NO}, + {0x2F995, UNICODE_NORM_QC_NO}, + {0x2F996, UNICODE_NORM_QC_NO}, + {0x2F997, UNICODE_NORM_QC_NO}, + {0x2F998, UNICODE_NORM_QC_NO}, + {0x2F999, UNICODE_NORM_QC_NO}, + {0x2F99A, UNICODE_NORM_QC_NO}, + {0x2F99B, UNICODE_NORM_QC_NO}, + {0x2F99C, UNICODE_NORM_QC_NO}, + {0x2F99D, UNICODE_NORM_QC_NO}, + {0x2F99E, UNICODE_NORM_QC_NO}, + {0x2F99F, UNICODE_NORM_QC_NO}, + {0x2F9A0, UNICODE_NORM_QC_NO}, + {0x2F9A1, UNICODE_NORM_QC_NO}, + {0x2F9A2, UNICODE_NORM_QC_NO}, + {0x2F9A3, UNICODE_NORM_QC_NO}, + {0x2F9A4, UNICODE_NORM_QC_NO}, + {0x2F9A5, UNICODE_NORM_QC_NO}, + {0x2F9A6, UNICODE_NORM_QC_NO}, + {0x2F9A7, UNICODE_NORM_QC_NO}, + {0x2F9A8, UNICODE_NORM_QC_NO}, + {0x2F9A9, UNICODE_NORM_QC_NO}, + {0x2F9AA, UNICODE_NORM_QC_NO}, + {0x2F9AB, UNICODE_NORM_QC_NO}, + {0x2F9AC, UNICODE_NORM_QC_NO}, + {0x2F9AD, UNICODE_NORM_QC_NO}, + {0x2F9AE, UNICODE_NORM_QC_NO}, + {0x2F9AF, UNICODE_NORM_QC_NO}, + {0x2F9B0, UNICODE_NORM_QC_NO}, + {0x2F9B1, UNICODE_NORM_QC_NO}, + {0x2F9B2, UNICODE_NORM_QC_NO}, + {0x2F9B3, UNICODE_NORM_QC_NO}, + {0x2F9B4, UNICODE_NORM_QC_NO}, + {0x2F9B5, UNICODE_NORM_QC_NO}, + {0x2F9B6, UNICODE_NORM_QC_NO}, + {0x2F9B7, UNICODE_NORM_QC_NO}, + {0x2F9B8, UNICODE_NORM_QC_NO}, + {0x2F9B9, UNICODE_NORM_QC_NO}, + {0x2F9BA, UNICODE_NORM_QC_NO}, + {0x2F9BB, UNICODE_NORM_QC_NO}, + {0x2F9BC, UNICODE_NORM_QC_NO}, + {0x2F9BD, UNICODE_NORM_QC_NO}, + {0x2F9BE, UNICODE_NORM_QC_NO}, + {0x2F9BF, UNICODE_NORM_QC_NO}, + {0x2F9C0, UNICODE_NORM_QC_NO}, + {0x2F9C1, UNICODE_NORM_QC_NO}, + {0x2F9C2, UNICODE_NORM_QC_NO}, + {0x2F9C3, UNICODE_NORM_QC_NO}, + {0x2F9C4, UNICODE_NORM_QC_NO}, + {0x2F9C5, UNICODE_NORM_QC_NO}, + {0x2F9C6, UNICODE_NORM_QC_NO}, + {0x2F9C7, UNICODE_NORM_QC_NO}, + {0x2F9C8, UNICODE_NORM_QC_NO}, + {0x2F9C9, UNICODE_NORM_QC_NO}, + {0x2F9CA, UNICODE_NORM_QC_NO}, + {0x2F9CB, UNICODE_NORM_QC_NO}, + {0x2F9CC, UNICODE_NORM_QC_NO}, + {0x2F9CD, UNICODE_NORM_QC_NO}, + {0x2F9CE, UNICODE_NORM_QC_NO}, + {0x2F9CF, UNICODE_NORM_QC_NO}, + {0x2F9D0, UNICODE_NORM_QC_NO}, + {0x2F9D1, UNICODE_NORM_QC_NO}, + {0x2F9D2, UNICODE_NORM_QC_NO}, + {0x2F9D3, UNICODE_NORM_QC_NO}, + {0x2F9D4, UNICODE_NORM_QC_NO}, + {0x2F9D5, UNICODE_NORM_QC_NO}, + {0x2F9D6, UNICODE_NORM_QC_NO}, + {0x2F9D7, UNICODE_NORM_QC_NO}, + {0x2F9D8, UNICODE_NORM_QC_NO}, + {0x2F9D9, UNICODE_NORM_QC_NO}, + {0x2F9DA, UNICODE_NORM_QC_NO}, + {0x2F9DB, UNICODE_NORM_QC_NO}, + {0x2F9DC, UNICODE_NORM_QC_NO}, + {0x2F9DD, UNICODE_NORM_QC_NO}, + {0x2F9DE, UNICODE_NORM_QC_NO}, + {0x2F9DF, UNICODE_NORM_QC_NO}, + {0x2F9E0, UNICODE_NORM_QC_NO}, + {0x2F9E1, UNICODE_NORM_QC_NO}, + {0x2F9E2, UNICODE_NORM_QC_NO}, + {0x2F9E3, UNICODE_NORM_QC_NO}, + {0x2F9E4, UNICODE_NORM_QC_NO}, + {0x2F9E5, UNICODE_NORM_QC_NO}, + {0x2F9E6, UNICODE_NORM_QC_NO}, + {0x2F9E7, UNICODE_NORM_QC_NO}, + {0x2F9E8, UNICODE_NORM_QC_NO}, + {0x2F9E9, UNICODE_NORM_QC_NO}, + {0x2F9EA, UNICODE_NORM_QC_NO}, + {0x2F9EB, UNICODE_NORM_QC_NO}, + {0x2F9EC, UNICODE_NORM_QC_NO}, + {0x2F9ED, UNICODE_NORM_QC_NO}, + {0x2F9EE, UNICODE_NORM_QC_NO}, + {0x2F9EF, UNICODE_NORM_QC_NO}, + {0x2F9F0, UNICODE_NORM_QC_NO}, + {0x2F9F1, UNICODE_NORM_QC_NO}, + {0x2F9F2, UNICODE_NORM_QC_NO}, + {0x2F9F3, UNICODE_NORM_QC_NO}, + {0x2F9F4, UNICODE_NORM_QC_NO}, + {0x2F9F5, UNICODE_NORM_QC_NO}, + {0x2F9F6, UNICODE_NORM_QC_NO}, + {0x2F9F7, UNICODE_NORM_QC_NO}, + {0x2F9F8, UNICODE_NORM_QC_NO}, + {0x2F9F9, UNICODE_NORM_QC_NO}, + {0x2F9FA, UNICODE_NORM_QC_NO}, + {0x2F9FB, UNICODE_NORM_QC_NO}, + {0x2F9FC, UNICODE_NORM_QC_NO}, + {0x2F9FD, UNICODE_NORM_QC_NO}, + {0x2F9FE, UNICODE_NORM_QC_NO}, + {0x2F9FF, UNICODE_NORM_QC_NO}, + {0x2FA00, UNICODE_NORM_QC_NO}, + {0x2FA01, UNICODE_NORM_QC_NO}, + {0x2FA02, UNICODE_NORM_QC_NO}, + {0x2FA03, UNICODE_NORM_QC_NO}, + {0x2FA04, UNICODE_NORM_QC_NO}, + {0x2FA05, UNICODE_NORM_QC_NO}, + {0x2FA06, UNICODE_NORM_QC_NO}, + {0x2FA07, UNICODE_NORM_QC_NO}, + {0x2FA08, UNICODE_NORM_QC_NO}, + {0x2FA09, UNICODE_NORM_QC_NO}, + {0x2FA0A, UNICODE_NORM_QC_NO}, + {0x2FA0B, UNICODE_NORM_QC_NO}, + {0x2FA0C, UNICODE_NORM_QC_NO}, + {0x2FA0D, UNICODE_NORM_QC_NO}, + {0x2FA0E, UNICODE_NORM_QC_NO}, + {0x2FA0F, UNICODE_NORM_QC_NO}, + {0x2FA10, UNICODE_NORM_QC_NO}, + {0x2FA11, UNICODE_NORM_QC_NO}, + {0x2FA12, UNICODE_NORM_QC_NO}, + {0x2FA13, UNICODE_NORM_QC_NO}, + {0x2FA14, UNICODE_NORM_QC_NO}, + {0x2FA15, UNICODE_NORM_QC_NO}, + {0x2FA16, UNICODE_NORM_QC_NO}, + {0x2FA17, UNICODE_NORM_QC_NO}, + {0x2FA18, UNICODE_NORM_QC_NO}, + {0x2FA19, UNICODE_NORM_QC_NO}, + {0x2FA1A, UNICODE_NORM_QC_NO}, + {0x2FA1B, UNICODE_NORM_QC_NO}, + {0x2FA1C, UNICODE_NORM_QC_NO}, + {0x2FA1D, UNICODE_NORM_QC_NO}, +}; + +/* Perfect hash function for NFKC_QC */ +static int +NFKC_QC_hash_func(const void *key) +{ + static const int16 h[9955] = { + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 3138, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -50, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 1, 32767, 2, 32767, 32767, 32767, 32767, 3, + 32767, 32767, 4, 5, 6, 7, 32767, 32767, + 8, 9, 10, 32767, 11, 12, -39, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 14, 15, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -36, -3114, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, -43, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -61, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 3139, 3140, 3141, 3142, + 3143, 3144, 3145, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 3104, 21, 3107, + 23, 24, 25, 26, 27, 28, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 3146, 3147, 3148, 3149, 3150, 3151, 32767, + 32767, 32767, 29, 30, 31, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 3130, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 3213, 3214, 2948, 35, 3060, 3219, + 38, 39, 40, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 41, 42, 43, 44, 45, 46, + 32767, 32767, -634, 48, 49, 50, 51, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 32767, 0, + 32767, 32767, 32767, 32767, 0, 32767, 0, 0, + 0, 0, 0, 32767, 32767, 0, 0, 0, + 32767, 0, 0, 52, 3131, 54, 55, 56, + 32767, 57, 58, 59, 60, 61, 62, 63, + 32767, 32767, 64, 32767, 3221, 32767, 3222, 3223, + 32767, 32767, 32767, 32767, 32767, 32767, 68, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 69, 70, + 71, 72, 73, 74, 32767, 32767, 32767, 32767, + 75, 76, 32767, 77, 3259, 32767, 32767, 32767, + 32767, 32767, 32767, 79, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 80, 81, 82, 83, 84, + 85, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, -33, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, -2919, + 32767, 32767, 32767, 32767, 32767, -3076, 32767, 32767, + 32767, -3079, 32767, 32767, 32767, 32767, 32767, -3084, + -3084, 0, -3085, 0, 0, 0, 0, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 0, 0, + 32767, 32767, 32767, -943, -942, -941, 32767, 32767, + 32767, 32767, 0, -3078, 0, 0, 0, 32767, + 0, 0, 0, 0, 0, 0, 0, 32767, + 32767, 0, 32767, -3156, -3156, -3156, -3156, -3156, + -3156, -3156, 32767, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 0, 0, + 0, 0, 0, 32767, 32767, 32767, 32767, 0, + 0, 32767, 0, -3181, -3181, -2914, 0, -3024, + -3182, 0, 0, 0, -3185, 32767, 32767, 32767, + 32767, 32767, 0, 0, 0, 0, 0, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 0, 0, 0, 0, 0, + 0, 32767, 32767, 681, 0, 0, 0, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 3152, 3153, 3154, 3155, 4895, 3005, 3158, + 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, + 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, + 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, + 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, + 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, + 3199, 3200, 3201, 3202, 3203, 3204, 1002, 3206, + 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, + 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, + 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3230, + 3231, 3232, 3233, 3234, 3235, 3236, 32767, 3237, + 3238, 3239, 3240, 3241, 3242, 3243, 3244, 3245, + 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, + 3254, 3255, 3256, 3257, 3258, 7120, 3260, 3261, + 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3114, + 3270, 3271, 3272, 3273, 3118, 3275, 3276, 3277, + 3278, 3122, 3280, 3281, 3015, 3283, 3126, 3285, + 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, + 3294, 3295, 3296, 5040, 3298, 3299, 3300, 3301, + 3302, 3303, 3304, 3305, 3306, 5059, 32767, 574, + 574, 32767, 32767, 3944, 32767, 32767, 3311, 3312, + 32767, 32767, 3313, 5153, 3315, 3316, 32767, 3317, + 3318, 3319, 3320, 4304, 4305, 4306, 4307, 4308, + 4309, 4310, 3328, 32767, 4313, 32767, 3330, 3331, + 3332, 3333, 3334, 3335, 3336, 32767, 3337, 8896, + 3339, 3340, 3341, 3342, 5133, 3344, 3345, 3346, + 3347, 5142, 3349, 3350, 3351, 3352, 7858, 3354, + 3355, 3356, -12, 3358, 3359, 3360, 3361, 3362, + -3689, -3689, -3689, -920, 3367, 3368, 3369, 3370, + 3371, 3372, 3373, 3374, 3375, 3132, 3377, 3378, + 3379, 3380, 3381, 3382, 3383, 3384, 3385, 3386, + 3387, 3388, 1815, 3390, 3391, 3392, 3393, 3394, + 3395, 32767, 3396, 3240, 3398, 3399, 3133, 3401, + 32767, 3402, 3403, 3404, 3405, 32767, 32767, 3406, + 3407, 3408, 3409, 3410, 3411, 5155, 3413, 0, + 3414, 3415, 3416, 3417, 3418, 3419, 3420, 32767, + 3421, 688, 688, 688, 4059, 4060, 3427, 3428, + 3429, 3430, 3431, 3432, 3433, 5273, 3435, 3436, + 3437, 3438, 3439, 3440, 3441, 4425, 4426, 4427, + 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4378, + 3452, 32767, 3453, 3454, 3455, 3456, 3457, 32767, + 3458, 32767, 32767, 32767, 3459, 3460, 5251, 3462, + 3463, 3464, 3465, 32767, 3466, 3467, 3468, 3469, + 7975, 3471, 3472, 3473, 105, 3475, 3476, 3477, + 3478, 3479, -3572, -3572, -3572, -803, 3484, 3485, + 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3249, + 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, + 3502, 3503, 3504, 3505, 1932, 3507, 3508, 3509, + 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, + 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, + 3526, 3527, 3528, 3529, 3530, 682, 683, 3533, + 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, + 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, + 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, + 3558, 3559, 3560, 3561, 3562, 3563, 3564, 3565, + 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, + 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, + 3582, -3534, -3534, -3534, -3534, 3587, 3588, 3589, + 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, + 3598, 3599, 3600, 5398, 3602, 3603, 10119, 3605, + 3606, 3607, 3608, 3609, 3610, 3611, 3612, 3613, + 2446, 3615, 3616, 2444, 3618, 3619, 3620, 3621, + 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, + 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, + 3638, 3639, 32767, 3640, 3641, 3642, 3643, 3644, + 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, + 3653, 3654, 3655, 3656, 3657, 3658, 3659, 811, + 812, 3662, 3663, 3664, 3665, 3666, 3667, 3668, + 3669, 3670, 3671, 3672, 3673, 3674, 3675, 3676, + 3677, 3678, 3679, 3680, 3681, 3682, 3683, 3684, + 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, + 3693, 3694, 3695, 3696, 3697, 3698, 3699, 3700, + 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, + 3709, 3710, 3711, -3405, -3405, -3405, -3405, 3716, + 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, + 3725, 3726, 3727, 3728, 3729, 5527, 3731, 3732, + 10248, 3734, 3735, 3736, 3737, 3738, 3739, 3740, + 3741, 3742, 2575, 3744, 3745, 2573, 3747, 3748, + 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, + 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, + 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, + 3773, 684, 3775, 3776, 3777, 3778, 3779, 3780, + 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, + 3789, 3790, 3937, 3938, 2261, 3940, 3795, 3796, + 3797, 3798, 3799, 3800, 3801, 3802, 3803, 221, + 3805, 32767, 32767, 3806, 3807, 3808, 3809, 3810, + 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, + 3819, 3820, 3821, 3822, 2571, 3824, 3825, -2009, + 3827, 3828, 3829, 5428, -32, 3832, 2298, 2298, + 3651, 2298, 2298, 2298, 2298, 2298, 2298, 2298, + 2298, 2298, 2298, 2298, 2298, 2298, 2298, 2298, + 2298, 2298, 2298, 2298, 2298, 2298, 3008, 2298, + 2298, -1412, -1970, 3070, 3790, -10984,-10984,4117, + -1240, -1239, -1238, -10892,2298, 2298, 2298, 2298, + 3199, 2298, 2298, 8405, 3654, 12572, 2298, 12575, + 3655, 8408, 12579, 12580, 12581, 3786, 3889, 3890, + 3891, 3892, 2298, 32767, 3894, 3895, 3896, 3897, + 3898, 3899, 3900, 811, 3902, 3903, 3904, 3905, + 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, + 3914, 3915, 3916, 3917, 4064, 4065, 2388, 4067, + 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, + 3930, 348, 3932, 3933, 3934, 3935, 3936, 3937, + 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, + 3946, 3947, 3948, 3949, 3950, 3951, 2700, 3953, + 3954, -1880, 3956, 3957, 3958, 5557, 97, 3961, + 2427, 2427, 3780, 2427, 2427, 2427, 2427, 2427, + 2427, 2427, 2427, 2427, 2427, 2427, 2427, 2427, + 2427, 2427, 2427, 2427, 2427, 2427, 2427, 2427, + 3137, 2427, 2427, -1283, -1841, 3199, 3919, -10855, + -10855,4246, -1111, -1110, -1109, -10763,2427, 2427, + 2427, 2427, 3328, 2427, 2427, 8534, 3783, 12701, + 2427, 12704, 3784, 8537, 12708, 12709, 12710, 3915, + 4018, 4019, 4020, 4021, 2427, 10069, -1249, 13526, + 13527, -1573, 3785, 3785, 3785, 13440, 4978, 12723, + 12724, 13444, 3785, 3785, 3785, 3785, 3785, 2427, + 13783, 13784, 13785, 13786, 13787, 13788, 13789, 13790, + 13791, 12571, 7690, 12573, 4054, 8638, 8639, 7689, + 4848, 12578, 4849, 4850, 4851, 6358, 7295, 7295, + 7295, 7295, 7295, 7295, 2427, 2427, 2427, 2427, + 2427, 2427, 2427, 2427, 2427, 2427, 2427, 2427, + 2427, 13409, 2427, 2427, 2427, 2427, 2427, 2427, + -2360, 2427, 2427, 2427, 2427, 2427, 2427, 2427, + 32767, 32767, 2425, 2425, 2425, 4101, 4102, 2425, + 4104, 4034, 2425, 2425, 308, 1325, 1326, 376, + 2841, 2841, 376, 376, 3794, 4117, 3792, 375, + 4120, 4121, 4122, 4123, -1233, 6543, 4126, 4127, + 4128, 6544, 6545, 4131, 16128, 3831, 8385, 4135, + 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, + 4144, 4145, 4146, 4147, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 686, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 70, 70, 70, 688, 689, 690, + 67, 67, 693, 694, 695, 696, 697, 698, + 699, 700, 701, 702, 703, 704, 705, 706, + 707, 708, 709, 710, 711, 712, 713, 714, + 715, 716, 717, 718, 2461, 720, 721, 722, + 723, 724, 725, 726, 727, 728, 729, 730, + -1302, 732, 733, 734, 735, 736, 737, 738, + 739, 740, 741, 742, 743, 744, 745, 746, + 747, 748, 749, 750, 751, 752, 753, 3609, + 755, 3805, 757, 758, 759, 760, 761, 762, + 763, 764, 765, 766, 767, 768, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 778, + 779, 780, 781, 782, 783, 784, 785, 786, + 787, 788, 789, 790, 791, 792, 793, 794, + 795, 796, 797, 798, 799, 800, 801, 802, + 803, 804, 805, 806, 807, 808, 809, 810, + 811, 812, 813, 814, 815, 816, 817, 818, + 819, 820, 821, 822, 823, 824, 825, -3308, + -5758, -5758, -5758, -5758, -5758, -5758, -5758, -5758, + -5758, -5758, -5758, -1733, -1732, -1731, -1730, -1729, + -1728, -1727, -1726, -1725, -1724, -1723, -1722, -1721, + -3609, -3609, -1720, -3609, -1718, -3609, -1373, -3609, + -1714, -3609, -1712, -3609, -1710, -3609, -1708, -3609, + -3609, 2387, 2388, 2389, 2390, 2391, 2392, 2393, + -3609, -3609, -1696, 878, 879, 880, -2490, -2490, + -3609, -1689, -1688, -1687, 2092, 2427, -3688, -3688, + -3688, -1681, -1680, -1679, -1678, 896, -3683, -1675, + -3682, -2759, 32767, 0, 0, 1353, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 710, 0, 0, -3710, -4268, + 772, 1492, -13282,-13282,1819, -3538, -3537, -3536, + -13190,0, 0, 0, 0, 901, 0, 0, + 6107, 1356, 10274, 0, 10277, 1357, 6110, 10281, + 10282, 10283, 1488, 1591, 1592, 1593, 1594, 0, + 7642, -3676, 11099, 11100, -4000, 1358, 1358, 1358, + 11013, 2551, 10296, 10297, 11017, 1358, 1358, 1358, + 1358, 1358, 0, 11356, 11357, 11358, 11359, 11360, + 11361, 11362, 11363, 11364, 10144, 5263, 10146, 1627, + 6211, 6212, 5262, 2421, 10151, 2422, 2423, 2424, + 3931, 4868, 4868, 4868, 4868, 4868, 4868, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10982, 0, 0, 0, + 0, 0, 0, -4787, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1676, 1677, 0, 1679, 1609, 0, 0, -2117, + -1100, -1099, -2049, 416, 416, -2049, -2049, 1369, + 1692, 1367, -2050, 1695, 1696, 1697, 1698, -3658, + 4118, 1701, 1702, 1703, 4119, 4120, 1706, 13703, + 1406, 5960, 1710, 1711, 1712, 1713, 1714, 1715, + 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1406, + 1406, 1406, 1406, 1406, 0, 10979, -4121, 77, + 1236, 2500, 0, 0, 2501, 0, 1563, 1563, + 1563, 1563, 1563, 1563, 1563, 1563, 1563, 1563, + 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, + 4022, 4023, 4024, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1890, 0, 1892, -343, 1894, + 0, 1896, 0, 1898, 0, 1900, 0, 1902, + 1903, -4092, -4092, -4092, -4092, -4092, -4092, -4092, + 1911, 1912, 0, -2573, -2573, -2573, 798, 799, + 1919, 0, 0, 0, -3778, -4112, 2004, 2005, + 2006, 0, 0, 0, 0, -2573, 2007, 0, + 2008, 1086, 2010, -446, 2012, 2013, 2014, 2015, + 2016, 1094, -443, -3070, 2390, -3070, -3070, 1100, + -3070, -3070, -3070, 5726, 2028, 5729, 5730, 2031, + 1959, -426, 10893, -3881, -3881, 1964, 1965, -3068, + 1967, -3787, 4676, 1970, -3069, -3788, 1973, -4114, + -4114, -4114, -4114, -4114, -4114, -4114, -4114, -4114, + -4114, -4114, -4114, -4114, -4114, -2893, 1989, -2893, + 2059, 1043, 1043, 1994, 4836, -2893, 4837, 4837, + 4837, 3331, 2395, 2396, 2397, 2398, 2399, 2400, + 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, + 2409, 2410, 2411, -3687, -3687, -3687, -3687, -3687, + -3687, 2092, 2093, 2428, -3687, -3687, -3687, 10820, + -2764, -2764, -3687, -3687, -3687, 2104, -3687, -2764, + -3687, -1230, -3687, -3687, -3687, -3687, -3687, -2764, + -1226, 1402, -4057, 1404, 1405, -2764, 1407, 1408, + 1409, -7386, -3687, -7387, -7387, -3687, -3687, -1229, + -12547,2228, 2229, -3615, -1402, 1418, -1400, 2138, + -6324, 1421, 1422, 2142, -6327, 2469, 2470, 2471, + 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, + 2480, 2481, 2482, -30, -3686, 0, 0, 0, + -2739, -3689, -1224, -1224, -3689, -3689, -271, 52, + -3689, -3689, -4140, 58, 1217, 2481, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2451, + 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, + 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, + 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, + 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, + 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, + 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, + 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, + 2508, 2509, 2510, 2511, 2512, 0, -3656, 1227, + -3724, -2707, -2706, -3656, -1191, -1191, -3656, -3656, + -238, 85, -3656, -3656, -4107, 91, 0, 2513, + -5261, 2515, 2516, 2517, 2518, 2519, 2520, 2521, + 2522, 2523, 2413, 2525, 2526, 2416, 2528, 2529, + 2419, 2420, 2421, 4867, 4867, 3361, 2425, 2426, + 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, + 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442, + 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, + -3665, -3665, -3665, 10842, -2742, -2742, -3665, -3665, + -3665, 2126, -3665, -2742, -3665, -1208, -3665, -3665, + -3665, -3665, -3665, -2742, -1204, 1424, -4035, 1426, + 1427, -2742, 1429, 1430, 1431, -7364, -3665, -7365, + -7365, -3665, -3665, -1207, -12525,2250, 2251, -3593, + -1380, 1440, -1378, 2160, -6302, 1443, 0, 2163, + -6306, 2490, 2491, 2492, 2493, 2494, 2495, 2496, + 2497, 2498, 2499, 2500, 2501, 2502, 2503, 1283, + -3598, 1285, -3666, -2649, -2648, -3598, -6439, 1291, + -6438, -6437, -6436, -4929, -3992, -3992, -3992, -3992, + -3992, -3992, -3992, -3992, -3992, -3992, -3992, -3992, + -3992, -3992, -3992, -3992, -3992, 2107, 2108, 2109, + 2110, 2111, 2112, -3666, -3666, -4000, 2116, 2117, + 2118, -12388,1197, 1198, 2122, 2123, 2124, -3666, + 2126, 1204, 2128, -328, 2130, 2131, 2132, 2133, + 2134, 1212, -325, -2952, 2508, -2952, -2952, 1218, + -2952, -2952, -2952, 5844, 2146, 5847, 5848, 2149, + 2150, -307, 11012, -3762, -3762, 2083, -129, -2948, + -129, -3666, 4797, -2947, -2947, -3666, 4804, -3991, + -3991, -3991, -3991, -3991, -3991, -2946, -2946, 5630, + -129, -211, -129, -2944, -129, -129, -129, -129, + -129, -129, 1261, -129, 3621, -129, -129, 0, + 1572, 2292, -6177, 2619, 2620, 2621, 2622, 2623, + 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, + 2632, 1412, -3469, 1414, -3537, -2520, -2519, -3469, + -6310, 1420, -6309, -6308, -6307, -4800, -3863, -3863, + -3863, -3863, -3863, -3863, -3863, -3863, -3863, -3863, + -3863, -3863, -3863, -3863, -3863, -3863, -3863, 2236, + 2237, 2238, 2239, 2240, 2241, -3537, -3537, -3871, + 2245, 2246, 2247, -12259,1326, 1327, 2251, 2252, + 2253, -3537, 2255, 1333, 2257, -199, 2259, 2260, + 2261, 2262, 2263, 1341, -196, -2823, 2637, -2823, + -2823, 1347, -2823, -2823, -2823, 5973, 2275, 5976, + 5977, 2278, 2279, -178, 11141, -3633, -3633, 2212, + 0, -2819, 0, -3537, 4926, -2818, -2818, -3537, + 4933, -3862, -3862, -3862, -3862, -3862, -3862, -2817, + -2817, 5759, 0, -82, 0, -2815, 0, 0, + 0, 0, 0, 0, 1390, 0, 3750, 0, + 0, -2805, 0, -2804, 0, -2803, 0, 1401, + 1402, 1403, 0, 1405, 1406, -3537, 1408, 0, + 1410, 2632, 2633, 1413, -3468, 1415, -3536, -2519, + -2518, -3468, -6309, 1421, -6308, -6307, -6306, -4799, + -3862, -3862, -3862, -3862, -3862, -3862, -3862, -3862, + -3862, -3862, -3862, -3862, -3862, -3862, -3862, 1441, + 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, + 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, + 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, + 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, + 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, + 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, + 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, + 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, + 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, + 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2635, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, 0, 0, 0, 0, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, -5116, + 32767, 32767, 32767, 32767, -2277, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 148, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 0, 0, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -10147,32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 150, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 0, + 0, 0, -1739, 152, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2203, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -3861, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 155, 0, 0, 0, + 0, 156, 0, 0, 0, 0, 157, 0, + 0, 267, 0, 158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1743, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1752, 0, 2734, 2735, 2736, -634, + -634, 0, 0, 0, 0, 0, 0, 0, + -1839, 0, 0, 0, 0, 0, 0, 0, + -983, -983, -983, -983, -983, -983, -983, 0, + -984, -984, -927, 0, 0, 0, 0, 0, + 0, 0, 32767, 0, -5558, 0, 0, 0, + 0, -1790, 0, 0, 0, 0, -1794, 0, + 0, 0, 0, -4505, 0, 0, 0, 3369, + 0, 0, 0, 0, 0, 7052, 7053, 7054, + 4286, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 244, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1574, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2849, 2849, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7117, 7118, 7119, 7120, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -1797, 0, + 0, -6515, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1168, 0, 0, 1173, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3090, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -146, -146, 1532, -146, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 3583, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1252, 0, 0, + 5835, 0, 0, 0, -1598, 3863, 0, 1535, + 1536, 184, 1538, 1539, 1540, 1541, 1542, 1543, + 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1551, + 1552, 1553, 1554, 1555, 1556, 1557, 1558, 849, + 1560, 1561, 5272, 5831, 792, 73, 14848, 14849, + -251, 5107, 5107, 5107, 14762, 1573, 1574, 1575, + 1576, 676, 1578, 1579, -4527, 225, -8692, 1583, + -8693, 228, -4524, -8694, -8694, -8694, 102, 0, + 0, 0, 0, 1595, -6046, 5273, -9501, -9501, + 5600, 243, 244, 245, -9409, -946, -8690, -8690, + -9409, 251, 252, 253, 254, 255, 1614, -9741, + -9741, -9741, -9741, -9741, -9741, -9741, -9741, -9741, + -8520, -3638, -8520, 0, -4583, -4583, -3632, -790, + -8519, -789, -789, -789, -2295, -3231, -3230, -3229, + -3228, -3227, -3226, 1643, 1644, 1645, 1646, 1647, + 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, + -9326, 1657, 1658, 1659, 1660, 1661, 1662, 6450, + 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, + 1672, 1673, 1674, 1675, 0, 0, 1678, 0, + 71, 1681, 1682, 3800, 2784, 2784, 3735, 1271, + 1272, 3738, 3739, 322, 0, 326, 3744, 0, + 0, 0, 0, 5357, -2418, 0, 0, 0, + -2415, -2415, 0, -11996,302, -4251, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 318, 319, 320, 321, + 1728, -9250, 5851, 1654, 496, -767, 1734, 1735, + -765, 1737, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, -2266, -2266, -2266, -2266, + -2266, -2266, -2266, -2266, -2266, -2266, -2266, 1759, + 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, + 1768, 1769, 1770, 1771, 1772, 1773, 1774, -115, + 1776, -115, 2121, -115, 1780, -115, 1782, -115, + 1784, -115, 1786, -115, -115, 5881, 5882, 32767, + 1791, 6579, 1793, 1794, 1795, 1796, 1797, 1798, + 1799, 1800, 1801, 1802, 1803, 1804, 32767, 32767, + 1805, -2316, 197, 3854, -1028, 3924, 2908, 2908, + 3859, 1395, 1396, 3862, 3863, 446, 124, 3866, + 3867, 4319, 122, 214, -2298, 5477, -2298, -2298, + -2298, -2298, -2298, -2298, 117, -11879,419, -4134, + 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 117, 117, 434, 435, 436, + 437, 438, 1845, -9133, 5968, 1771, 613, -650, + 1851, 1852, -648, 1854, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, -2149, -2149, + -2149, -2149, -2149, -2149, -2149, -2149, -2149, -2149, + -2149, 1876, 1877, 1878, 1879, 1880, 1881, 1882, + 1883, 1884, 1885, 1886, 1887, 1888, 0, 0, + 1889, 0, 1891, 0, 2236, 0, 1895, 0, + 1897, 0, 1899, 0, 1901, 0, 0, 5996, + 5997, 5998, 5999, 6000, 6001, 6002, 0, 0, + 1913, 4487, 4488, 4489, 1119, 1119, 0, 1920, + 1921, 1922, 5701, 6036, -79, -79, -79, 1928, + 1929, 1930, 1931, 4505, -74, 1934, -73, 850, + -73, 2384, -73, -73, -73, -73, -73, 850, + 2388, 5016, -443, 5018, 5019, 850, 5021, 5022, + 5023, -3772, -73, -3773, -3773, -73, 0, 2386, + -8932, 5843, 5844, 0, 0, 5034, 0, 5755, + -2707, 0, 5040, 5760, 0, 6088, 6089, 6090, + 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, + 6099, 6100, 6101, 4881, 0, 4883, -68, 949, + 950, 0, 2465, 2465, 0, 0, 3418, 3741, + 0, 0, -451, 3747, 4906, 6170, -1604, 6172, + 6173, 6174, 6175, 6176, 6177, 6178, 6179, 6180, + 6070, 6182, 6183, 6073, 6185, 6186, 6076, 6077, + 6078, 8524, 8524, 7018, 6082, 6083, 6084, 6085, + 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, + 6094, 6095, 6096, 6097, 6098, 0, 0, 0, + 0, 0, 0, 5779, 5780, 6115, 0, 0, + 0, 14507, 923, 923, 0, 0, 0, 5791, + 0, 923, 0, 2457, 0, 0, 0, 0, + 0, 923, 2461, 5089, -370, 5091, 5092, 923, + 5094, 5095, 5096, -3699, 0, -3700, -3700, 0, + 0, 2458, -8860, 5915, 5916, 72, 2285, 5105, + 2287, 5825, -2637, 5108, 5109, 5829, -2640, 6156, + 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, + 6165, 6166, 6167, 6168, 6169, 4949, 68, 4951, + 0, 1017, 1018, 68, -2773, 4957, -2772, -2771, + -2770, -1263, -326, -326, -326, -326, -326, -326, + -326, -326, -326, -326, -326, -326, -326, -326, + -326, -326, -326, 5773, 5774, 5775, 5776, 5777, + 5778, 0, 0, -334, 5782, 5783, 5784, -8722, + 4863, 4864, 5788, 5789, 5790, 0, 5792, 4870, + 5794, 3338, 5796, 5797, 5798, 5799, 5800, 4878, + 3341, 714, 6174, 714, 714, 4884, 714, 714, + 714, 9510, 5812, 9513, 9514, 5815, 5816, 3359, + 14678, -96, -96, 5749, 3537, 718, 3537, 0, + 8463, 719, 719, 0, 8470, -325, -325, -325, + -325, -325, -325, 720, 720, 9296, 3537, 3455, + 3537, 722, 3537, 3537, 3537, 3537, 3537, 3537, + 4927, 3537, 7287, 3537, 3537, 732, 3537, 733, + 3537, 734, 3537, 4938, 4939, 4940, 3537, 4942, + 4943, 0, 4945, 3537, 2150, 2151, 2152, 2153, + 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, + 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, + 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, + 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, + 2186, 2187, 2188, 2189, 2190, 2191, 2192, -258, + -258, 32767, 4959, 4960, 5884, 5885, 5886, 96, + 5888, 4966, 5890, 3434, 5892, 5893, 5894, 5895, + 5896, 4974, 3437, 810, 6270, 810, 810, 4980, + 810, 810, 810, 9606, 5908, 9609, 9610, 5911, + 5912, 3455, 14774, 0, 0, 5845, 3633, 814, + 3633, 96, 8559, 815, 815, 96, 8566, -229, + -229, -229, -229, -229, -229, -229, -229, -229, + -229, -229, -229, -229, -229, 2284, 5941, 2256, + 2257, 2258, 4998, 5949, 3485, 3486, 5952, 5953, + 2536, 2214, 5956, 5957, 6409, 2212, 1054, -209, + 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, + 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, + 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, + 2297, 2298, 2299, 2300, 2301, 2302, 2303, 2304, + 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, + 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, + 2321, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, -129, + -129, -129, -129, -129, -129, -129, -129, 2384, + 6041, 1159, 6111, 5095, 5095, 6046, 3582, 3583, + 6049, 6050, 2633, 2311, 6053, 6054, 6506, 2309, + 2401, -111, 7664, -111, -111, -111, -111, -111, + -111, -111, -111, -111, 0, -111, -111, 0, + -111, -111, 0, 0, 0, -2445, -2444, -937, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7775, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 111, 0, + 0, 111, 0, 0, 111, 111, 111, -2334, + -2333, -826, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 6227, 6228, 6229, -8277, + 5308, 5309, 6233, 6234, 6235, 445, 6237, 5315, + 6239, 3783, 6241, 32767, 32767, 6242, 6243, 5321, + 3784, 1157, 6617, 1157, 1157, 5327, 1157, 1157, + 1157, 9953, 6255, 9956, 9957, 6258, 6259, 3802, + 15121, 347, 347, 6192, 3980, 1161, 3980, 443, + 8906, 1162, 2606, 444, 8914, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 1340, 6222, 1340, 6292, 5276, + 5276, 6227, 9069, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 6297, 506, 1429, 506, 2963, + 506, 506, 506, 506, 506, 1429, 2967, 5595, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 6309, 6310, 6311, 6312, + 6313, 5391, 3854, 1227, 6687, 1227, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 2654, 492, 8962, 167, + 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 1388, 6270, 1388, + 6340, 32767, 32767, 6273, 9115, 1386, 9116, 9116, + 9116, 7610, 6674, 6675, 6676, 6677, 6678, 32767, + 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, + 6687, 6688, 6689, 591, 591, 591, 591, 591, + 591, 6370, 6371, 32767, 590, 590, 590, 15097, + 32767, 32767, 32767, 32767, 586, 6377, 586, 32767, + 585, 32767, 584, 584, 584, 584, 584, 1507, + 3045, 5673, 214, 5675, 5676, 1507, 5678, 5679, + 5680, -3115, 584, -3116, -3116, 584, 584, 3042, + -8276, 6499, 6500, 656, 2869, 5689, 2871, 6409, + -2053, 5692, 5693, 6413, -2056, 6740, 6741, 6742, + 6743, 6744, 6745, 5701, 5702, -2873, 2887, 2970, + 2889, 5705, 2891, 2892, 2893, 2894, 2895, 2896, + 1507, 2898, -851, 2900, 2901, 2773, 1202, 483, + 8953, 158, 158, 158, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 158, 158, 1379, + 6261, 1379, 6331, 5315, 5315, 6266, 9108, 1379, + 9109, 9109, 9109, 7603, 6667, 6668, 6669, 6670, + 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, + 6679, 6680, 6681, 6682, 6683, 585, 585, 585, + 585, 585, 585, 6364, 6365, 6700, 585, 585, + 585, 15092, 1508, 1508, 585, 585, 585, 6376, + 585, 1508, 585, 3042, 585, 585, 585, 585, + 585, 32767, 32767, 32767, 32767, 32767, 5801, 1632, + 5803, 5804, 5805, -2990, 709, -2991, -2991, 709, + 709, 3167, -8151, 6624, 6625, 781, 2994, 5814, + 2996, 6534, -1928, 5817, 5818, 6538, -1931, 6865, + 6866, 6867, 6868, 6869, 6870, 5826, 5827, -2748, + 3012, 3095, 3014, 5830, 3016, 3017, 3018, 3019, + 3020, 3021, 1632, 3023, -726, 3025, 3026, 2898, + 1327, 608, 9078, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, + 283, 1504, 6386, 1504, 6456, 5440, 5440, 6391, + 9233, 1504, 9234, 9234, 9234, 7728, 6792, 6793, + 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, + 6802, 6803, 6804, 6805, 6806, 6807, 6808, 710, + 710, 710, 710, 710, 710, 6489, 6490, 6825, + 710, 710, 710, 15217, 1633, 1633, 710, 710, + 710, 6501, 710, 1633, 710, 3167, 710, 710, + 710, 710, 710, 1633, 3171, 5799, 340, 5801, + 5802, 1633, 5804, 5805, 5806, -2989, 710, -2990, + -2990, 710, 710, 3168, -8150, 6625, 6626, 782, + 2995, 5815, 2997, 6535, -1927, 5818, 5819, 6539, + -1930, 6866, 6867, 6868, 6869, 6870, 6871, 5827, + 5828, -2747, 3013, 3096, 3015, 5831, 3017, 3018, + 3019, 3020, 3021, 3022, 1633, 3024, -725, 3026, + 3027, 5833, 3029, 5834, 3031, 5835, 3033, 1633, + 1633, 1633, 3037, 1633, 32767, 32767, 32767, 3039, + 1630, 409, 409, 1630, 6512, 32767, 32767, 5564, + 5564, 6515, 9357, 1628, 9358, 32767, 32767, 7850, + 6914, 6915, 6916, 6917, 6918, 32767, 32767, 6919, + 6920, 6921, 32767, 32767, 32767, 6922, 6923, 1621, + 1621, 1621, 1621, 1621, 32767, 1620, 1620, 1620, + 1620, 1620, 1620, 1620, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 617, 0, + 0, 0, 624, 625, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -1742, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2033, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -2855, 0, -3049, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4134, 6585, 6586, 6587, 6588, 6589, 6590, + 6591, 6592, 6593, 6594, 6595, 2571, 2571, 2571, + 2571, 2571, 2571, 2571, 2571, 2571, 2571, 2571, + 2571, 2571, 4460, 4461, 2573, 4463, 2573, 4465, + 2230, 4467, 2573, 4469, 2573, 4471, 2573, 4473, + 2573, 4475, 4476, -1519, -1519, -1519, -1519, -1519, + -1519, -1519, 4484, 4485, 2573, 0, 0, 0, + 3371, 3372, 4492, 2573, 2573, 2573, -1205, -1539, + 4577, 4578, 4579, 2573, 2573, 2573, 2573, 0, + 4580, 2573, 4581, 3659, 4583, 2127, 4585, 4586, + 4587, 4588, 4589, 3667, 2130, -497, 4963, -497, + -497, 3673, -497, -497, -497, 8299, 4601, 8302, + 8303, 4604, 4532, 2147, 13466, -1308, -1308, 4537, + 4538, -495, 4540, -1214, 7249, 4543, -496, -1215, + 4546, -1541, -1541, -1541, -1541, -1541, -1541, -1541, + -1541, -1541, -1541, -1541, -1541, -1541, -1541, -320, + 4562, -320, 4632, 3616, 3616, 4567, 2103, 2104, + 4570, 4571, 1154, 832, 4574, 4575, 5027, 830, + -328, -1591, 6184, -1591, -1591, -1591, -1591, -1591, + -1591, -1591, -1591, -1591, -1480, -1591, -1591, -1480, + -1591, -1591, -1480, -1480, -1480, -3925, -3924, -2417, + -1480, -1480, -1480, -1480, -1480, -1480, -1480, -1480, + -1480, -1480, -1480, -1480, -1480, -1480, -1480, -1480, + -1480, 4619, 4620, 4621, 4622, 4623, 4624, -1154, + -1154, -1488, 4628, 4629, 4630, -9876, 3709, 3710, + 4634, 4635, 4636, -1154, 4638, 3716, 4640, 2184, + 4642, 4643, 4644, 4645, 4646, 3724, 2187, -440, + 5020, -440, -440, 3730, -440, -440, -440, 8356, + 4658, 8359, 8360, 4661, 4662, 2205, 13524, -1250, + -1250, 4595, 2383, -436, 2383, -1154, 7309, -435, + -435, -1154, 7316, -1479, -1479, -1479, -1479, -1479, + -1479, -1479, -1479, -1479, -1479, -1479, -1479, -1479, + -1479, 1034, 4691, -191, 4761, 3745, 3745, 4696, + 2232, 2233, 4699, 4700, 1283, 961, 4703, 4704, + 5156, 959, -199, -1462, 6313, -1462, -1462, -1462, + -1462, -1462, -1462, -1462, -1462, -1462, -1351, -1462, + -1462, -1351, -1462, -1462, -1351, -1351, -1351, -3796, + -3795, -2288, -1351, -1351, -1351, -1351, -1351, -1351, + -1351, -1351, -1351, -1351, -1351, -1351, -1351, -1351, + -1351, -1351, -1351, 4748, 4749, 4750, 4751, 4752, + 4753, -1025, -1025, -1359, 4757, 4758, 4759, -9747, + 3838, 3839, 4763, 4764, 4765, -1025, 4767, 3845, + 4769, 2313, 4771, 4772, 4773, 4774, 4775, 3853, + 2316, -311, 5149, -311, -311, 3859, -311, -311, + -311, 8485, 4787, 8488, 8489, 4790, 4791, 2334, + 13653, -1121, -1121, 4724, 2512, -307, 2512, -1025, + 7438, -306, -306, -1025, 7445, -1350, -1350, -1350, + -1350, -1350, -1350, -1350, -1350, -1350, -1350, -1350, + -1350, -1350, -1350, -129, 4753, -129, 4823, 3807, + 3807, 4758, 7600, -129, 7601, 7601, 7601, 6095, + 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, + 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174, + 5175, -923, -923, -923, -923, -923, -923, 4856, + 4857, 5192, -923, -923, -923, 13584, 0, 0, + -923, -923, -923, 4868, -923, 0, -923, 1534, + -923, -923, -923, -923, -923, 0, 1538, 4166, + -1293, 4168, 4169, 0, 4171, 4172, 4173, -4622, + -923, -4623, -4623, -923, -923, 1535, -9783, 4992, + 4993, -851, 1362, 4182, 1364, 4902, -3560, 4185, + 4186, 4906, -3563, 5233, 5234, 5235, 5236, 5237, + 5238, 4194, 4195, -4380, 1380, 1463, 1382, 4198, + 1384, 1385, 1386, 1387, 1388, 1389, 0, 1391, + -2358, 1393, 1394, 4200, 1396, 4201, 1398, 4202, + 1400, 0, 0, 0, 1404, 0, 0, 4944, + 0, 1409, 0, -1221, -1221, 0, 4882, 0, + 4952, 3936, 3936, 4887, 7729, 0, 7730, 7730, + 7730, 6224, 5288, 5289, 5290, 5291, 5292, 5293, + 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, + 5302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 4751, 0, 8918, 3459, 8920, 0, 4753, + 8924, 8925, 8926, 131, 234, 235, 236, 237, + 32767, 6284, -5034, 9741, 9742, -5358, 0, 0, + 0, 9655, 1193, 8938, 8939, 9659, 0, 0, + 0, 0, 0, 0, 9997, 9998, 9999, 10000, + 10001, 10002, 10003, 10004, 10005, 8785, 3904, 8787, + 268, 4852, 4853, 3903, 1062, 8792, 1063, 1064, + 1065, 2572, 3509, 3509, 3509, 3509, 3509, 3509, + 3509, 3509, 3509, 3509, 3509, 3509, 3509, 3509, + 3509, 3509, 3509, 9608, 9609, 9610, 9611, 9612, + 9613, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 0, 0, 0, 32767, 32767, + -37, 286, -39, -3456, 289, 290, 291, 292, + -5064, 2712, 295, 296, 297, 2713, 2714, 300, + 12297, 0, 4554, 304, 305, 306, 307, 308, + 309, 310, 311, 312, 313, 314, 315, 316, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 32767, 32767, 32767, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 0, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 5071, -9435, 4150, 4151, 32767, + 5075, 5076, -714, 5078, 4156, 5080, 2624, 5082, + 5083, 5084, 5085, 5086, 4164, 2627, 0, 5460, + 0, 0, 4170, 0, 0, 0, 8796, 5098, + 8799, 8800, 5101, 2644, 2644, 13963, 0, -812, + 0, 0, 0, 0, -719, 7744, 0, 0, + -719, 7751, -1044, -1044, -1044, -1044, 0, -1045, + 0, 0, 8576, 0, 2734, 0, 0, 0, + 0, 0, 0, 0, 0, 4199, 8829, 8830, + 0, 0, 0, 0, 0, 0, 0, 32767, + 4203, 4204, 4205, 32767, 4206, 4207, 32767, 4208, + 32767, 32767, 5430, 32767, 4210, 32767, 4211, 32767, + 276, 32767, -674, 32767, 4214, -3515, 32767, -3514, + 32767, 32767, -1072, -1072, -1072, -1072, 32767, -1073, + -1073, -1073, -1073, -1073, -1073, -1073, 32767, -1074, + 4229, 4230, 4231, 32767, 4232, 4233, 4234, 4235, + 32767, 4236, 32767, 4237, 4238, 4239, 4240, 4241, + 4242, 4243, 4244, 4245, 4246, 32767, 4247, 4248, + 4249, 4250, 4251, 4252, 4253, 4254, 4255, 4256, + 4257, 4258, 4259, 4260, 4261, 4262, 4263, 32767, + 32767, 32767, 32767, 32767, 4264, 4265, 4266, 32767, + 4267, 4268, 4269, 4270, 4271, 32767, 4272, 4273, + 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, + 4282, 4283, 4284, 4285, 4286, 4287, 4288, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 324, 32767, 325, 32767, 326, 32767, 327, 32767, + 328, 32767, 329, 32767, 330, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, -5512, 32767, 332, 333, -4700, 335, + -5419, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -5753, 32767, -5754, 32767, -5755, -5755, -5755, 32767, + 32767, 32767, -5758, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 343, 32767, -2121, 345, 346, 32767, + 32767, 32767, 347, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, -5826, 32767, -5827, -5827, -5827, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -5725, 32767, -8171, 32767, -6664, -5727, 32767, 32767, + 356, 357, -5638, -5638, -5638, -5638, -5638, -5638, + -5638, 365, 366, 32767, 32767, 32767, 32767, 32767, + 32767, 367, 32767, 32767, 32767, 32767, 32767, 447, + 3075, -2384, 3077, 3078, 32767, 3079, 3080, 3081, + -5714, -2015, -5715, -5715, -2015, 443, 444, -10874, + 3090, 3903, 3092, 3093, 3094, 3095, 3815, -4647, + 3098, 3099, 3819, -4650, 4146, 4147, 4148, 4149, + 3106, 4152, 3108, 3109, -5466, 3111, 378, 3113, + 3114, 3115, 3116, 3117, 3118, 3119, 3120, 379, + -5708, -5708, 3123, 3124, 3125, 3126, 3127, 3128, + 3129, 32767, 32767, 32767, 32767, 32767, 32767, 382, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 383, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + -5794, -5794, 32767, 32767, -5796, -5796, -5685, -5796, + -5796, -5685, -5685, -5685, -8130, -8129, -6622, -5685, + -5685, -5685, -5685, -5685, -5685, -5685, -5685, -5685, + -5685, -5685, -5685, -5685, -5685, -5685, -5685, 32767, + 413, 414, 415, 416, 417, 418, -5360, -5360, + -5694, 422, 423, 424, -14082,32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 426, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, -5655, -5655, -5655, -5655, 32767, -5656, -5656, + -5656, 32767, -5657, -5657, -5657, -5657, -5657, -5657, + -5657, -5657, 442, 443, 444, 32767, 445, 446, + 32767, 32767, -5668, 448, 449, 450, -14056,32767, + 32767, 452, 453, 454, 32767, 455, 32767, 456, + 32767, 457, 32767, 458, 459, 460, -462, 4290, + -4627, 833, -4627, 4294, -458, -4628, -4628, -4628, + 4168, 470, 4171, 32767, 472, 473, -1984, 9335, + -5439, -5439, 9662, 4305, 4306, 4307, -5347, 3116, + -4628, -4628, -5347, 4313, 4314, 4315, 4316, 4317, + 4318, -5678, -5678, -5678, -5678, -5678, -5678, -5678, + -5678, -5678, -4457, 425, -4457, 495, -521, -521, + 430, 3272, -4457, 3273, 3273, 3273, 1767, 831, + 832, 833, 834, 835, 836, 837, 838, 839, + 840, 841, 842, 843, 844, 845, 846, 847, + -5251, -5251, -5251, -5251, -5251, -5251, 528, 529, + 864, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 531, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 4363, 4364, 4365, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 4366, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 532, -7930, + 4368, -185, 535, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 4370, + 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, + 4379, 4380, 4381, 4382, 4383, 4384, 4385, 4386, + 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, + 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, + 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, + 4411, 4412, 4413, 32767, 32767, 32767, 32767, 4414, + 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 4423, + 4424, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 536, 537, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 0, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 0, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 649, 650, 651, 541, + 653, 654, 544, 656, 657, 547, 548, 549, + 2995, 2995, 1489, 553, 554, 555, 556, 557, + 558, 559, 560, 561, 562, 563, 564, 565, + 566, 567, 568, 569, 570, 571, 572, 573, + 574, 575, 576, 577, 578, 579, 580, 581, + 582, 583, 584, 585, 586, 587, 588, 589, + 590, 591, 592, 593, 594, 595, 596, 597, + 598, 599, 600, 601, 602, 603, 604, 605, + 606, 607, 608, 609, 610, 611, 612, 613, + 614, 615, 616, 617, 618, 619, 620, 621, + 622, 623, 624, 625, 626, 627, 628, 629, + 630, 631, 632, 633, 634, 635, 636, 637, + 638, 639, 640, 641, 642, 643, 644, 645, + 646, 647, 648, 649, 650, 651, 652, 653, + 654, 655, 656, 657, 658, 659, 660, -7114, + 662, 663, 664, 665, 666, 667, 668, 669, + 670, 560, 672, 673, 563, 675, 676, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 0, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767 + }; + + const unsigned char *k = (const unsigned char *) key; + size_t keylen = 4; + uint32 a = 0; + uint32 b = 1; + + while (keylen--) + { + unsigned char c = *k++; + + a = a * 257 + c; + b = b * 127 + c; + } + return h[a % 9955] + h[b % 9955]; +} + +/* Hash lookup information for NFKC_QC */ +static const pg_unicode_norminfo UnicodeNormInfo_NFKC_QC = { + UnicodeNormProps_NFKC_QC, + NFKC_QC_hash_func, + 4977 +}; diff --git a/src/include/common/username.h b/src/include/common/username.h new file mode 100644 index 0000000..b17f560 --- /dev/null +++ b/src/include/common/username.h @@ -0,0 +1,15 @@ +/* + * username.h + * lookup effective username + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/common/username.h + */ +#ifndef USERNAME_H +#define USERNAME_H + +extern const char *get_user_name(char **errstr); +extern const char *get_user_name_or_exit(const char *progname); + +#endif /* USERNAME_H */ diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h new file mode 100644 index 0000000..d155f1b --- /dev/null +++ b/src/include/datatype/timestamp.h @@ -0,0 +1,236 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Timestamp and Interval typedefs and related macros. + * + * Note: this file must be includable in both frontend and backend contexts. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/datatype/timestamp.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATATYPE_TIMESTAMP_H +#define DATATYPE_TIMESTAMP_H + +/* + * Timestamp represents absolute time. + * + * Interval represents delta time. Keep track of months (and years), days, + * and hours/minutes/seconds separately since the elapsed time spanned is + * unknown until instantiated relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + * + * Timestamps, as well as the h/m/s fields of intervals, are stored as + * int64 values with units of microseconds. (Once upon a time they were + * double values with units of seconds.) + * + * TimeOffset and fsec_t are convenience typedefs for temporary variables. + * Do not use fsec_t in values stored on-disk. + * Also, fsec_t is only meant for *fractional* seconds; beware of overflow + * if the value you need to store could be many seconds. + */ + +typedef int64 Timestamp; +typedef int64 TimestampTz; +typedef int64 TimeOffset; +typedef int32 fsec_t; /* fractional seconds (in microseconds) */ + + +/* + * Storage format for type interval. + */ +typedef struct +{ + TimeOffset time; /* all time units other than days, months and + * years */ + int32 day; /* days, after time for alignment */ + int32 month; /* months and years, after time for alignment */ +} Interval; + +/* + * Data structure representing a broken-down interval. + * + * For historical reasons, this is modeled on struct pg_tm for timestamps. + * Unlike the situation for timestamps, there's no magic interpretation + * needed for months or years: they're just zero or not. Note that fields + * can be negative; however, because of the divisions done while converting + * from struct Interval, only tm_mday could be INT_MIN. This is important + * because we may need to negate the values in some code paths. + */ +struct pg_itm +{ + int tm_usec; + int tm_sec; + int tm_min; + int64 tm_hour; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + +/* + * Data structure for decoding intervals. We could just use struct pg_itm, + * but then the requirement for tm_usec to be 64 bits would propagate to + * places where it's not really needed. Also, omitting the fields that + * aren't used during decoding seems like a good error-prevention measure. + */ +struct pg_itm_in +{ + int64 tm_usec; /* needs to be wide */ + int tm_mday; + int tm_mon; + int tm_year; +}; + + +/* Limits on the "precision" option (typmod) for these data types */ +#define MAX_TIMESTAMP_PRECISION 6 +#define MAX_INTERVAL_PRECISION 6 + +/* + * Round off to MAX_TIMESTAMP_PRECISION decimal places. + * Note: this is also used for rounding off intervals. + */ +#define TS_PREC_INV 1000000.0 +#define TSROUND(j) (rint(((double) (j)) * TS_PREC_INV) / TS_PREC_INV) + + +/* + * Assorted constants for datetime-related calculations + */ + +#define DAYS_PER_YEAR 365.25 /* assumes leap year every four years */ +#define MONTHS_PER_YEAR 12 +/* + * DAYS_PER_MONTH is very imprecise. The more accurate value is + * 365.2425/12 = 30.436875, or '30 days 10:29:06'. Right now we only + * return an integral number of days, but someday perhaps we should + * also return a 'time' value to be used as well. ISO 8601 suggests + * 30 days. + */ +#define DAYS_PER_MONTH 30 /* assumes exactly 30 days per month */ +#define HOURS_PER_DAY 24 /* assume no daylight savings time changes */ + +/* + * This doesn't adjust for uneven daylight savings time intervals or leap + * seconds, and it crudely estimates leap years. A more accurate value + * for days per years is 365.2422. + */ +#define SECS_PER_YEAR (36525 * 864) /* avoid floating-point computation */ +#define SECS_PER_DAY 86400 +#define SECS_PER_HOUR 3600 +#define SECS_PER_MINUTE 60 +#define MINS_PER_HOUR 60 + +#define USECS_PER_DAY INT64CONST(86400000000) +#define USECS_PER_HOUR INT64CONST(3600000000) +#define USECS_PER_MINUTE INT64CONST(60000000) +#define USECS_PER_SEC INT64CONST(1000000) + +/* + * We allow numeric timezone offsets up to 15:59:59 either way from Greenwich. + * Currently, the record holders for wackiest offsets in actual use are zones + * Asia/Manila, at -15:56:00 until 1844, and America/Metlakatla, at +15:13:42 + * until 1867. If we were to reject such values we would fail to dump and + * restore old timestamptz values with these zone settings. + */ +#define MAX_TZDISP_HOUR 15 /* maximum allowed hour part */ +#define TZDISP_LIMIT ((MAX_TZDISP_HOUR + 1) * SECS_PER_HOUR) + +/* + * DT_NOBEGIN represents timestamp -infinity; DT_NOEND represents +infinity + */ +#define DT_NOBEGIN PG_INT64_MIN +#define DT_NOEND PG_INT64_MAX + +#define TIMESTAMP_NOBEGIN(j) \ + do {(j) = DT_NOBEGIN;} while (0) + +#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) + +#define TIMESTAMP_NOEND(j) \ + do {(j) = DT_NOEND;} while (0) + +#define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND) + +#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) + + +/* + * Julian date support. + * + * date2j() and j2date() nominally handle the Julian date range 0..INT_MAX, + * or 4714-11-24 BC to 5874898-06-03 AD. In practice, date2j() will work and + * give correct negative Julian dates for dates before 4714-11-24 BC as well. + * We rely on it to do so back to 4714-11-01 BC. Allowing at least one day's + * slop is necessary so that timestamp rotation doesn't produce dates that + * would be rejected on input. For example, '4714-11-24 00:00 GMT BC' is a + * legal timestamptz value, but in zones east of Greenwich it would print as + * sometime in the afternoon of 4714-11-23 BC; if we couldn't process such a + * date we'd have a dump/reload failure. So the idea is for IS_VALID_JULIAN + * to accept a slightly wider range of dates than we really support, and + * then we apply the exact checks in IS_VALID_DATE or IS_VALID_TIMESTAMP, + * after timezone rotation if any. To save a few cycles, we can make + * IS_VALID_JULIAN check only to the month boundary, since its exact cutoffs + * are not very critical in this scheme. + * + * It is correct that JULIAN_MINYEAR is -4713, not -4714; it is defined to + * allow easy comparison to tm_year values, in which we follow the convention + * that tm_year <= 0 represents abs(tm_year)+1 BC. + */ + +#define JULIAN_MINYEAR (-4713) +#define JULIAN_MINMONTH (11) +#define JULIAN_MINDAY (24) +#define JULIAN_MAXYEAR (5874898) +#define JULIAN_MAXMONTH (6) +#define JULIAN_MAXDAY (3) + +#define IS_VALID_JULIAN(y,m,d) \ + (((y) > JULIAN_MINYEAR || \ + ((y) == JULIAN_MINYEAR && ((m) >= JULIAN_MINMONTH))) && \ + ((y) < JULIAN_MAXYEAR || \ + ((y) == JULIAN_MAXYEAR && ((m) < JULIAN_MAXMONTH)))) + +/* Julian-date equivalents of Day 0 in Unix and Postgres reckoning */ +#define UNIX_EPOCH_JDATE 2440588 /* == date2j(1970, 1, 1) */ +#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */ + +/* + * Range limits for dates and timestamps. + * + * We have traditionally allowed Julian day zero as a valid datetime value, + * so that is the lower bound for both dates and timestamps. + * + * The upper limit for dates is 5874897-12-31, which is a bit less than what + * the Julian-date code can allow. For timestamps, the upper limit is + * 294276-12-31. The int64 overflow limit would be a few days later; again, + * leaving some slop avoids worries about corner-case overflow, and provides + * a simpler user-visible definition. + */ + +/* First allowed date, and first disallowed date, in Julian-date form */ +#define DATETIME_MIN_JULIAN (0) +#define DATE_END_JULIAN (2147483494) /* == date2j(JULIAN_MAXYEAR, 1, 1) */ +#define TIMESTAMP_END_JULIAN (109203528) /* == date2j(294277, 1, 1) */ + +/* Timestamp limits */ +#define MIN_TIMESTAMP INT64CONST(-211813488000000000) +/* == (DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ +#define END_TIMESTAMP INT64CONST(9223371331200000000) +/* == (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE) * USECS_PER_DAY */ + +/* Range-check a date (given in Postgres, not Julian, numbering) */ +#define IS_VALID_DATE(d) \ + ((DATETIME_MIN_JULIAN - POSTGRES_EPOCH_JDATE) <= (d) && \ + (d) < (DATE_END_JULIAN - POSTGRES_EPOCH_JDATE)) + +/* Range-check a timestamp */ +#define IS_VALID_TIMESTAMP(t) (MIN_TIMESTAMP <= (t) && (t) < END_TIMESTAMP) + +#endif /* DATATYPE_TIMESTAMP_H */ diff --git a/src/include/executor/execAsync.h b/src/include/executor/execAsync.h new file mode 100644 index 0000000..fc6452f --- /dev/null +++ b/src/include/executor/execAsync.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * execAsync.h + * Support functions for asynchronous execution + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/executor/execAsync.h + *------------------------------------------------------------------------- + */ + +#ifndef EXECASYNC_H +#define EXECASYNC_H + +#include "nodes/execnodes.h" + +extern void ExecAsyncRequest(AsyncRequest *areq); +extern void ExecAsyncConfigureWait(AsyncRequest *areq); +extern void ExecAsyncNotify(AsyncRequest *areq); +extern void ExecAsyncResponse(AsyncRequest *areq); +extern void ExecAsyncRequestDone(AsyncRequest *areq, TupleTableSlot *result); +extern void ExecAsyncRequestPending(AsyncRequest *areq); + +#endif /* EXECASYNC_H */ diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h new file mode 100644 index 0000000..144728e --- /dev/null +++ b/src/include/executor/execExpr.h @@ -0,0 +1,778 @@ +/*------------------------------------------------------------------------- + * + * execExpr.h + * Low level infrastructure related to expression evaluation + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/execExpr.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXEC_EXPR_H +#define EXEC_EXPR_H + +#include "executor/nodeAgg.h" +#include "nodes/execnodes.h" + +/* forward references to avoid circularity */ +struct ExprEvalStep; +struct SubscriptingRefState; +struct ScalarArrayOpExprHashTable; + +/* Bits in ExprState->flags (see also execnodes.h for public flag bits): */ +/* expression's interpreter has been initialized */ +#define EEO_FLAG_INTERPRETER_INITIALIZED (1 << 1) +/* jump-threading is in use */ +#define EEO_FLAG_DIRECT_THREADED (1 << 2) + +/* Typical API for out-of-line evaluation subroutines */ +typedef void (*ExecEvalSubroutine) (ExprState *state, + struct ExprEvalStep *op, + ExprContext *econtext); + +/* API for out-of-line evaluation subroutines returning bool */ +typedef bool (*ExecEvalBoolSubroutine) (ExprState *state, + struct ExprEvalStep *op, + ExprContext *econtext); + +/* ExprEvalSteps that cache a composite type's tupdesc need one of these */ +/* (it fits in-line in some step types, otherwise allocate out-of-line) */ +typedef struct ExprEvalRowtypeCache +{ + /* + * cacheptr points to composite type's TypeCacheEntry if tupdesc_id is not + * 0; or for an anonymous RECORD type, it points directly at the cached + * tupdesc for the type, and tupdesc_id is 0. (We'd use separate fields + * if space were not at a premium.) Initial state is cacheptr == NULL. + */ + void *cacheptr; + uint64 tupdesc_id; /* last-seen tupdesc identifier, or 0 */ +} ExprEvalRowtypeCache; + +/* + * Discriminator for ExprEvalSteps. + * + * Identifies the operation to be executed and which member in the + * ExprEvalStep->d union is valid. + * + * The order of entries needs to be kept in sync with the dispatch_table[] + * array in execExprInterp.c:ExecInterpExpr(). + */ +typedef enum ExprEvalOp +{ + /* entire expression has been evaluated completely, return */ + EEOP_DONE, + + /* apply slot_getsomeattrs on corresponding tuple slot */ + EEOP_INNER_FETCHSOME, + EEOP_OUTER_FETCHSOME, + EEOP_SCAN_FETCHSOME, + + /* compute non-system Var value */ + EEOP_INNER_VAR, + EEOP_OUTER_VAR, + EEOP_SCAN_VAR, + + /* compute system Var value */ + EEOP_INNER_SYSVAR, + EEOP_OUTER_SYSVAR, + EEOP_SCAN_SYSVAR, + + /* compute wholerow Var */ + EEOP_WHOLEROW, + + /* + * Compute non-system Var value, assign it into ExprState's resultslot. + * These are not used if a CheckVarSlotCompatibility() check would be + * needed. + */ + EEOP_ASSIGN_INNER_VAR, + EEOP_ASSIGN_OUTER_VAR, + EEOP_ASSIGN_SCAN_VAR, + + /* assign ExprState's resvalue/resnull to a column of its resultslot */ + EEOP_ASSIGN_TMP, + /* ditto, applying MakeExpandedObjectReadOnly() */ + EEOP_ASSIGN_TMP_MAKE_RO, + + /* evaluate Const value */ + EEOP_CONST, + + /* + * Evaluate function call (including OpExprs etc). For speed, we + * distinguish in the opcode whether the function is strict and/or + * requires usage stats tracking. + */ + EEOP_FUNCEXPR, + EEOP_FUNCEXPR_STRICT, + EEOP_FUNCEXPR_FUSAGE, + EEOP_FUNCEXPR_STRICT_FUSAGE, + + /* + * Evaluate boolean AND expression, one step per subexpression. FIRST/LAST + * subexpressions are special-cased for performance. Since AND always has + * at least two subexpressions, FIRST and LAST never apply to the same + * subexpression. + */ + EEOP_BOOL_AND_STEP_FIRST, + EEOP_BOOL_AND_STEP, + EEOP_BOOL_AND_STEP_LAST, + + /* similarly for boolean OR expression */ + EEOP_BOOL_OR_STEP_FIRST, + EEOP_BOOL_OR_STEP, + EEOP_BOOL_OR_STEP_LAST, + + /* evaluate boolean NOT expression */ + EEOP_BOOL_NOT_STEP, + + /* simplified version of BOOL_AND_STEP for use by ExecQual() */ + EEOP_QUAL, + + /* unconditional jump to another step */ + EEOP_JUMP, + + /* conditional jumps based on current result value */ + EEOP_JUMP_IF_NULL, + EEOP_JUMP_IF_NOT_NULL, + EEOP_JUMP_IF_NOT_TRUE, + + /* perform NULL tests for scalar values */ + EEOP_NULLTEST_ISNULL, + EEOP_NULLTEST_ISNOTNULL, + + /* perform NULL tests for row values */ + EEOP_NULLTEST_ROWISNULL, + EEOP_NULLTEST_ROWISNOTNULL, + + /* evaluate a BooleanTest expression */ + EEOP_BOOLTEST_IS_TRUE, + EEOP_BOOLTEST_IS_NOT_TRUE, + EEOP_BOOLTEST_IS_FALSE, + EEOP_BOOLTEST_IS_NOT_FALSE, + + /* evaluate PARAM_EXEC/EXTERN parameters */ + EEOP_PARAM_EXEC, + EEOP_PARAM_EXTERN, + EEOP_PARAM_CALLBACK, + + /* return CaseTestExpr value */ + EEOP_CASE_TESTVAL, + + /* apply MakeExpandedObjectReadOnly() to target value */ + EEOP_MAKE_READONLY, + + /* evaluate assorted special-purpose expression types */ + EEOP_IOCOERCE, + EEOP_DISTINCT, + EEOP_NOT_DISTINCT, + EEOP_NULLIF, + EEOP_SQLVALUEFUNCTION, + EEOP_CURRENTOFEXPR, + EEOP_NEXTVALUEEXPR, + EEOP_ARRAYEXPR, + EEOP_ARRAYCOERCE, + EEOP_ROW, + + /* + * Compare two individual elements of each of two compared ROW() + * expressions. Skip to ROWCOMPARE_FINAL if elements are not equal. + */ + EEOP_ROWCOMPARE_STEP, + + /* evaluate boolean value based on previous ROWCOMPARE_STEP operations */ + EEOP_ROWCOMPARE_FINAL, + + /* evaluate GREATEST() or LEAST() */ + EEOP_MINMAX, + + /* evaluate FieldSelect expression */ + EEOP_FIELDSELECT, + + /* + * Deform tuple before evaluating new values for individual fields in a + * FieldStore expression. + */ + EEOP_FIELDSTORE_DEFORM, + + /* + * Form the new tuple for a FieldStore expression. Individual fields will + * have been evaluated into columns of the tuple deformed by the preceding + * DEFORM step. + */ + EEOP_FIELDSTORE_FORM, + + /* Process container subscripts; possibly short-circuit result to NULL */ + EEOP_SBSREF_SUBSCRIPTS, + + /* + * Compute old container element/slice when a SubscriptingRef assignment + * expression contains SubscriptingRef/FieldStore subexpressions. Value is + * accessed using the CaseTest mechanism. + */ + EEOP_SBSREF_OLD, + + /* compute new value for SubscriptingRef assignment expression */ + EEOP_SBSREF_ASSIGN, + + /* compute element/slice for SubscriptingRef fetch expression */ + EEOP_SBSREF_FETCH, + + /* evaluate value for CoerceToDomainValue */ + EEOP_DOMAIN_TESTVAL, + + /* evaluate a domain's NOT NULL constraint */ + EEOP_DOMAIN_NOTNULL, + + /* evaluate a single domain CHECK constraint */ + EEOP_DOMAIN_CHECK, + + /* evaluate assorted special-purpose expression types */ + EEOP_CONVERT_ROWTYPE, + EEOP_SCALARARRAYOP, + EEOP_HASHED_SCALARARRAYOP, + EEOP_XMLEXPR, + EEOP_AGGREF, + EEOP_GROUPING_FUNC, + EEOP_WINDOW_FUNC, + EEOP_SUBPLAN, + + /* aggregation related nodes */ + EEOP_AGG_STRICT_DESERIALIZE, + EEOP_AGG_DESERIALIZE, + EEOP_AGG_STRICT_INPUT_CHECK_ARGS, + EEOP_AGG_STRICT_INPUT_CHECK_NULLS, + EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, + EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, + EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, + EEOP_AGG_PLAIN_TRANS_BYVAL, + EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, + EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, + EEOP_AGG_PLAIN_TRANS_BYREF, + EEOP_AGG_ORDERED_TRANS_DATUM, + EEOP_AGG_ORDERED_TRANS_TUPLE, + + /* non-existent operation, used e.g. to check array lengths */ + EEOP_LAST +} ExprEvalOp; + + +typedef struct ExprEvalStep +{ + /* + * Instruction to be executed. During instruction preparation this is an + * enum ExprEvalOp, but later it can be changed to some other type, e.g. a + * pointer for computed goto (that's why it's an intptr_t). + */ + intptr_t opcode; + + /* where to store the result of this step */ + Datum *resvalue; + bool *resnull; + + /* + * Inline data for the operation. Inline data is faster to access, but + * also bloats the size of all instructions. The union should be kept to + * no more than 40 bytes on 64-bit systems (so that the entire struct is + * no more than 64 bytes, a single cacheline on common systems). + */ + union + { + /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */ + struct + { + /* attribute number up to which to fetch (inclusive) */ + int last_var; + /* will the type of slot be the same for every invocation */ + bool fixed; + /* tuple descriptor, if known */ + TupleDesc known_desc; + /* type of slot, can only be relied upon if fixed is set */ + const TupleTableSlotOps *kind; + } fetch; + + /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */ + struct + { + /* attnum is attr number - 1 for regular VAR ... */ + /* but it's just the normal (negative) attr number for SYSVAR */ + int attnum; + Oid vartype; /* type OID of variable */ + } var; + + /* for EEOP_WHOLEROW */ + struct + { + Var *var; /* original Var node in plan tree */ + bool first; /* first time through, need to initialize? */ + bool slow; /* need runtime check for nulls? */ + TupleDesc tupdesc; /* descriptor for resulting tuples */ + JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */ + } wholerow; + + /* for EEOP_ASSIGN_*_VAR */ + struct + { + /* target index in ExprState->resultslot->tts_values/nulls */ + int resultnum; + /* source attribute number - 1 */ + int attnum; + } assign_var; + + /* for EEOP_ASSIGN_TMP[_MAKE_RO] */ + struct + { + /* target index in ExprState->resultslot->tts_values/nulls */ + int resultnum; + } assign_tmp; + + /* for EEOP_CONST */ + struct + { + /* constant's value */ + Datum value; + bool isnull; + } constval; + + /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */ + struct + { + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction fn_addr; /* actual call address */ + int nargs; /* number of arguments */ + } func; + + /* for EEOP_BOOL_*_STEP */ + struct + { + bool *anynull; /* track if any input was NULL */ + int jumpdone; /* jump here if result determined */ + } boolexpr; + + /* for EEOP_QUAL */ + struct + { + int jumpdone; /* jump here on false or null */ + } qualexpr; + + /* for EEOP_JUMP[_CONDITION] */ + struct + { + int jumpdone; /* target instruction's index */ + } jump; + + /* for EEOP_NULLTEST_ROWIS[NOT]NULL */ + struct + { + /* cached descriptor for composite type - filled at runtime */ + ExprEvalRowtypeCache rowcache; + } nulltest_row; + + /* for EEOP_PARAM_EXEC/EXTERN */ + struct + { + int paramid; /* numeric ID for parameter */ + Oid paramtype; /* OID of parameter's datatype */ + } param; + + /* for EEOP_PARAM_CALLBACK */ + struct + { + ExecEvalSubroutine paramfunc; /* add-on evaluation subroutine */ + void *paramarg; /* private data for same */ + int paramid; /* numeric ID for parameter */ + Oid paramtype; /* OID of parameter's datatype */ + } cparam; + + /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */ + struct + { + Datum *value; /* value to return */ + bool *isnull; + } casetest; + + /* for EEOP_MAKE_READONLY */ + struct + { + Datum *value; /* value to coerce to read-only */ + bool *isnull; + } make_readonly; + + /* for EEOP_IOCOERCE */ + struct + { + /* lookup and call info for source type's output function */ + FmgrInfo *finfo_out; + FunctionCallInfo fcinfo_data_out; + /* lookup and call info for result type's input function */ + FmgrInfo *finfo_in; + FunctionCallInfo fcinfo_data_in; + } iocoerce; + + /* for EEOP_SQLVALUEFUNCTION */ + struct + { + SQLValueFunction *svf; + } sqlvaluefunction; + + /* for EEOP_NEXTVALUEEXPR */ + struct + { + Oid seqid; + Oid seqtypid; + } nextvalueexpr; + + /* for EEOP_ARRAYEXPR */ + struct + { + Datum *elemvalues; /* element values get stored here */ + bool *elemnulls; + int nelems; /* length of the above arrays */ + Oid elemtype; /* array element type */ + int16 elemlength; /* typlen of the array element type */ + bool elembyval; /* is the element type pass-by-value? */ + char elemalign; /* typalign of the element type */ + bool multidims; /* is array expression multi-D? */ + } arrayexpr; + + /* for EEOP_ARRAYCOERCE */ + struct + { + ExprState *elemexprstate; /* null if no per-element work */ + Oid resultelemtype; /* element type of result array */ + struct ArrayMapState *amstate; /* workspace for array_map */ + } arraycoerce; + + /* for EEOP_ROW */ + struct + { + TupleDesc tupdesc; /* descriptor for result tuples */ + /* workspace for the values constituting the row: */ + Datum *elemvalues; + bool *elemnulls; + } row; + + /* for EEOP_ROWCOMPARE_STEP */ + struct + { + /* lookup and call data for column comparison function */ + FmgrInfo *finfo; + FunctionCallInfo fcinfo_data; + PGFunction fn_addr; + /* target for comparison resulting in NULL */ + int jumpnull; + /* target for comparison yielding inequality */ + int jumpdone; + } rowcompare_step; + + /* for EEOP_ROWCOMPARE_FINAL */ + struct + { + RowCompareType rctype; + } rowcompare_final; + + /* for EEOP_MINMAX */ + struct + { + /* workspace for argument values */ + Datum *values; + bool *nulls; + int nelems; + /* is it GREATEST or LEAST? */ + MinMaxOp op; + /* lookup and call data for comparison function */ + FmgrInfo *finfo; + FunctionCallInfo fcinfo_data; + } minmax; + + /* for EEOP_FIELDSELECT */ + struct + { + AttrNumber fieldnum; /* field number to extract */ + Oid resulttype; /* field's type */ + /* cached descriptor for composite type - filled at runtime */ + ExprEvalRowtypeCache rowcache; + } fieldselect; + + /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */ + struct + { + /* original expression node */ + FieldStore *fstore; + + /* cached descriptor for composite type - filled at runtime */ + /* note that a DEFORM and FORM pair share the same cache */ + ExprEvalRowtypeCache *rowcache; + + /* workspace for column values */ + Datum *values; + bool *nulls; + int ncolumns; + } fieldstore; + + /* for EEOP_SBSREF_SUBSCRIPTS */ + struct + { + ExecEvalBoolSubroutine subscriptfunc; /* evaluation subroutine */ + /* too big to have inline */ + struct SubscriptingRefState *state; + int jumpdone; /* jump here on null */ + } sbsref_subscript; + + /* for EEOP_SBSREF_OLD / ASSIGN / FETCH */ + struct + { + ExecEvalSubroutine subscriptfunc; /* evaluation subroutine */ + /* too big to have inline */ + struct SubscriptingRefState *state; + } sbsref; + + /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */ + struct + { + /* name of constraint */ + char *constraintname; + /* where the result of a CHECK constraint will be stored */ + Datum *checkvalue; + bool *checknull; + /* OID of domain type */ + Oid resulttype; + } domaincheck; + + /* for EEOP_CONVERT_ROWTYPE */ + struct + { + Oid inputtype; /* input composite type */ + Oid outputtype; /* output composite type */ + /* these three fields are filled at runtime: */ + ExprEvalRowtypeCache *incache; /* cache for input type */ + ExprEvalRowtypeCache *outcache; /* cache for output type */ + TupleConversionMap *map; /* column mapping */ + } convert_rowtype; + + /* for EEOP_SCALARARRAYOP */ + struct + { + /* element_type/typlen/typbyval/typalign are filled at runtime */ + Oid element_type; /* InvalidOid if not yet filled */ + bool useOr; /* use OR or AND semantics? */ + int16 typlen; /* array element type storage info */ + bool typbyval; + char typalign; + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction fn_addr; /* actual call address */ + } scalararrayop; + + /* for EEOP_HASHED_SCALARARRAYOP */ + struct + { + bool has_nulls; + bool inclause; /* true for IN and false for NOT IN */ + struct ScalarArrayOpExprHashTable *elements_tab; + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + ScalarArrayOpExpr *saop; + } hashedscalararrayop; + + /* for EEOP_XMLEXPR */ + struct + { + XmlExpr *xexpr; /* original expression node */ + /* workspace for evaluating named args, if any */ + Datum *named_argvalue; + bool *named_argnull; + /* workspace for evaluating unnamed args, if any */ + Datum *argvalue; + bool *argnull; + } xmlexpr; + + /* for EEOP_AGGREF */ + struct + { + int aggno; + } aggref; + + /* for EEOP_GROUPING_FUNC */ + struct + { + List *clauses; /* integer list of column numbers */ + } grouping_func; + + /* for EEOP_WINDOW_FUNC */ + struct + { + /* out-of-line state, modified by nodeWindowAgg.c */ + WindowFuncExprState *wfstate; + } window_func; + + /* for EEOP_SUBPLAN */ + struct + { + /* out-of-line state, created by nodeSubplan.c */ + SubPlanState *sstate; + } subplan; + + /* for EEOP_AGG_*DESERIALIZE */ + struct + { + FunctionCallInfo fcinfo_data; + int jumpnull; + } agg_deserialize; + + /* for EEOP_AGG_STRICT_INPUT_CHECK_NULLS / STRICT_INPUT_CHECK_ARGS */ + struct + { + /* + * For EEOP_AGG_STRICT_INPUT_CHECK_ARGS args contains pointers to + * the NullableDatums that need to be checked for NULLs. + * + * For EEOP_AGG_STRICT_INPUT_CHECK_NULLS nulls contains pointers + * to booleans that need to be checked for NULLs. + * + * Both cases currently need to exist because sometimes the + * to-be-checked nulls are in TupleTableSlot.isnull array, and + * sometimes in FunctionCallInfoBaseData.args[i].isnull. + */ + NullableDatum *args; + bool *nulls; + int nargs; + int jumpnull; + } agg_strict_input_check; + + /* for EEOP_AGG_PLAIN_PERGROUP_NULLCHECK */ + struct + { + int setoff; + int jumpnull; + } agg_plain_pergroup_nullcheck; + + /* for EEOP_AGG_PLAIN_TRANS_[INIT_][STRICT_]{BYVAL,BYREF} */ + /* for EEOP_AGG_ORDERED_TRANS_{DATUM,TUPLE} */ + struct + { + AggStatePerTrans pertrans; + ExprContext *aggcontext; + int setno; + int transno; + int setoff; + } agg_trans; + } d; +} ExprEvalStep; + + +/* Non-inline data for container operations */ +typedef struct SubscriptingRefState +{ + bool isassignment; /* is it assignment, or just fetch? */ + + /* workspace for type-specific subscripting code */ + void *workspace; + + /* numupper and upperprovided[] are filled at expression compile time */ + /* at runtime, subscripts are computed in upperindex[]/upperindexnull[] */ + int numupper; + bool *upperprovided; /* indicates if this position is supplied */ + Datum *upperindex; + bool *upperindexnull; + + /* similarly for lower indexes, if any */ + int numlower; + bool *lowerprovided; + Datum *lowerindex; + bool *lowerindexnull; + + /* for assignment, new value to assign is evaluated into here */ + Datum replacevalue; + bool replacenull; + + /* if we have a nested assignment, sbs_fetch_old puts old value here */ + Datum prevvalue; + bool prevnull; +} SubscriptingRefState; + +/* Execution step methods used for SubscriptingRef */ +typedef struct SubscriptExecSteps +{ + /* See nodes/subscripting.h for more detail about these */ + ExecEvalBoolSubroutine sbs_check_subscripts; /* process subscripts */ + ExecEvalSubroutine sbs_fetch; /* fetch an element */ + ExecEvalSubroutine sbs_assign; /* assign to an element */ + ExecEvalSubroutine sbs_fetch_old; /* fetch old value for assignment */ +} SubscriptExecSteps; + + +/* functions in execExpr.c */ +extern void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s); + +/* functions in execExprInterp.c */ +extern void ExecReadyInterpretedExpr(ExprState *state); +extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op); + +extern Datum ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull); +extern void CheckExprStillValid(ExprState *state, ExprContext *econtext); + +/* + * Non fast-path execution functions. These are externs instead of statics in + * execExprInterp.c, because that allows them to be used by other methods of + * expression evaluation, reducing code duplication. + */ +extern void ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op); +extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op); +extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op); +extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op); +extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalRow(ExprState *state, ExprEvalStep *op); +extern void ExecEvalMinMax(ExprState *state, ExprEvalStep *op); +extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op); +extern void ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op); +extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op); +extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op); +extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op); +extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op, + ExprContext *econtext, TupleTableSlot *slot); + +extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup, + ExprContext *aggcontext); +extern Datum ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans, + Datum newValue, bool newValueIsNull, + Datum oldValue, bool oldValueIsNull); +extern void ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); +extern void ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); + +#endif /* EXEC_EXPR_H */ diff --git a/src/include/executor/execParallel.h b/src/include/executor/execParallel.h new file mode 100644 index 0000000..3a1b113 --- /dev/null +++ b/src/include/executor/execParallel.h @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------- + * execParallel.h + * POSTGRES parallel execution interface + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/executor/execParallel.h + *-------------------------------------------------------------------- + */ + +#ifndef EXECPARALLEL_H +#define EXECPARALLEL_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" +#include "nodes/parsenodes.h" +#include "nodes/plannodes.h" +#include "utils/dsa.h" + +typedef struct SharedExecutorInstrumentation SharedExecutorInstrumentation; + +typedef struct ParallelExecutorInfo +{ + PlanState *planstate; /* plan subtree we're running in parallel */ + ParallelContext *pcxt; /* parallel context we're using */ + BufferUsage *buffer_usage; /* points to bufusage area in DSM */ + WalUsage *wal_usage; /* walusage area in DSM */ + SharedExecutorInstrumentation *instrumentation; /* optional */ + struct SharedJitInstrumentation *jit_instrumentation; /* optional */ + dsa_area *area; /* points to DSA area in DSM */ + dsa_pointer param_exec; /* serialized PARAM_EXEC parameters */ + bool finished; /* set true by ExecParallelFinish */ + /* These two arrays have pcxt->nworkers_launched entries: */ + shm_mq_handle **tqueue; /* tuple queues for worker output */ + struct TupleQueueReader **reader; /* tuple reader/writer support */ +} ParallelExecutorInfo; + +extern ParallelExecutorInfo *ExecInitParallelPlan(PlanState *planstate, + EState *estate, Bitmapset *sendParam, int nworkers, + int64 tuples_needed); +extern void ExecParallelCreateReaders(ParallelExecutorInfo *pei); +extern void ExecParallelFinish(ParallelExecutorInfo *pei); +extern void ExecParallelCleanup(ParallelExecutorInfo *pei); +extern void ExecParallelReinitialize(PlanState *planstate, + ParallelExecutorInfo *pei, Bitmapset *sendParam); + +extern void ParallelQueryMain(dsm_segment *seg, shm_toc *toc); + +#endif /* EXECPARALLEL_H */ diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h new file mode 100644 index 0000000..708435e --- /dev/null +++ b/src/include/executor/execPartition.h @@ -0,0 +1,131 @@ +/*-------------------------------------------------------------------- + * execPartition.h + * POSTGRES partitioning executor interface + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/executor/execPartition.h + *-------------------------------------------------------------------- + */ + +#ifndef EXECPARTITION_H +#define EXECPARTITION_H + +#include "nodes/execnodes.h" +#include "nodes/parsenodes.h" +#include "nodes/plannodes.h" +#include "partitioning/partprune.h" + +/* See execPartition.c for the definitions. */ +typedef struct PartitionDispatchData *PartitionDispatch; +typedef struct PartitionTupleRouting PartitionTupleRouting; + +extern PartitionTupleRouting *ExecSetupPartitionTupleRouting(EState *estate, + Relation rel); +extern ResultRelInfo *ExecFindPartition(ModifyTableState *mtstate, + ResultRelInfo *rootResultRelInfo, + PartitionTupleRouting *proute, + TupleTableSlot *slot, + EState *estate); +extern void ExecCleanupTupleRouting(ModifyTableState *mtstate, + PartitionTupleRouting *proute); + + +/* + * PartitionedRelPruningData - Per-partitioned-table data for run-time pruning + * of partitions. For a multilevel partitioned table, we have one of these + * for the topmost partition plus one for each non-leaf child partition. + * + * subplan_map[] and subpart_map[] have the same definitions as in + * PartitionedRelPruneInfo (see plannodes.h); though note that here, + * subpart_map contains indexes into PartitionPruningData.partrelprunedata[]. + * + * nparts Length of subplan_map[] and subpart_map[]. + * subplan_map Subplan index by partition index, or -1. + * subpart_map Subpart index by partition index, or -1. + * present_parts A Bitmapset of the partition indexes that we + * have subplans or subparts for. + * initial_pruning_steps List of PartitionPruneSteps used to + * perform executor startup pruning. + * exec_pruning_steps List of PartitionPruneSteps used to + * perform per-scan pruning. + * initial_context If initial_pruning_steps isn't NIL, contains + * the details needed to execute those steps. + * exec_context If exec_pruning_steps isn't NIL, contains + * the details needed to execute those steps. + */ +typedef struct PartitionedRelPruningData +{ + int nparts; + int *subplan_map; + int *subpart_map; + Bitmapset *present_parts; + List *initial_pruning_steps; + List *exec_pruning_steps; + PartitionPruneContext initial_context; + PartitionPruneContext exec_context; +} PartitionedRelPruningData; + +/* + * PartitionPruningData - Holds all the run-time pruning information for + * a single partitioning hierarchy containing one or more partitions. + * partrelprunedata[] is an array ordered such that parents appear before + * their children; in particular, the first entry is the topmost partition, + * which was actually named in the SQL query. + */ +typedef struct PartitionPruningData +{ + int num_partrelprunedata; /* number of array entries */ + PartitionedRelPruningData partrelprunedata[FLEXIBLE_ARRAY_MEMBER]; +} PartitionPruningData; + +/* + * PartitionPruneState - State object required for plan nodes to perform + * run-time partition pruning. + * + * This struct can be attached to plan types which support arbitrary Lists of + * subplans containing partitions, to allow subplans to be eliminated due to + * the clauses being unable to match to any tuple that the subplan could + * possibly produce. + * + * execparamids Contains paramids of PARAM_EXEC Params found within + * any of the partprunedata structs. Pruning must be + * done again each time the value of one of these + * parameters changes. + * other_subplans Contains indexes of subplans that don't belong to any + * "partprunedata", e.g UNION ALL children that are not + * partitioned tables, or a partitioned table that the + * planner deemed run-time pruning to be useless for. + * These must not be pruned. + * prune_context A short-lived memory context in which to execute the + * partition pruning functions. + * do_initial_prune true if pruning should be performed during executor + * startup (at any hierarchy level). + * do_exec_prune true if pruning should be performed during + * executor run (at any hierarchy level). + * num_partprunedata Number of items in "partprunedata" array. + * partprunedata Array of PartitionPruningData pointers for the plan's + * partitioned relation(s), one for each partitioning + * hierarchy that requires run-time pruning. + */ +typedef struct PartitionPruneState +{ + Bitmapset *execparamids; + Bitmapset *other_subplans; + MemoryContext prune_context; + bool do_initial_prune; + bool do_exec_prune; + int num_partprunedata; + PartitionPruningData *partprunedata[FLEXIBLE_ARRAY_MEMBER]; +} PartitionPruneState; + +extern PartitionPruneState *ExecInitPartitionPruning(PlanState *planstate, + int n_total_subplans, + PartitionPruneInfo *pruneinfo, + Bitmapset **initially_valid_subplans); +extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate, + bool initial_prune); + +#endif /* EXECPARTITION_H */ diff --git a/src/include/executor/execdebug.h b/src/include/executor/execdebug.h new file mode 100644 index 0000000..8cb8b8c --- /dev/null +++ b/src/include/executor/execdebug.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- + * + * execdebug.h + * #defines governing debugging behaviour in the executor + * + * XXX this is all pretty old and crufty. Newer code tends to use elog() + * for debug printouts, because that's more flexible than printf(). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/execdebug.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXECDEBUG_H +#define EXECDEBUG_H + +#include "executor/executor.h" +#include "nodes/print.h" + +/* ---------------------------------------------------------------- + * debugging defines. + * + * If you want certain debugging behaviour, then #define + * the variable to 1. No need to explicitly #undef by default, + * since we can use -D compiler options to enable features. + * - thomas 1999-02-20 + * ---------------------------------------------------------------- + */ + +/* ---------------- + * EXEC_NESTLOOPDEBUG is a flag which turns on debugging of the + * nest loop node by NL_printf() and ENL_printf() in nodeNestloop.c + * ---------------- +#undef EXEC_NESTLOOPDEBUG + */ + +/* ---------------- + * EXEC_SORTDEBUG is a flag which turns on debugging of + * the ExecSort() stuff by SO_printf() in nodeSort.c + * ---------------- +#undef EXEC_SORTDEBUG + */ + +/* ---------------- + * EXEC_MERGEJOINDEBUG is a flag which turns on debugging of + * the ExecMergeJoin() stuff by MJ_printf() in nodeMergejoin.c + * ---------------- +#undef EXEC_MERGEJOINDEBUG + */ + +/* ---------------------------------------------------------------- + * #defines controlled by above definitions + * + * Note: most of these are "incomplete" because I didn't + * need the ones not defined. More should be added + * only as necessary -cim 10/26/89 + * ---------------------------------------------------------------- + */ +#define T_OR_F(b) ((b) ? "true" : "false") +#define NULL_OR_TUPLE(slot) (TupIsNull(slot) ? "null" : "a tuple") + +/* ---------------- + * nest loop debugging defines + * ---------------- + */ +#ifdef EXEC_NESTLOOPDEBUG +#define NL_nodeDisplay(l) nodeDisplay(l) +#define NL_printf(s) printf(s) +#define NL1_printf(s, a) printf(s, a) +#define ENL1_printf(message) printf("ExecNestLoop: %s\n", message) +#else +#define NL_nodeDisplay(l) +#define NL_printf(s) +#define NL1_printf(s, a) +#define ENL1_printf(message) +#endif /* EXEC_NESTLOOPDEBUG */ + +/* ---------------- + * sort node debugging defines + * ---------------- + */ +#ifdef EXEC_SORTDEBUG +#define SO_nodeDisplay(l) nodeDisplay(l) +#define SO_printf(s) printf(s) +#define SO1_printf(s, p) printf(s, p) +#define SO2_printf(s, p1, p2) printf(s, p1, p2) +#else +#define SO_nodeDisplay(l) +#define SO_printf(s) +#define SO1_printf(s, p) +#define SO2_printf(s, p1, p2) +#endif /* EXEC_SORTDEBUG */ + +/* ---------------- + * merge join debugging defines + * ---------------- + */ +#ifdef EXEC_MERGEJOINDEBUG + +#define MJ_nodeDisplay(l) nodeDisplay(l) +#define MJ_printf(s) printf(s) +#define MJ1_printf(s, p) printf(s, p) +#define MJ2_printf(s, p1, p2) printf(s, p1, p2) +#define MJ_debugtup(slot) debugtup(slot, NULL) +#define MJ_dump(state) ExecMergeTupleDump(state) +#define MJ_DEBUG_COMPARE(res) \ + MJ1_printf(" MJCompare() returns %d\n", (res)) +#define MJ_DEBUG_QUAL(clause, res) \ + MJ2_printf(" ExecQual(%s, econtext) returns %s\n", \ + CppAsString(clause), T_OR_F(res)) +#define MJ_DEBUG_PROC_NODE(slot) \ + MJ2_printf(" %s = ExecProcNode(...) returns %s\n", \ + CppAsString(slot), NULL_OR_TUPLE(slot)) +#else + +#define MJ_nodeDisplay(l) +#define MJ_printf(s) +#define MJ1_printf(s, p) +#define MJ2_printf(s, p1, p2) +#define MJ_debugtup(slot) +#define MJ_dump(state) +#define MJ_DEBUG_COMPARE(res) +#define MJ_DEBUG_QUAL(clause, res) +#define MJ_DEBUG_PROC_NODE(slot) +#endif /* EXEC_MERGEJOINDEBUG */ + +#endif /* EXECDEBUG_H */ diff --git a/src/include/executor/execdesc.h b/src/include/executor/execdesc.h new file mode 100644 index 0000000..e79e2c0 --- /dev/null +++ b/src/include/executor/execdesc.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- + * + * execdesc.h + * plan and query descriptor accessor macros used by the executor + * and related modules. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/execdesc.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXECDESC_H +#define EXECDESC_H + +#include "nodes/execnodes.h" +#include "tcop/dest.h" + + +/* ---------------- + * query descriptor: + * + * a QueryDesc encapsulates everything that the executor + * needs to execute the query. + * + * For the convenience of SQL-language functions, we also support QueryDescs + * containing utility statements; these must not be passed to the executor + * however. + * --------------------- + */ +typedef struct QueryDesc +{ + /* These fields are provided by CreateQueryDesc */ + CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */ + PlannedStmt *plannedstmt; /* planner's output (could be utility, too) */ + const char *sourceText; /* source text of the query */ + Snapshot snapshot; /* snapshot to use for query */ + Snapshot crosscheck_snapshot; /* crosscheck for RI update/delete */ + DestReceiver *dest; /* the destination for tuple output */ + ParamListInfo params; /* param values being passed in */ + QueryEnvironment *queryEnv; /* query environment passed in */ + int instrument_options; /* OR of InstrumentOption flags */ + + /* These fields are set by ExecutorStart */ + TupleDesc tupDesc; /* descriptor for result tuples */ + EState *estate; /* executor's query-wide state */ + PlanState *planstate; /* tree of per-plan-node state */ + + /* This field is set by ExecutorRun */ + bool already_executed; /* true if previously executed */ + + /* This is always set NULL by the core system, but plugins can change it */ + struct Instrumentation *totaltime; /* total time spent in ExecutorRun */ +} QueryDesc; + +/* in pquery.c */ +extern QueryDesc *CreateQueryDesc(PlannedStmt *plannedstmt, + const char *sourceText, + Snapshot snapshot, + Snapshot crosscheck_snapshot, + DestReceiver *dest, + ParamListInfo params, + QueryEnvironment *queryEnv, + int instrument_options); + +extern void FreeQueryDesc(QueryDesc *qdesc); + +#endif /* EXECDESC_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h new file mode 100644 index 0000000..7cd9b2f --- /dev/null +++ b/src/include/executor/executor.h @@ -0,0 +1,666 @@ +/*------------------------------------------------------------------------- + * + * executor.h + * support for the POSTGRES executor module + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/executor.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXECUTOR_H +#define EXECUTOR_H + +#include "executor/execdesc.h" +#include "fmgr.h" +#include "nodes/lockoptions.h" +#include "nodes/parsenodes.h" +#include "utils/memutils.h" + + +/* + * The "eflags" argument to ExecutorStart and the various ExecInitNode + * routines is a bitwise OR of the following flag bits, which tell the + * called plan node what to expect. Note that the flags will get modified + * as they are passed down the plan tree, since an upper node may require + * functionality in its subnode not demanded of the plan as a whole + * (example: MergeJoin requires mark/restore capability in its inner input), + * or an upper node may shield its input from some functionality requirement + * (example: Materialize shields its input from needing to do backward scan). + * + * EXPLAIN_ONLY indicates that the plan tree is being initialized just so + * EXPLAIN can print it out; it will not be run. Hence, no side-effects + * of startup should occur. However, error checks (such as permission checks) + * should be performed. + * + * REWIND indicates that the plan node should try to efficiently support + * rescans without parameter changes. (Nodes must support ExecReScan calls + * in any case, but if this flag was not given, they are at liberty to do it + * through complete recalculation. Note that a parameter change forces a + * full recalculation in any case.) + * + * BACKWARD indicates that the plan node must respect the es_direction flag. + * When this is not passed, the plan node will only be run forwards. + * + * MARK indicates that the plan node must support Mark/Restore calls. + * When this is not passed, no Mark/Restore will occur. + * + * SKIP_TRIGGERS tells ExecutorStart/ExecutorFinish to skip calling + * AfterTriggerBeginQuery/AfterTriggerEndQuery. This does not necessarily + * mean that the plan can't queue any AFTER triggers; just that the caller + * is responsible for there being a trigger context for them to be queued in. + */ +#define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no ANALYZE */ +#define EXEC_FLAG_REWIND 0x0002 /* need efficient rescan */ +#define EXEC_FLAG_BACKWARD 0x0004 /* need backward scan */ +#define EXEC_FLAG_MARK 0x0008 /* need mark/restore */ +#define EXEC_FLAG_SKIP_TRIGGERS 0x0010 /* skip AfterTrigger calls */ +#define EXEC_FLAG_WITH_NO_DATA 0x0020 /* rel scannability doesn't matter */ + + +/* Hook for plugins to get control in ExecutorStart() */ +typedef void (*ExecutorStart_hook_type) (QueryDesc *queryDesc, int eflags); +extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook; + +/* Hook for plugins to get control in ExecutorRun() */ +typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc, + ScanDirection direction, + uint64 count, + bool execute_once); +extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook; + +/* Hook for plugins to get control in ExecutorFinish() */ +typedef void (*ExecutorFinish_hook_type) (QueryDesc *queryDesc); +extern PGDLLIMPORT ExecutorFinish_hook_type ExecutorFinish_hook; + +/* Hook for plugins to get control in ExecutorEnd() */ +typedef void (*ExecutorEnd_hook_type) (QueryDesc *queryDesc); +extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook; + +/* Hook for plugins to get control in ExecCheckRTPerms() */ +typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool); +extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; + + +/* + * prototypes from functions in execAmi.c + */ +struct Path; /* avoid including pathnodes.h here */ + +extern void ExecReScan(PlanState *node); +extern void ExecMarkPos(PlanState *node); +extern void ExecRestrPos(PlanState *node); +extern bool ExecSupportsMarkRestore(struct Path *pathnode); +extern bool ExecSupportsBackwardScan(Plan *node); +extern bool ExecMaterializesOutput(NodeTag plantype); + +/* + * prototypes from functions in execCurrent.c + */ +extern bool execCurrentOf(CurrentOfExpr *cexpr, + ExprContext *econtext, + Oid table_oid, + ItemPointer current_tid); + +/* + * prototypes from functions in execGrouping.c + */ +extern ExprState *execTuplesMatchPrepare(TupleDesc desc, + int numCols, + const AttrNumber *keyColIdx, + const Oid *eqOperators, + const Oid *collations, + PlanState *parent); +extern void execTuplesHashPrepare(int numCols, + const Oid *eqOperators, + Oid **eqFuncOids, + FmgrInfo **hashFunctions); +extern TupleHashTable BuildTupleHashTable(PlanState *parent, + TupleDesc inputDesc, + int numCols, AttrNumber *keyColIdx, + const Oid *eqfuncoids, + FmgrInfo *hashfunctions, + Oid *collations, + long nbuckets, Size additionalsize, + MemoryContext tablecxt, + MemoryContext tempcxt, bool use_variable_hash_iv); +extern TupleHashTable BuildTupleHashTableExt(PlanState *parent, + TupleDesc inputDesc, + int numCols, AttrNumber *keyColIdx, + const Oid *eqfuncoids, + FmgrInfo *hashfunctions, + Oid *collations, + long nbuckets, Size additionalsize, + MemoryContext metacxt, + MemoryContext tablecxt, + MemoryContext tempcxt, bool use_variable_hash_iv); +extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable, + TupleTableSlot *slot, + bool *isnew, uint32 *hash); +extern uint32 TupleHashTableHash(TupleHashTable hashtable, + TupleTableSlot *slot); +extern TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, + TupleTableSlot *slot, + bool *isnew, uint32 hash); +extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, + TupleTableSlot *slot, + ExprState *eqcomp, + FmgrInfo *hashfunctions); +extern void ResetTupleHashTable(TupleHashTable hashtable); + +/* + * prototypes from functions in execJunk.c + */ +extern JunkFilter *ExecInitJunkFilter(List *targetList, + TupleTableSlot *slot); +extern JunkFilter *ExecInitJunkFilterConversion(List *targetList, + TupleDesc cleanTupType, + TupleTableSlot *slot); +extern AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, + const char *attrName); +extern AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, + const char *attrName); +extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter, + TupleTableSlot *slot); + +/* + * ExecGetJunkAttribute + * + * Given a junk filter's input tuple (slot) and a junk attribute's number + * previously found by ExecFindJunkAttribute, extract & return the value and + * isNull flag of the attribute. + */ +#ifndef FRONTEND +static inline Datum +ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull) +{ + Assert(attno > 0); + return slot_getattr(slot, attno, isNull); +} +#endif + +/* + * prototypes from functions in execMain.c + */ +extern void ExecutorStart(QueryDesc *queryDesc, int eflags); +extern void standard_ExecutorStart(QueryDesc *queryDesc, int eflags); +extern void ExecutorRun(QueryDesc *queryDesc, + ScanDirection direction, uint64 count, bool execute_once); +extern void standard_ExecutorRun(QueryDesc *queryDesc, + ScanDirection direction, uint64 count, bool execute_once); +extern void ExecutorFinish(QueryDesc *queryDesc); +extern void standard_ExecutorFinish(QueryDesc *queryDesc); +extern void ExecutorEnd(QueryDesc *queryDesc); +extern void standard_ExecutorEnd(QueryDesc *queryDesc); +extern void ExecutorRewind(QueryDesc *queryDesc); +extern bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation); +extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation); +extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, + Relation resultRelationDesc, + Index resultRelationIndex, + ResultRelInfo *partition_root_rri, + int instrument_options); +extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid, + ResultRelInfo *rootRelInfo); +extern List *ExecGetAncestorResultRels(EState *estate, ResultRelInfo *resultRelInfo); +extern void ExecConstraints(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate); +extern bool ExecPartitionCheck(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate, bool emitError); +extern void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate); +extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate); +extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo); +extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool missing_ok); +extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist); +extern TupleTableSlot *EvalPlanQual(EPQState *epqstate, Relation relation, + Index rti, TupleTableSlot *testslot); +extern void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, + Plan *subplan, List *auxrowmarks, int epqParam); +extern void EvalPlanQualInitExt(EPQState *epqstate, EState *parentestate, + Plan *subplan, List *auxrowmarks, + int epqParam, List *resultRelations); +extern void EvalPlanQualSetPlan(EPQState *epqstate, + Plan *subplan, List *auxrowmarks); +extern TupleTableSlot *EvalPlanQualSlot(EPQState *epqstate, + Relation relation, Index rti); + +#define EvalPlanQualSetSlot(epqstate, slot) ((epqstate)->origslot = (slot)) +extern bool EvalPlanQualFetchRowMark(EPQState *epqstate, Index rti, TupleTableSlot *slot); +extern TupleTableSlot *EvalPlanQualNext(EPQState *epqstate); +extern void EvalPlanQualBegin(EPQState *epqstate); +extern void EvalPlanQualEnd(EPQState *epqstate); + +/* + * functions in execProcnode.c + */ +extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags); +extern void ExecSetExecProcNode(PlanState *node, ExecProcNodeMtd function); +extern Node *MultiExecProcNode(PlanState *node); +extern void ExecEndNode(PlanState *node); +extern bool ExecShutdownNode(PlanState *node); +extern void ExecSetTupleBound(int64 tuples_needed, PlanState *child_node); + + +/* ---------------------------------------------------------------- + * ExecProcNode + * + * Execute the given node to return a(nother) tuple. + * ---------------------------------------------------------------- + */ +#ifndef FRONTEND +static inline TupleTableSlot * +ExecProcNode(PlanState *node) +{ + if (node->chgParam != NULL) /* something changed? */ + ExecReScan(node); /* let ReScan handle this */ + + return node->ExecProcNode(node); +} +#endif + +/* + * prototypes from functions in execExpr.c + */ +extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); +extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params); +extern ExprState *ExecInitQual(List *qual, PlanState *parent); +extern ExprState *ExecInitCheck(List *qual, PlanState *parent); +extern List *ExecInitExprList(List *nodes, PlanState *parent); +extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase, + bool doSort, bool doHash, bool nullcheck); +extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, + const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, + int numCols, + const AttrNumber *keyColIdx, + const Oid *eqfunctions, + const Oid *collations, + PlanState *parent); +extern ExprState *ExecBuildParamSetEqual(TupleDesc desc, + const TupleTableSlotOps *lops, + const TupleTableSlotOps *rops, + const Oid *eqfunctions, + const Oid *collations, + const List *param_exprs, + PlanState *parent); +extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList, + ExprContext *econtext, + TupleTableSlot *slot, + PlanState *parent, + TupleDesc inputDesc); +extern ProjectionInfo *ExecBuildUpdateProjection(List *targetList, + bool evalTargetList, + List *targetColnos, + TupleDesc relDesc, + ExprContext *econtext, + TupleTableSlot *slot, + PlanState *parent); +extern ExprState *ExecPrepareExpr(Expr *node, EState *estate); +extern ExprState *ExecPrepareQual(List *qual, EState *estate); +extern ExprState *ExecPrepareCheck(List *qual, EState *estate); +extern List *ExecPrepareExprList(List *nodes, EState *estate); + +/* + * ExecEvalExpr + * + * Evaluate expression identified by "state" in the execution context + * given by "econtext". *isNull is set to the is-null flag for the result, + * and the Datum value is the function result. + * + * The caller should already have switched into the temporary memory + * context econtext->ecxt_per_tuple_memory. The convenience entry point + * ExecEvalExprSwitchContext() is provided for callers who don't prefer to + * do the switch in an outer loop. + */ +#ifndef FRONTEND +static inline Datum +ExecEvalExpr(ExprState *state, + ExprContext *econtext, + bool *isNull) +{ + return state->evalfunc(state, econtext, isNull); +} +#endif + +/* + * ExecEvalExprSwitchContext + * + * Same as ExecEvalExpr, but get into the right allocation context explicitly. + */ +#ifndef FRONTEND +static inline Datum +ExecEvalExprSwitchContext(ExprState *state, + ExprContext *econtext, + bool *isNull) +{ + Datum retDatum; + MemoryContext oldContext; + + oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + retDatum = state->evalfunc(state, econtext, isNull); + MemoryContextSwitchTo(oldContext); + return retDatum; +} +#endif + +/* + * ExecProject + * + * Projects a tuple based on projection info and stores it in the slot passed + * to ExecBuildProjectionInfo(). + * + * Note: the result is always a virtual tuple; therefore it may reference + * the contents of the exprContext's scan tuples and/or temporary results + * constructed in the exprContext. If the caller wishes the result to be + * valid longer than that data will be valid, he must call ExecMaterializeSlot + * on the result slot. + */ +#ifndef FRONTEND +static inline TupleTableSlot * +ExecProject(ProjectionInfo *projInfo) +{ + ExprContext *econtext = projInfo->pi_exprContext; + ExprState *state = &projInfo->pi_state; + TupleTableSlot *slot = state->resultslot; + bool isnull; + + /* + * Clear any former contents of the result slot. This makes it safe for + * us to use the slot's Datum/isnull arrays as workspace. + */ + ExecClearTuple(slot); + + /* Run the expression, discarding scalar result from the last column. */ + (void) ExecEvalExprSwitchContext(state, econtext, &isnull); + + /* + * Successfully formed a result row. Mark the result slot as containing a + * valid virtual tuple (inlined version of ExecStoreVirtualTuple()). + */ + slot->tts_flags &= ~TTS_FLAG_EMPTY; + slot->tts_nvalid = slot->tts_tupleDescriptor->natts; + + return slot; +} +#endif + +/* + * ExecQual - evaluate a qual prepared with ExecInitQual (possibly via + * ExecPrepareQual). Returns true if qual is satisfied, else false. + * + * Note: ExecQual used to have a third argument "resultForNull". The + * behavior of this function now corresponds to resultForNull == false. + * If you want the resultForNull == true behavior, see ExecCheck. + */ +#ifndef FRONTEND +static inline bool +ExecQual(ExprState *state, ExprContext *econtext) +{ + Datum ret; + bool isnull; + + /* short-circuit (here and in ExecInitQual) for empty restriction list */ + if (state == NULL) + return true; + + /* verify that expression was compiled using ExecInitQual */ + Assert(state->flags & EEO_FLAG_IS_QUAL); + + ret = ExecEvalExprSwitchContext(state, econtext, &isnull); + + /* EEOP_QUAL should never return NULL */ + Assert(!isnull); + + return DatumGetBool(ret); +} +#endif + +/* + * ExecQualAndReset() - evaluate qual with ExecQual() and reset expression + * context. + */ +#ifndef FRONTEND +static inline bool +ExecQualAndReset(ExprState *state, ExprContext *econtext) +{ + bool ret = ExecQual(state, econtext); + + /* inline ResetExprContext, to avoid ordering issue in this file */ + MemoryContextReset(econtext->ecxt_per_tuple_memory); + return ret; +} +#endif + +extern bool ExecCheck(ExprState *state, ExprContext *context); + +/* + * prototypes from functions in execSRF.c + */ +extern SetExprState *ExecInitTableFunctionResult(Expr *expr, + ExprContext *econtext, PlanState *parent); +extern Tuplestorestate *ExecMakeTableFunctionResult(SetExprState *setexpr, + ExprContext *econtext, + MemoryContext argContext, + TupleDesc expectedDesc, + bool randomAccess); +extern SetExprState *ExecInitFunctionResultSet(Expr *expr, + ExprContext *econtext, PlanState *parent); +extern Datum ExecMakeFunctionResultSet(SetExprState *fcache, + ExprContext *econtext, + MemoryContext argContext, + bool *isNull, + ExprDoneCond *isDone); + +/* + * prototypes from functions in execScan.c + */ +typedef TupleTableSlot *(*ExecScanAccessMtd) (ScanState *node); +typedef bool (*ExecScanRecheckMtd) (ScanState *node, TupleTableSlot *slot); + +extern TupleTableSlot *ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, + ExecScanRecheckMtd recheckMtd); +extern void ExecAssignScanProjectionInfo(ScanState *node); +extern void ExecAssignScanProjectionInfoWithVarno(ScanState *node, int varno); +extern void ExecScanReScan(ScanState *node); + +/* + * prototypes from functions in execTuples.c + */ +extern void ExecInitResultTypeTL(PlanState *planstate); +extern void ExecInitResultSlot(PlanState *planstate, + const TupleTableSlotOps *tts_ops); +extern void ExecInitResultTupleSlotTL(PlanState *planstate, + const TupleTableSlotOps *tts_ops); +extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, + TupleDesc tupleDesc, + const TupleTableSlotOps *tts_ops); +extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate, + TupleDesc tupledesc, + const TupleTableSlotOps *tts_ops); +extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate, TupleDesc tupType, + const TupleTableSlotOps *tts_ops); +extern TupleDesc ExecTypeFromTL(List *targetList); +extern TupleDesc ExecCleanTypeFromTL(List *targetList); +extern TupleDesc ExecTypeFromExprList(List *exprList); +extern void ExecTypeSetColNames(TupleDesc typeInfo, List *namesList); +extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); + +typedef struct TupOutputState +{ + TupleTableSlot *slot; + DestReceiver *dest; +} TupOutputState; + +extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest, + TupleDesc tupdesc, + const TupleTableSlotOps *tts_ops); +extern void do_tup_output(TupOutputState *tstate, Datum *values, bool *isnull); +extern void do_text_output_multiline(TupOutputState *tstate, const char *txt); +extern void end_tup_output(TupOutputState *tstate); + +/* + * Write a single line of text given as a C string. + * + * Should only be used with a single-TEXT-attribute tupdesc. + */ +#define do_text_output_oneline(tstate, str_to_emit) \ + do { \ + Datum values_[1]; \ + bool isnull_[1]; \ + values_[0] = PointerGetDatum(cstring_to_text(str_to_emit)); \ + isnull_[0] = false; \ + do_tup_output(tstate, values_, isnull_); \ + pfree(DatumGetPointer(values_[0])); \ + } while (0) + + +/* + * prototypes from functions in execUtils.c + */ +extern EState *CreateExecutorState(void); +extern void FreeExecutorState(EState *estate); +extern ExprContext *CreateExprContext(EState *estate); +extern ExprContext *CreateWorkExprContext(EState *estate); +extern ExprContext *CreateStandaloneExprContext(void); +extern void FreeExprContext(ExprContext *econtext, bool isCommit); +extern void ReScanExprContext(ExprContext *econtext); + +#define ResetExprContext(econtext) \ + MemoryContextReset((econtext)->ecxt_per_tuple_memory) + +extern ExprContext *MakePerTupleExprContext(EState *estate); + +/* Get an EState's per-output-tuple exprcontext, making it if first use */ +#define GetPerTupleExprContext(estate) \ + ((estate)->es_per_tuple_exprcontext ? \ + (estate)->es_per_tuple_exprcontext : \ + MakePerTupleExprContext(estate)) + +#define GetPerTupleMemoryContext(estate) \ + (GetPerTupleExprContext(estate)->ecxt_per_tuple_memory) + +/* Reset an EState's per-output-tuple exprcontext, if one's been created */ +#define ResetPerTupleExprContext(estate) \ + do { \ + if ((estate)->es_per_tuple_exprcontext) \ + ResetExprContext((estate)->es_per_tuple_exprcontext); \ + } while (0) + +extern void ExecAssignExprContext(EState *estate, PlanState *planstate); +extern TupleDesc ExecGetResultType(PlanState *planstate); +extern const TupleTableSlotOps *ExecGetResultSlotOps(PlanState *planstate, + bool *isfixed); +extern void ExecAssignProjectionInfo(PlanState *planstate, + TupleDesc inputDesc); +extern void ExecConditionalAssignProjectionInfo(PlanState *planstate, + TupleDesc inputDesc, int varno); +extern void ExecFreeExprContext(PlanState *planstate); +extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc); +extern void ExecCreateScanSlotFromOuterPlan(EState *estate, + ScanState *scanstate, + const TupleTableSlotOps *tts_ops); + +extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid); + +extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags); + +extern void ExecInitRangeTable(EState *estate, List *rangeTable); +extern void ExecCloseRangeTableRelations(EState *estate); +extern void ExecCloseResultRelations(EState *estate); + +static inline RangeTblEntry * +exec_rt_fetch(Index rti, EState *estate) +{ + return (RangeTblEntry *) list_nth(estate->es_range_table, rti - 1); +} + +extern Relation ExecGetRangeTableRelation(EState *estate, Index rti); +extern void ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo, + Index rti); + +extern int executor_errposition(EState *estate, int location); + +extern void RegisterExprContextCallback(ExprContext *econtext, + ExprContextCallbackFunction function, + Datum arg); +extern void UnregisterExprContextCallback(ExprContext *econtext, + ExprContextCallbackFunction function, + Datum arg); + +extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname, + bool *isNull); +extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, + bool *isNull); + +extern int ExecTargetListLength(List *targetlist); +extern int ExecCleanTargetListLength(List *targetlist); + +extern TupleTableSlot *ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo); +extern TupleTableSlot *ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo); +extern TupleTableSlot *ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo); +extern TupleConversionMap *ExecGetChildToRootMap(ResultRelInfo *resultRelInfo); + +extern Bitmapset *ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate); +extern Bitmapset *ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate); +extern Bitmapset *ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate); +extern Bitmapset *ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate); + +/* + * prototypes from functions in execIndexing.c + */ +extern void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative); +extern void ExecCloseIndices(ResultRelInfo *resultRelInfo); +extern List *ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, EState *estate, + bool update, + bool noDupErr, + bool *specConflict, List *arbiterIndexes); +extern bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, + TupleTableSlot *slot, + EState *estate, ItemPointer conflictTid, + List *arbiterIndexes); +extern void check_exclusion_constraint(Relation heap, Relation index, + IndexInfo *indexInfo, + ItemPointer tupleid, + Datum *values, bool *isnull, + EState *estate, bool newIndex); + +/* + * prototypes from functions in execReplication.c + */ +extern bool RelationFindReplTupleByIndex(Relation rel, Oid idxoid, + LockTupleMode lockmode, + TupleTableSlot *searchslot, + TupleTableSlot *outslot); +extern bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, + TupleTableSlot *searchslot, TupleTableSlot *outslot); + +extern void ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo, + EState *estate, TupleTableSlot *slot); +extern void ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo, + EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot, TupleTableSlot *slot); +extern void ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo, + EState *estate, EPQState *epqstate, + TupleTableSlot *searchslot); +extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd); + +extern void CheckSubscriptionRelkind(char relkind, const char *nspname, + const char *relname); + +/* + * prototypes from functions in nodeModifyTable.c + */ +extern TupleTableSlot *ExecGetUpdateNewTuple(ResultRelInfo *relinfo, + TupleTableSlot *planSlot, + TupleTableSlot *oldSlot); +extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, + Oid resultoid, + bool missing_ok, + bool update_cache); + +#endif /* EXECUTOR_H */ diff --git a/src/include/executor/functions.h b/src/include/executor/functions.h new file mode 100644 index 0000000..4c20cf4 --- /dev/null +++ b/src/include/executor/functions.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * functions.h + * Declarations for execution of SQL-language functions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/functions.h + * + *------------------------------------------------------------------------- + */ +#ifndef FUNCTIONS_H +#define FUNCTIONS_H + +#include "nodes/execnodes.h" +#include "tcop/dest.h" + +/* + * Data structure needed by the parser callback hooks to resolve parameter + * references during parsing of a SQL function's body. This is separate from + * SQLFunctionCache since we sometimes do parsing separately from execution. + */ +typedef struct SQLFunctionParseInfo +{ + char *fname; /* function's name */ + int nargs; /* number of input arguments */ + Oid *argtypes; /* resolved types of input arguments */ + char **argnames; /* names of input arguments; NULL if none */ + /* Note that argnames[i] can be NULL, if some args are unnamed */ + Oid collation; /* function's input collation, if known */ +} SQLFunctionParseInfo; + +typedef SQLFunctionParseInfo *SQLFunctionParseInfoPtr; + +extern Datum fmgr_sql(PG_FUNCTION_ARGS); + +extern SQLFunctionParseInfoPtr prepare_sql_fn_parse_info(HeapTuple procedureTuple, + Node *call_expr, + Oid inputCollation); + +extern void sql_fn_parser_setup(struct ParseState *pstate, + SQLFunctionParseInfoPtr pinfo); + +extern void check_sql_fn_statements(List *queryTreeLists); + +extern bool check_sql_fn_retval(List *queryTreeLists, + Oid rettype, TupleDesc rettupdesc, + bool insertDroppedCols, + List **resultTargetList); + +extern DestReceiver *CreateSQLFunctionDestReceiver(void); + +#endif /* FUNCTIONS_H */ diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h new file mode 100644 index 0000000..d7e90bc --- /dev/null +++ b/src/include/executor/hashjoin.h @@ -0,0 +1,363 @@ +/*------------------------------------------------------------------------- + * + * hashjoin.h + * internal structures for hash joins + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/hashjoin.h + * + *------------------------------------------------------------------------- + */ +#ifndef HASHJOIN_H +#define HASHJOIN_H + +#include "nodes/execnodes.h" +#include "port/atomics.h" +#include "storage/barrier.h" +#include "storage/buffile.h" +#include "storage/lwlock.h" + +/* ---------------------------------------------------------------- + * hash-join hash table structures + * + * Each active hashjoin has a HashJoinTable control block, which is + * palloc'd in the executor's per-query context. All other storage needed + * for the hashjoin is kept in private memory contexts, two for each hashjoin. + * This makes it easy and fast to release the storage when we don't need it + * anymore. (Exception: data associated with the temp files lives in the + * per-query context too, since we always call buffile.c in that context.) + * + * The hashtable contexts are made children of the per-query context, ensuring + * that they will be discarded at end of statement even if the join is + * aborted early by an error. (Likewise, any temporary files we make will + * be cleaned up by the virtual file manager in event of an error.) + * + * Storage that should live through the entire join is allocated from the + * "hashCxt", while storage that is only wanted for the current batch is + * allocated in the "batchCxt". By resetting the batchCxt at the end of + * each batch, we free all the per-batch storage reliably and without tedium. + * + * During first scan of inner relation, we get its tuples from executor. + * If nbatch > 1 then tuples that don't belong in first batch get saved + * into inner-batch temp files. The same statements apply for the + * first scan of the outer relation, except we write tuples to outer-batch + * temp files. After finishing the first scan, we do the following for + * each remaining batch: + * 1. Read tuples from inner batch file, load into hash buckets. + * 2. Read tuples from outer batch file, match to hash buckets and output. + * + * It is possible to increase nbatch on the fly if the in-memory hash table + * gets too big. The hash-value-to-batch computation is arranged so that this + * can only cause a tuple to go into a later batch than previously thought, + * never into an earlier batch. When we increase nbatch, we rescan the hash + * table and dump out any tuples that are now of a later batch to the correct + * inner batch file. Subsequently, while reading either inner or outer batch + * files, we might find tuples that no longer belong to the current batch; + * if so, we just dump them out to the correct batch file. + * ---------------------------------------------------------------- + */ + +/* these are in nodes/execnodes.h: */ +/* typedef struct HashJoinTupleData *HashJoinTuple; */ +/* typedef struct HashJoinTableData *HashJoinTable; */ + +typedef struct HashJoinTupleData +{ + /* link to next tuple in same bucket */ + union + { + struct HashJoinTupleData *unshared; + dsa_pointer shared; + } next; + uint32 hashvalue; /* tuple's hash code */ + /* Tuple data, in MinimalTuple format, follows on a MAXALIGN boundary */ +} HashJoinTupleData; + +#define HJTUPLE_OVERHEAD MAXALIGN(sizeof(HashJoinTupleData)) +#define HJTUPLE_MINTUPLE(hjtup) \ + ((MinimalTuple) ((char *) (hjtup) + HJTUPLE_OVERHEAD)) + +/* + * If the outer relation's distribution is sufficiently nonuniform, we attempt + * to optimize the join by treating the hash values corresponding to the outer + * relation's MCVs specially. Inner relation tuples matching these hash + * values go into the "skew" hashtable instead of the main hashtable, and + * outer relation tuples with these hash values are matched against that + * table instead of the main one. Thus, tuples with these hash values are + * effectively handled as part of the first batch and will never go to disk. + * The skew hashtable is limited to SKEW_HASH_MEM_PERCENT of the total memory + * allowed for the join; while building the hashtables, we decrease the number + * of MCVs being specially treated if needed to stay under this limit. + * + * Note: you might wonder why we look at the outer relation stats for this, + * rather than the inner. One reason is that the outer relation is typically + * bigger, so we get more I/O savings by optimizing for its most common values. + * Also, for similarly-sized relations, the planner prefers to put the more + * uniformly distributed relation on the inside, so we're more likely to find + * interesting skew in the outer relation. + */ +typedef struct HashSkewBucket +{ + uint32 hashvalue; /* common hash value */ + HashJoinTuple tuples; /* linked list of inner-relation tuples */ +} HashSkewBucket; + +#define SKEW_BUCKET_OVERHEAD MAXALIGN(sizeof(HashSkewBucket)) +#define INVALID_SKEW_BUCKET_NO (-1) +#define SKEW_HASH_MEM_PERCENT 2 +#define SKEW_MIN_OUTER_FRACTION 0.01 + +/* + * To reduce palloc overhead, the HashJoinTuples for the current batch are + * packed in 32kB buffers instead of pallocing each tuple individually. + */ +typedef struct HashMemoryChunkData +{ + int ntuples; /* number of tuples stored in this chunk */ + size_t maxlen; /* size of the chunk's tuple buffer */ + size_t used; /* number of buffer bytes already used */ + + /* pointer to the next chunk (linked list) */ + union + { + struct HashMemoryChunkData *unshared; + dsa_pointer shared; + } next; + + /* + * The chunk's tuple buffer starts after the HashMemoryChunkData struct, + * at offset HASH_CHUNK_HEADER_SIZE (which must be maxaligned). Note that + * that offset is not included in "maxlen" or "used". + */ +} HashMemoryChunkData; + +typedef struct HashMemoryChunkData *HashMemoryChunk; + +#define HASH_CHUNK_SIZE (32 * 1024L) +#define HASH_CHUNK_HEADER_SIZE MAXALIGN(sizeof(HashMemoryChunkData)) +#define HASH_CHUNK_DATA(hc) (((char *) (hc)) + HASH_CHUNK_HEADER_SIZE) +/* tuples exceeding HASH_CHUNK_THRESHOLD bytes are put in their own chunk */ +#define HASH_CHUNK_THRESHOLD (HASH_CHUNK_SIZE / 4) + +/* + * For each batch of a Parallel Hash Join, we have a ParallelHashJoinBatch + * object in shared memory to coordinate access to it. Since they are + * followed by variable-sized objects, they are arranged in contiguous memory + * but not accessed directly as an array. + */ +typedef struct ParallelHashJoinBatch +{ + dsa_pointer buckets; /* array of hash table buckets */ + Barrier batch_barrier; /* synchronization for joining this batch */ + + dsa_pointer chunks; /* chunks of tuples loaded */ + size_t size; /* size of buckets + chunks in memory */ + size_t estimated_size; /* size of buckets + chunks while writing */ + size_t ntuples; /* number of tuples loaded */ + size_t old_ntuples; /* number of tuples before repartitioning */ + bool space_exhausted; + + /* + * Variable-sized SharedTuplestore objects follow this struct in memory. + * See the accessor macros below. + */ +} ParallelHashJoinBatch; + +/* Accessor for inner batch tuplestore following a ParallelHashJoinBatch. */ +#define ParallelHashJoinBatchInner(batch) \ + ((SharedTuplestore *) \ + ((char *) (batch) + MAXALIGN(sizeof(ParallelHashJoinBatch)))) + +/* Accessor for outer batch tuplestore following a ParallelHashJoinBatch. */ +#define ParallelHashJoinBatchOuter(batch, nparticipants) \ + ((SharedTuplestore *) \ + ((char *) ParallelHashJoinBatchInner(batch) + \ + MAXALIGN(sts_estimate(nparticipants)))) + +/* Total size of a ParallelHashJoinBatch and tuplestores. */ +#define EstimateParallelHashJoinBatch(hashtable) \ + (MAXALIGN(sizeof(ParallelHashJoinBatch)) + \ + MAXALIGN(sts_estimate((hashtable)->parallel_state->nparticipants)) * 2) + +/* Accessor for the nth ParallelHashJoinBatch given the base. */ +#define NthParallelHashJoinBatch(base, n) \ + ((ParallelHashJoinBatch *) \ + ((char *) (base) + \ + EstimateParallelHashJoinBatch(hashtable) * (n))) + +/* + * Each backend requires a small amount of per-batch state to interact with + * each ParallelHashJoinBatch. + */ +typedef struct ParallelHashJoinBatchAccessor +{ + ParallelHashJoinBatch *shared; /* pointer to shared state */ + + /* Per-backend partial counters to reduce contention. */ + size_t preallocated; /* pre-allocated space for this backend */ + size_t ntuples; /* number of tuples */ + size_t size; /* size of partition in memory */ + size_t estimated_size; /* size of partition on disk */ + size_t old_ntuples; /* how many tuples before repartitioning? */ + bool at_least_one_chunk; /* has this backend allocated a chunk? */ + + bool done; /* flag to remember that a batch is done */ + SharedTuplestoreAccessor *inner_tuples; + SharedTuplestoreAccessor *outer_tuples; +} ParallelHashJoinBatchAccessor; + +/* + * While hashing the inner relation, any participant might determine that it's + * time to increase the number of buckets to reduce the load factor or batches + * to reduce the memory size. This is indicated by setting the growth flag to + * these values. + */ +typedef enum ParallelHashGrowth +{ + /* The current dimensions are sufficient. */ + PHJ_GROWTH_OK, + /* The load factor is too high, so we need to add buckets. */ + PHJ_GROWTH_NEED_MORE_BUCKETS, + /* The memory budget would be exhausted, so we need to repartition. */ + PHJ_GROWTH_NEED_MORE_BATCHES, + /* Repartitioning didn't help last time, so don't try to do that again. */ + PHJ_GROWTH_DISABLED +} ParallelHashGrowth; + +/* + * The shared state used to coordinate a Parallel Hash Join. This is stored + * in the DSM segment. + */ +typedef struct ParallelHashJoinState +{ + dsa_pointer batches; /* array of ParallelHashJoinBatch */ + dsa_pointer old_batches; /* previous generation during repartition */ + int nbatch; /* number of batches now */ + int old_nbatch; /* previous number of batches */ + int nbuckets; /* number of buckets */ + ParallelHashGrowth growth; /* control batch/bucket growth */ + dsa_pointer chunk_work_queue; /* chunk work queue */ + int nparticipants; + size_t space_allowed; + size_t total_tuples; /* total number of inner tuples */ + LWLock lock; /* lock protecting the above */ + + Barrier build_barrier; /* synchronization for the build phases */ + Barrier grow_batches_barrier; + Barrier grow_buckets_barrier; + pg_atomic_uint32 distributor; /* counter for load balancing */ + + SharedFileSet fileset; /* space for shared temporary files */ +} ParallelHashJoinState; + +/* The phases for building batches, used by build_barrier. */ +#define PHJ_BUILD_ELECTING 0 +#define PHJ_BUILD_ALLOCATING 1 +#define PHJ_BUILD_HASHING_INNER 2 +#define PHJ_BUILD_HASHING_OUTER 3 +#define PHJ_BUILD_RUNNING 4 +#define PHJ_BUILD_DONE 5 + +/* The phases for probing each batch, used by for batch_barrier. */ +#define PHJ_BATCH_ELECTING 0 +#define PHJ_BATCH_ALLOCATING 1 +#define PHJ_BATCH_LOADING 2 +#define PHJ_BATCH_PROBING 3 +#define PHJ_BATCH_DONE 4 + +/* The phases of batch growth while hashing, for grow_batches_barrier. */ +#define PHJ_GROW_BATCHES_ELECTING 0 +#define PHJ_GROW_BATCHES_ALLOCATING 1 +#define PHJ_GROW_BATCHES_REPARTITIONING 2 +#define PHJ_GROW_BATCHES_DECIDING 3 +#define PHJ_GROW_BATCHES_FINISHING 4 +#define PHJ_GROW_BATCHES_PHASE(n) ((n) % 5) /* circular phases */ + +/* The phases of bucket growth while hashing, for grow_buckets_barrier. */ +#define PHJ_GROW_BUCKETS_ELECTING 0 +#define PHJ_GROW_BUCKETS_ALLOCATING 1 +#define PHJ_GROW_BUCKETS_REINSERTING 2 +#define PHJ_GROW_BUCKETS_PHASE(n) ((n) % 3) /* circular phases */ + +typedef struct HashJoinTableData +{ + int nbuckets; /* # buckets in the in-memory hash table */ + int log2_nbuckets; /* its log2 (nbuckets must be a power of 2) */ + + int nbuckets_original; /* # buckets when starting the first hash */ + int nbuckets_optimal; /* optimal # buckets (per batch) */ + int log2_nbuckets_optimal; /* log2(nbuckets_optimal) */ + + /* buckets[i] is head of list of tuples in i'th in-memory bucket */ + union + { + /* unshared array is per-batch storage, as are all the tuples */ + struct HashJoinTupleData **unshared; + /* shared array is per-query DSA area, as are all the tuples */ + dsa_pointer_atomic *shared; + } buckets; + + bool keepNulls; /* true to store unmatchable NULL tuples */ + + bool skewEnabled; /* are we using skew optimization? */ + HashSkewBucket **skewBucket; /* hashtable of skew buckets */ + int skewBucketLen; /* size of skewBucket array (a power of 2!) */ + int nSkewBuckets; /* number of active skew buckets */ + int *skewBucketNums; /* array indexes of active skew buckets */ + + int nbatch; /* number of batches */ + int curbatch; /* current batch #; 0 during 1st pass */ + + int nbatch_original; /* nbatch when we started inner scan */ + int nbatch_outstart; /* nbatch when we started outer scan */ + + bool growEnabled; /* flag to shut off nbatch increases */ + + double totalTuples; /* # tuples obtained from inner plan */ + double partialTuples; /* # tuples obtained from inner plan by me */ + double skewTuples; /* # tuples inserted into skew tuples */ + + /* + * These arrays are allocated for the life of the hash join, but only if + * nbatch > 1. A file is opened only when we first write a tuple into it + * (otherwise its pointer remains NULL). Note that the zero'th array + * elements never get used, since we will process rather than dump out any + * tuples of batch zero. + */ + BufFile **innerBatchFile; /* buffered virtual temp file per batch */ + BufFile **outerBatchFile; /* buffered virtual temp file per batch */ + + /* + * Info about the datatype-specific hash functions for the datatypes being + * hashed. These are arrays of the same length as the number of hash join + * clauses (hash keys). + */ + FmgrInfo *outer_hashfunctions; /* lookup data for hash functions */ + FmgrInfo *inner_hashfunctions; /* lookup data for hash functions */ + bool *hashStrict; /* is each hash join operator strict? */ + Oid *collations; + + Size spaceUsed; /* memory space currently used by tuples */ + Size spaceAllowed; /* upper limit for space used */ + Size spacePeak; /* peak space used */ + Size spaceUsedSkew; /* skew hash table's current space usage */ + Size spaceAllowedSkew; /* upper limit for skew hashtable */ + + MemoryContext hashCxt; /* context for whole-hash-join storage */ + MemoryContext batchCxt; /* context for this-batch-only storage */ + + /* used for dense allocation of tuples (into linked chunks) */ + HashMemoryChunk chunks; /* one list for the whole batch */ + + /* Shared and private state for Parallel Hash. */ + HashMemoryChunk current_chunk; /* this backend's current chunk */ + dsa_area *area; /* DSA area to allocate memory from */ + ParallelHashJoinState *parallel_state; + ParallelHashJoinBatchAccessor *batches; + dsa_pointer current_chunk_shared; +} HashJoinTableData; + +#endif /* HASHJOIN_H */ diff --git a/src/include/executor/instrument.h b/src/include/executor/instrument.h new file mode 100644 index 0000000..2945cce --- /dev/null +++ b/src/include/executor/instrument.h @@ -0,0 +1,118 @@ +/*------------------------------------------------------------------------- + * + * instrument.h + * definitions for run-time statistics collection + * + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/executor/instrument.h + * + *------------------------------------------------------------------------- + */ +#ifndef INSTRUMENT_H +#define INSTRUMENT_H + +#include "portability/instr_time.h" + + +/* + * BufferUsage and WalUsage counters keep being incremented infinitely, + * i.e., must never be reset to zero, so that we can calculate how much + * the counters are incremented in an arbitrary period. + */ +typedef struct BufferUsage +{ + int64 shared_blks_hit; /* # of shared buffer hits */ + int64 shared_blks_read; /* # of shared disk blocks read */ + int64 shared_blks_dirtied; /* # of shared blocks dirtied */ + int64 shared_blks_written; /* # of shared disk blocks written */ + int64 local_blks_hit; /* # of local buffer hits */ + int64 local_blks_read; /* # of local disk blocks read */ + int64 local_blks_dirtied; /* # of local blocks dirtied */ + int64 local_blks_written; /* # of local disk blocks written */ + int64 temp_blks_read; /* # of temp blocks read */ + int64 temp_blks_written; /* # of temp blocks written */ + instr_time blk_read_time; /* time spent reading blocks */ + instr_time blk_write_time; /* time spent writing blocks */ + instr_time temp_blk_read_time; /* time spent reading temp blocks */ + instr_time temp_blk_write_time; /* time spent writing temp blocks */ +} BufferUsage; + +/* + * WalUsage tracks only WAL activity like WAL records generation that + * can be measured per query and is displayed by EXPLAIN command, + * pg_stat_statements extension, etc. It does not track other WAL activity + * like WAL writes that it's not worth measuring per query. That's tracked + * by WAL global statistics counters in WalStats, instead. + */ +typedef struct WalUsage +{ + int64 wal_records; /* # of WAL records produced */ + int64 wal_fpi; /* # of WAL full page images produced */ + uint64 wal_bytes; /* size of WAL records produced */ +} WalUsage; + +/* Flag bits included in InstrAlloc's instrument_options bitmask */ +typedef enum InstrumentOption +{ + INSTRUMENT_TIMER = 1 << 0, /* needs timer (and row counts) */ + INSTRUMENT_BUFFERS = 1 << 1, /* needs buffer usage */ + INSTRUMENT_ROWS = 1 << 2, /* needs row count */ + INSTRUMENT_WAL = 1 << 3, /* needs WAL usage */ + INSTRUMENT_ALL = PG_INT32_MAX +} InstrumentOption; + +typedef struct Instrumentation +{ + /* Parameters set at node creation: */ + bool need_timer; /* true if we need timer data */ + bool need_bufusage; /* true if we need buffer usage data */ + bool need_walusage; /* true if we need WAL usage data */ + bool async_mode; /* true if node is in async mode */ + /* Info about current plan cycle: */ + bool running; /* true if we've completed first tuple */ + instr_time starttime; /* start time of current iteration of node */ + instr_time counter; /* accumulated runtime for this node */ + double firsttuple; /* time for first tuple of this cycle */ + double tuplecount; /* # of tuples emitted so far this cycle */ + BufferUsage bufusage_start; /* buffer usage at start */ + WalUsage walusage_start; /* WAL usage at start */ + /* Accumulated statistics across all completed cycles: */ + double startup; /* total startup time (in seconds) */ + double total; /* total time (in seconds) */ + double ntuples; /* total tuples produced */ + double ntuples2; /* secondary node-specific tuple counter */ + double nloops; /* # of run cycles for this node */ + double nfiltered1; /* # of tuples removed by scanqual or joinqual */ + double nfiltered2; /* # of tuples removed by "other" quals */ + BufferUsage bufusage; /* total buffer usage */ + WalUsage walusage; /* total WAL usage */ +} Instrumentation; + +typedef struct WorkerInstrumentation +{ + int num_workers; /* # of structures that follow */ + Instrumentation instrument[FLEXIBLE_ARRAY_MEMBER]; +} WorkerInstrumentation; + +extern PGDLLIMPORT BufferUsage pgBufferUsage; +extern PGDLLIMPORT WalUsage pgWalUsage; + +extern Instrumentation *InstrAlloc(int n, int instrument_options, + bool async_mode); +extern void InstrInit(Instrumentation *instr, int instrument_options); +extern void InstrStartNode(Instrumentation *instr); +extern void InstrStopNode(Instrumentation *instr, double nTuples); +extern void InstrUpdateTupleCount(Instrumentation *instr, double nTuples); +extern void InstrEndLoop(Instrumentation *instr); +extern void InstrAggNode(Instrumentation *dst, Instrumentation *add); +extern void InstrStartParallelQuery(void); +extern void InstrEndParallelQuery(BufferUsage *bufusage, WalUsage *walusage); +extern void InstrAccumParallelQuery(BufferUsage *bufusage, WalUsage *walusage); +extern void BufferUsageAccumDiff(BufferUsage *dst, + const BufferUsage *add, const BufferUsage *sub); +extern void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, + const WalUsage *sub); + +#endif /* INSTRUMENT_H */ diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h new file mode 100644 index 0000000..4d1bd92 --- /dev/null +++ b/src/include/executor/nodeAgg.h @@ -0,0 +1,333 @@ +/*------------------------------------------------------------------------- + * + * nodeAgg.h + * prototypes for nodeAgg.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeAgg.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEAGG_H +#define NODEAGG_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + + +/* + * AggStatePerTransData - per aggregate state value information + * + * Working state for updating the aggregate's state value, by calling the + * transition function with an input row. This struct does not store the + * information needed to produce the final aggregate result from the transition + * state, that's stored in AggStatePerAggData instead. This separation allows + * multiple aggregate results to be produced from a single state value. + */ +typedef struct AggStatePerTransData +{ + /* + * These values are set up during ExecInitAgg() and do not change + * thereafter: + */ + + /* + * Link to an Aggref expr this state value is for. + * + * There can be multiple Aggref's sharing the same state value, so long as + * the inputs and transition functions are identical and the final + * functions are not read-write. This points to the first one of them. + */ + Aggref *aggref; + + /* + * Is this state value actually being shared by more than one Aggref? + */ + bool aggshared; + + /* + * Number of aggregated input columns. This includes ORDER BY expressions + * in both the plain-agg and ordered-set cases. Ordered-set direct args + * are not counted, though. + */ + int numInputs; + + /* + * Number of aggregated input columns to pass to the transfn. This + * includes the ORDER BY columns for ordered-set aggs, but not for plain + * aggs. (This doesn't count the transition state value!) + */ + int numTransInputs; + + /* Oid of the state transition or combine function */ + Oid transfn_oid; + + /* Oid of the serialization function or InvalidOid */ + Oid serialfn_oid; + + /* Oid of the deserialization function or InvalidOid */ + Oid deserialfn_oid; + + /* Oid of state value's datatype */ + Oid aggtranstype; + + /* + * fmgr lookup data for transition function or combine function. Note in + * particular that the fn_strict flag is kept here. + */ + FmgrInfo transfn; + + /* fmgr lookup data for serialization function */ + FmgrInfo serialfn; + + /* fmgr lookup data for deserialization function */ + FmgrInfo deserialfn; + + /* Input collation derived for aggregate */ + Oid aggCollation; + + /* number of sorting columns */ + int numSortCols; + + /* number of sorting columns to consider in DISTINCT comparisons */ + /* (this is either zero or the same as numSortCols) */ + int numDistinctCols; + + /* deconstructed sorting information (arrays of length numSortCols) */ + AttrNumber *sortColIdx; + Oid *sortOperators; + Oid *sortCollations; + bool *sortNullsFirst; + + /* + * Comparators for input columns --- only set/used when aggregate has + * DISTINCT flag. equalfnOne version is used for single-column + * comparisons, equalfnMulti for the case of multiple columns. + */ + FmgrInfo equalfnOne; + ExprState *equalfnMulti; + + /* + * initial value from pg_aggregate entry + */ + Datum initValue; + bool initValueIsNull; + + /* + * We need the len and byval info for the agg's input and transition data + * types in order to know how to copy/delete values. + * + * Note that the info for the input type is used only when handling + * DISTINCT aggs with just one argument, so there is only one input type. + */ + int16 inputtypeLen, + transtypeLen; + bool inputtypeByVal, + transtypeByVal; + + /* + * Slots for holding the evaluated input arguments. These are set up + * during ExecInitAgg() and then used for each input row requiring either + * FILTER or ORDER BY/DISTINCT processing. + */ + TupleTableSlot *sortslot; /* current input tuple */ + TupleTableSlot *uniqslot; /* used for multi-column DISTINCT */ + TupleDesc sortdesc; /* descriptor of input tuples */ + + /* + * These values are working state that is initialized at the start of an + * input tuple group and updated for each input tuple. + * + * For a simple (non DISTINCT/ORDER BY) aggregate, we just feed the input + * values straight to the transition function. If it's DISTINCT or + * requires ORDER BY, we pass the input values into a Tuplesort object; + * then at completion of the input tuple group, we scan the sorted values, + * eliminate duplicates if needed, and run the transition function on the + * rest. + * + * We need a separate tuplesort for each grouping set. + */ + + Tuplesortstate **sortstates; /* sort objects, if DISTINCT or ORDER BY */ + + /* + * This field is a pre-initialized FunctionCallInfo struct used for + * calling this aggregate's transfn. We save a few cycles per row by not + * re-initializing the unchanging fields; which isn't much, but it seems + * worth the extra space consumption. + */ + FunctionCallInfo transfn_fcinfo; + + /* Likewise for serialization and deserialization functions */ + FunctionCallInfo serialfn_fcinfo; + + FunctionCallInfo deserialfn_fcinfo; +} AggStatePerTransData; + +/* + * AggStatePerAggData - per-aggregate information + * + * This contains the information needed to call the final function, to produce + * a final aggregate result from the state value. If there are multiple + * identical Aggrefs in the query, they can all share the same per-agg data. + * + * These values are set up during ExecInitAgg() and do not change thereafter. + */ +typedef struct AggStatePerAggData +{ + /* + * Link to an Aggref expr this state value is for. + * + * There can be multiple identical Aggref's sharing the same per-agg. This + * points to the first one of them. + */ + Aggref *aggref; + + /* index to the state value which this agg should use */ + int transno; + + /* Optional Oid of final function (may be InvalidOid) */ + Oid finalfn_oid; + + /* + * fmgr lookup data for final function --- only valid when finalfn_oid is + * not InvalidOid. + */ + FmgrInfo finalfn; + + /* + * Number of arguments to pass to the finalfn. This is always at least 1 + * (the transition state value) plus any ordered-set direct args. If the + * finalfn wants extra args then we pass nulls corresponding to the + * aggregated input columns. + */ + int numFinalArgs; + + /* ExprStates for any direct-argument expressions */ + List *aggdirectargs; + + /* + * We need the len and byval info for the agg's result data type in order + * to know how to copy/delete values. + */ + int16 resulttypeLen; + bool resulttypeByVal; + + /* + * "shareable" is false if this agg cannot share state values with other + * aggregates because the final function is read-write. + */ + bool shareable; +} AggStatePerAggData; + +/* + * AggStatePerGroupData - per-aggregate-per-group working state + * + * These values are working state that is initialized at the start of + * an input tuple group and updated for each input tuple. + * + * In AGG_PLAIN and AGG_SORTED modes, we have a single array of these + * structs (pointed to by aggstate->pergroup); we re-use the array for + * each input group, if it's AGG_SORTED mode. In AGG_HASHED mode, the + * hash table contains an array of these structs for each tuple group. + * + * Logically, the sortstate field belongs in this struct, but we do not + * keep it here for space reasons: we don't support DISTINCT aggregates + * in AGG_HASHED mode, so there's no reason to use up a pointer field + * in every entry of the hashtable. + */ +typedef struct AggStatePerGroupData +{ +#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE 0 + Datum transValue; /* current transition value */ +#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL 1 + bool transValueIsNull; + +#define FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE 2 + bool noTransValue; /* true if transValue not set yet */ + + /* + * Note: noTransValue initially has the same value as transValueIsNull, + * and if true both are cleared to false at the same time. They are not + * the same though: if transfn later returns a NULL, we want to keep that + * NULL and not auto-replace it with a later input value. Only the first + * non-NULL input will be auto-substituted. + */ +} AggStatePerGroupData; + +/* + * AggStatePerPhaseData - per-grouping-set-phase state + * + * Grouping sets are divided into "phases", where a single phase can be + * processed in one pass over the input. If there is more than one phase, then + * at the end of input from the current phase, state is reset and another pass + * taken over the data which has been re-sorted in the mean time. + * + * Accordingly, each phase specifies a list of grouping sets and group clause + * information, plus each phase after the first also has a sort order. + */ +typedef struct AggStatePerPhaseData +{ + AggStrategy aggstrategy; /* strategy for this phase */ + int numsets; /* number of grouping sets (or 0) */ + int *gset_lengths; /* lengths of grouping sets */ + Bitmapset **grouped_cols; /* column groupings for rollup */ + ExprState **eqfunctions; /* expression returning equality, indexed by + * nr of cols to compare */ + Agg *aggnode; /* Agg node for phase data */ + Sort *sortnode; /* Sort node for input ordering for phase */ + + ExprState *evaltrans; /* evaluation of transition functions */ + + /*---------- + * Cached variants of the compiled expression. + * first subscript: 0: outerops; 1: TTSOpsMinimalTuple + * second subscript: 0: no NULL check; 1: with NULL check + *---------- + */ + ExprState *evaltrans_cache[2][2]; +} AggStatePerPhaseData; + +/* + * AggStatePerHashData - per-hashtable state + * + * When doing grouping sets with hashing, we have one of these for each + * grouping set. (When doing hashing without grouping sets, we have just one of + * them.) + */ +typedef struct AggStatePerHashData +{ + TupleHashTable hashtable; /* hash table with one entry per group */ + TupleHashIterator hashiter; /* for iterating through hash table */ + TupleTableSlot *hashslot; /* slot for loading hash table */ + FmgrInfo *hashfunctions; /* per-grouping-field hash fns */ + Oid *eqfuncoids; /* per-grouping-field equality fns */ + int numCols; /* number of hash key columns */ + int numhashGrpCols; /* number of columns in hash table */ + int largestGrpColIdx; /* largest col required for hashing */ + AttrNumber *hashGrpColIdxInput; /* hash col indices in input slot */ + AttrNumber *hashGrpColIdxHash; /* indices in hash table tuples */ + Agg *aggnode; /* original Agg node, for numGroups etc. */ +} AggStatePerHashData; + + +extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags); +extern void ExecEndAgg(AggState *node); +extern void ExecReScanAgg(AggState *node); + +extern Size hash_agg_entry_size(int numTrans, Size tupleWidth, + Size transitionSpace); +extern void hash_agg_set_limits(double hashentrysize, double input_groups, + int used_bits, Size *mem_limit, + uint64 *ngroups_limit, int *num_partitions); + +/* parallel instrumentation support */ +extern void ExecAggEstimate(AggState *node, ParallelContext *pcxt); +extern void ExecAggInitializeDSM(AggState *node, ParallelContext *pcxt); +extern void ExecAggInitializeWorker(AggState *node, ParallelWorkerContext *pwcxt); +extern void ExecAggRetrieveInstrumentation(AggState *node); + +#endif /* NODEAGG_H */ diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h new file mode 100644 index 0000000..4cb78ee --- /dev/null +++ b/src/include/executor/nodeAppend.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * nodeAppend.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeAppend.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEAPPEND_H +#define NODEAPPEND_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags); +extern void ExecEndAppend(AppendState *node); +extern void ExecReScanAppend(AppendState *node); +extern void ExecAppendEstimate(AppendState *node, ParallelContext *pcxt); +extern void ExecAppendInitializeDSM(AppendState *node, ParallelContext *pcxt); +extern void ExecAppendReInitializeDSM(AppendState *node, ParallelContext *pcxt); +extern void ExecAppendInitializeWorker(AppendState *node, ParallelWorkerContext *pwcxt); + +extern void ExecAsyncAppendResponse(AsyncRequest *areq); + +#endif /* NODEAPPEND_H */ diff --git a/src/include/executor/nodeBitmapAnd.h b/src/include/executor/nodeBitmapAnd.h new file mode 100644 index 0000000..bae6a83 --- /dev/null +++ b/src/include/executor/nodeBitmapAnd.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeBitmapAnd.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeBitmapAnd.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEBITMAPAND_H +#define NODEBITMAPAND_H + +#include "nodes/execnodes.h" + +extern BitmapAndState *ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags); +extern Node *MultiExecBitmapAnd(BitmapAndState *node); +extern void ExecEndBitmapAnd(BitmapAndState *node); +extern void ExecReScanBitmapAnd(BitmapAndState *node); + +#endif /* NODEBITMAPAND_H */ diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h new file mode 100644 index 0000000..789522c --- /dev/null +++ b/src/include/executor/nodeBitmapHeapscan.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * nodeBitmapHeapscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeBitmapHeapscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEBITMAPHEAPSCAN_H +#define NODEBITMAPHEAPSCAN_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags); +extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node); +extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node); +extern void ExecBitmapHeapEstimate(BitmapHeapScanState *node, + ParallelContext *pcxt); +extern void ExecBitmapHeapInitializeDSM(BitmapHeapScanState *node, + ParallelContext *pcxt); +extern void ExecBitmapHeapReInitializeDSM(BitmapHeapScanState *node, + ParallelContext *pcxt); +extern void ExecBitmapHeapInitializeWorker(BitmapHeapScanState *node, + ParallelWorkerContext *pwcxt); + +#endif /* NODEBITMAPHEAPSCAN_H */ diff --git a/src/include/executor/nodeBitmapIndexscan.h b/src/include/executor/nodeBitmapIndexscan.h new file mode 100644 index 0000000..01fb6ef --- /dev/null +++ b/src/include/executor/nodeBitmapIndexscan.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeBitmapIndexscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeBitmapIndexscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEBITMAPINDEXSCAN_H +#define NODEBITMAPINDEXSCAN_H + +#include "nodes/execnodes.h" + +extern BitmapIndexScanState *ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags); +extern Node *MultiExecBitmapIndexScan(BitmapIndexScanState *node); +extern void ExecEndBitmapIndexScan(BitmapIndexScanState *node); +extern void ExecReScanBitmapIndexScan(BitmapIndexScanState *node); + +#endif /* NODEBITMAPINDEXSCAN_H */ diff --git a/src/include/executor/nodeBitmapOr.h b/src/include/executor/nodeBitmapOr.h new file mode 100644 index 0000000..ad90812 --- /dev/null +++ b/src/include/executor/nodeBitmapOr.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeBitmapOr.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeBitmapOr.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEBITMAPOR_H +#define NODEBITMAPOR_H + +#include "nodes/execnodes.h" + +extern BitmapOrState *ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags); +extern Node *MultiExecBitmapOr(BitmapOrState *node); +extern void ExecEndBitmapOr(BitmapOrState *node); +extern void ExecReScanBitmapOr(BitmapOrState *node); + +#endif /* NODEBITMAPOR_H */ diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h new file mode 100644 index 0000000..317d142 --- /dev/null +++ b/src/include/executor/nodeCtescan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeCtescan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeCtescan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODECTESCAN_H +#define NODECTESCAN_H + +#include "nodes/execnodes.h" + +extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags); +extern void ExecEndCteScan(CteScanState *node); +extern void ExecReScanCteScan(CteScanState *node); + +#endif /* NODECTESCAN_H */ diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h new file mode 100644 index 0000000..5ef8901 --- /dev/null +++ b/src/include/executor/nodeCustom.h @@ -0,0 +1,42 @@ +/* ------------------------------------------------------------------------ + * + * nodeCustom.h + * + * prototypes for CustomScan nodes + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------ + */ +#ifndef NODECUSTOM_H +#define NODECUSTOM_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +/* + * General executor code + */ +extern CustomScanState *ExecInitCustomScan(CustomScan *cscan, + EState *estate, int eflags); +extern void ExecEndCustomScan(CustomScanState *node); + +extern void ExecReScanCustomScan(CustomScanState *node); +extern void ExecCustomMarkPos(CustomScanState *node); +extern void ExecCustomRestrPos(CustomScanState *node); + +/* + * Parallel execution support + */ +extern void ExecCustomScanEstimate(CustomScanState *node, + ParallelContext *pcxt); +extern void ExecCustomScanInitializeDSM(CustomScanState *node, + ParallelContext *pcxt); +extern void ExecCustomScanReInitializeDSM(CustomScanState *node, + ParallelContext *pcxt); +extern void ExecCustomScanInitializeWorker(CustomScanState *node, + ParallelWorkerContext *pwcxt); +extern void ExecShutdownCustomScan(CustomScanState *node); + +#endif /* NODECUSTOM_H */ diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h new file mode 100644 index 0000000..c9fbaed --- /dev/null +++ b/src/include/executor/nodeForeignscan.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * nodeForeignscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeForeignscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEFOREIGNSCAN_H +#define NODEFOREIGNSCAN_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags); +extern void ExecEndForeignScan(ForeignScanState *node); +extern void ExecReScanForeignScan(ForeignScanState *node); + +extern void ExecForeignScanEstimate(ForeignScanState *node, + ParallelContext *pcxt); +extern void ExecForeignScanInitializeDSM(ForeignScanState *node, + ParallelContext *pcxt); +extern void ExecForeignScanReInitializeDSM(ForeignScanState *node, + ParallelContext *pcxt); +extern void ExecForeignScanInitializeWorker(ForeignScanState *node, + ParallelWorkerContext *pwcxt); +extern void ExecShutdownForeignScan(ForeignScanState *node); + +extern void ExecAsyncForeignScanRequest(AsyncRequest *areq); +extern void ExecAsyncForeignScanConfigureWait(AsyncRequest *areq); +extern void ExecAsyncForeignScanNotify(AsyncRequest *areq); + +#endif /* NODEFOREIGNSCAN_H */ diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h new file mode 100644 index 0000000..7a598a1 --- /dev/null +++ b/src/include/executor/nodeFunctionscan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeFunctionscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeFunctionscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEFUNCTIONSCAN_H +#define NODEFUNCTIONSCAN_H + +#include "nodes/execnodes.h" + +extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags); +extern void ExecEndFunctionScan(FunctionScanState *node); +extern void ExecReScanFunctionScan(FunctionScanState *node); + +#endif /* NODEFUNCTIONSCAN_H */ diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h new file mode 100644 index 0000000..29829ff --- /dev/null +++ b/src/include/executor/nodeGather.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeGather.h + * prototypes for nodeGather.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeGather.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEGATHER_H +#define NODEGATHER_H + +#include "nodes/execnodes.h" + +extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags); +extern void ExecEndGather(GatherState *node); +extern void ExecShutdownGather(GatherState *node); +extern void ExecReScanGather(GatherState *node); + +#endif /* NODEGATHER_H */ diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h new file mode 100644 index 0000000..d724d5f --- /dev/null +++ b/src/include/executor/nodeGatherMerge.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * nodeGatherMerge.h + * prototypes for nodeGatherMerge.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeGatherMerge.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEGATHERMERGE_H +#define NODEGATHERMERGE_H + +#include "nodes/execnodes.h" + +extern GatherMergeState *ExecInitGatherMerge(GatherMerge *node, + EState *estate, + int eflags); +extern void ExecEndGatherMerge(GatherMergeState *node); +extern void ExecReScanGatherMerge(GatherMergeState *node); +extern void ExecShutdownGatherMerge(GatherMergeState *node); + +#endif /* NODEGATHERMERGE_H */ diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h new file mode 100644 index 0000000..816ed2c --- /dev/null +++ b/src/include/executor/nodeGroup.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeGroup.h + * prototypes for nodeGroup.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeGroup.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEGROUP_H +#define NODEGROUP_H + +#include "nodes/execnodes.h" + +extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags); +extern void ExecEndGroup(GroupState *node); +extern void ExecReScanGroup(GroupState *node); + +#endif /* NODEGROUP_H */ diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h new file mode 100644 index 0000000..e1e0dec --- /dev/null +++ b/src/include/executor/nodeHash.h @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------- + * + * nodeHash.h + * prototypes for nodeHash.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeHash.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEHASH_H +#define NODEHASH_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +struct SharedHashJoinBatch; + +extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags); +extern Node *MultiExecHash(HashState *node); +extern void ExecEndHash(HashState *node); +extern void ExecReScanHash(HashState *node); + +extern HashJoinTable ExecHashTableCreate(HashState *state, List *hashOperators, List *hashCollations, + bool keepNulls); +extern void ExecParallelHashTableAlloc(HashJoinTable hashtable, + int batchno); +extern void ExecHashTableDestroy(HashJoinTable hashtable); +extern void ExecHashTableDetach(HashJoinTable hashtable); +extern void ExecHashTableDetachBatch(HashJoinTable hashtable); +extern void ExecParallelHashTableSetCurrentBatch(HashJoinTable hashtable, + int batchno); + +extern void ExecHashTableInsert(HashJoinTable hashtable, + TupleTableSlot *slot, + uint32 hashvalue); +extern void ExecParallelHashTableInsert(HashJoinTable hashtable, + TupleTableSlot *slot, + uint32 hashvalue); +extern void ExecParallelHashTableInsertCurrentBatch(HashJoinTable hashtable, + TupleTableSlot *slot, + uint32 hashvalue); +extern bool ExecHashGetHashValue(HashJoinTable hashtable, + ExprContext *econtext, + List *hashkeys, + bool outer_tuple, + bool keep_nulls, + uint32 *hashvalue); +extern void ExecHashGetBucketAndBatch(HashJoinTable hashtable, + uint32 hashvalue, + int *bucketno, + int *batchno); +extern bool ExecScanHashBucket(HashJoinState *hjstate, ExprContext *econtext); +extern bool ExecParallelScanHashBucket(HashJoinState *hjstate, ExprContext *econtext); +extern void ExecPrepHashTableForUnmatched(HashJoinState *hjstate); +extern bool ExecScanHashTableForUnmatched(HashJoinState *hjstate, + ExprContext *econtext); +extern void ExecHashTableReset(HashJoinTable hashtable); +extern void ExecHashTableResetMatchFlags(HashJoinTable hashtable); +extern void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, + bool try_combined_hash_mem, + int parallel_workers, + size_t *space_allowed, + int *numbuckets, + int *numbatches, + int *num_skew_mcvs); +extern int ExecHashGetSkewBucket(HashJoinTable hashtable, uint32 hashvalue); +extern void ExecHashEstimate(HashState *node, ParallelContext *pcxt); +extern void ExecHashInitializeDSM(HashState *node, ParallelContext *pcxt); +extern void ExecHashInitializeWorker(HashState *node, ParallelWorkerContext *pwcxt); +extern void ExecHashRetrieveInstrumentation(HashState *node); +extern void ExecShutdownHash(HashState *node); +extern void ExecHashAccumInstrumentation(HashInstrumentation *instrument, + HashJoinTable hashtable); + +#endif /* NODEHASH_H */ diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h new file mode 100644 index 0000000..b3b5a2c --- /dev/null +++ b/src/include/executor/nodeHashjoin.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * nodeHashjoin.h + * prototypes for nodeHashjoin.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeHashjoin.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEHASHJOIN_H +#define NODEHASHJOIN_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" +#include "storage/buffile.h" + +extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags); +extern void ExecEndHashJoin(HashJoinState *node); +extern void ExecReScanHashJoin(HashJoinState *node); +extern void ExecShutdownHashJoin(HashJoinState *node); +extern void ExecHashJoinEstimate(HashJoinState *state, ParallelContext *pcxt); +extern void ExecHashJoinInitializeDSM(HashJoinState *state, ParallelContext *pcxt); +extern void ExecHashJoinReInitializeDSM(HashJoinState *state, ParallelContext *pcxt); +extern void ExecHashJoinInitializeWorker(HashJoinState *state, + ParallelWorkerContext *pwcxt); + +extern void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, + BufFile **fileptr); + +#endif /* NODEHASHJOIN_H */ diff --git a/src/include/executor/nodeIncrementalSort.h b/src/include/executor/nodeIncrementalSort.h new file mode 100644 index 0000000..84cfd96 --- /dev/null +++ b/src/include/executor/nodeIncrementalSort.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * nodeIncrementalSort.h + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeIncrementalSort.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEINCREMENTALSORT_H +#define NODEINCREMENTALSORT_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern IncrementalSortState *ExecInitIncrementalSort(IncrementalSort *node, EState *estate, int eflags); +extern void ExecEndIncrementalSort(IncrementalSortState *node); +extern void ExecReScanIncrementalSort(IncrementalSortState *node); + +/* parallel instrumentation support */ +extern void ExecIncrementalSortEstimate(IncrementalSortState *node, ParallelContext *pcxt); +extern void ExecIncrementalSortInitializeDSM(IncrementalSortState *node, ParallelContext *pcxt); +extern void ExecIncrementalSortInitializeWorker(IncrementalSortState *node, ParallelWorkerContext *pcxt); +extern void ExecIncrementalSortRetrieveInstrumentation(IncrementalSortState *node); + +#endif /* NODEINCREMENTALSORT_H */ diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h new file mode 100644 index 0000000..47b0395 --- /dev/null +++ b/src/include/executor/nodeIndexonlyscan.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------- + * + * nodeIndexonlyscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeIndexonlyscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEINDEXONLYSCAN_H +#define NODEINDEXONLYSCAN_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags); +extern void ExecEndIndexOnlyScan(IndexOnlyScanState *node); +extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node); +extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node); +extern void ExecReScanIndexOnlyScan(IndexOnlyScanState *node); + +/* Support functions for parallel index-only scans */ +extern void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, + ParallelContext *pcxt); +extern void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, + ParallelContext *pcxt); +extern void ExecIndexOnlyScanReInitializeDSM(IndexOnlyScanState *node, + ParallelContext *pcxt); +extern void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, + ParallelWorkerContext *pwcxt); + +#endif /* NODEINDEXONLYSCAN_H */ diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h new file mode 100644 index 0000000..0a075f9 --- /dev/null +++ b/src/include/executor/nodeIndexscan.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * nodeIndexscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeIndexscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEINDEXSCAN_H +#define NODEINDEXSCAN_H + +#include "access/genam.h" +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags); +extern void ExecEndIndexScan(IndexScanState *node); +extern void ExecIndexMarkPos(IndexScanState *node); +extern void ExecIndexRestrPos(IndexScanState *node); +extern void ExecReScanIndexScan(IndexScanState *node); +extern void ExecIndexScanEstimate(IndexScanState *node, ParallelContext *pcxt); +extern void ExecIndexScanInitializeDSM(IndexScanState *node, ParallelContext *pcxt); +extern void ExecIndexScanReInitializeDSM(IndexScanState *node, ParallelContext *pcxt); +extern void ExecIndexScanInitializeWorker(IndexScanState *node, + ParallelWorkerContext *pwcxt); + +/* + * These routines are exported to share code with nodeIndexonlyscan.c and + * nodeBitmapIndexscan.c + */ +extern void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, + List *quals, bool isorderby, + ScanKey *scanKeys, int *numScanKeys, + IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, + IndexArrayKeyInfo **arrayKeys, int *numArrayKeys); +extern void ExecIndexEvalRuntimeKeys(ExprContext *econtext, + IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys); +extern bool ExecIndexEvalArrayKeys(ExprContext *econtext, + IndexArrayKeyInfo *arrayKeys, int numArrayKeys); +extern bool ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys); + +#endif /* NODEINDEXSCAN_H */ diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h new file mode 100644 index 0000000..6da0c40 --- /dev/null +++ b/src/include/executor/nodeLimit.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeLimit.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeLimit.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODELIMIT_H +#define NODELIMIT_H + +#include "nodes/execnodes.h" + +extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags); +extern void ExecEndLimit(LimitState *node); +extern void ExecReScanLimit(LimitState *node); + +#endif /* NODELIMIT_H */ diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h new file mode 100644 index 0000000..125a32b --- /dev/null +++ b/src/include/executor/nodeLockRows.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeLockRows.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeLockRows.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODELOCKROWS_H +#define NODELOCKROWS_H + +#include "nodes/execnodes.h" + +extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags); +extern void ExecEndLockRows(LockRowsState *node); +extern void ExecReScanLockRows(LockRowsState *node); + +#endif /* NODELOCKROWS_H */ diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h new file mode 100644 index 0000000..21a6860 --- /dev/null +++ b/src/include/executor/nodeMaterial.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * nodeMaterial.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeMaterial.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEMATERIAL_H +#define NODEMATERIAL_H + +#include "nodes/execnodes.h" + +extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags); +extern void ExecEndMaterial(MaterialState *node); +extern void ExecMaterialMarkPos(MaterialState *node); +extern void ExecMaterialRestrPos(MaterialState *node); +extern void ExecReScanMaterial(MaterialState *node); + +#endif /* NODEMATERIAL_H */ diff --git a/src/include/executor/nodeMemoize.h b/src/include/executor/nodeMemoize.h new file mode 100644 index 0000000..4643163 --- /dev/null +++ b/src/include/executor/nodeMemoize.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * nodeMemoize.h + * + * + * + * Portions Copyright (c) 2021-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeMemoize.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEMEMOIZE_H +#define NODEMEMOIZE_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern MemoizeState *ExecInitMemoize(Memoize *node, EState *estate, int eflags); +extern void ExecEndMemoize(MemoizeState *node); +extern void ExecReScanMemoize(MemoizeState *node); +extern double ExecEstimateCacheEntryOverheadBytes(double ntuples); +extern void ExecMemoizeEstimate(MemoizeState *node, + ParallelContext *pcxt); +extern void ExecMemoizeInitializeDSM(MemoizeState *node, + ParallelContext *pcxt); +extern void ExecMemoizeInitializeWorker(MemoizeState *node, + ParallelWorkerContext *pwcxt); +extern void ExecMemoizeRetrieveInstrumentation(MemoizeState *node); + +#endif /* NODEMEMOIZE_H */ diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h new file mode 100644 index 0000000..97fe3b0 --- /dev/null +++ b/src/include/executor/nodeMergeAppend.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeMergeAppend.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeMergeAppend.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEMERGEAPPEND_H +#define NODEMERGEAPPEND_H + +#include "nodes/execnodes.h" + +extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags); +extern void ExecEndMergeAppend(MergeAppendState *node); +extern void ExecReScanMergeAppend(MergeAppendState *node); + +#endif /* NODEMERGEAPPEND_H */ diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h new file mode 100644 index 0000000..26ab517 --- /dev/null +++ b/src/include/executor/nodeMergejoin.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeMergejoin.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeMergejoin.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEMERGEJOIN_H +#define NODEMERGEJOIN_H + +#include "nodes/execnodes.h" + +extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags); +extern void ExecEndMergeJoin(MergeJoinState *node); +extern void ExecReScanMergeJoin(MergeJoinState *node); + +#endif /* NODEMERGEJOIN_H */ diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h new file mode 100644 index 0000000..372cec4 --- /dev/null +++ b/src/include/executor/nodeModifyTable.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * nodeModifyTable.h + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeModifyTable.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEMODIFYTABLE_H +#define NODEMODIFYTABLE_H + +#include "nodes/execnodes.h" + +extern void ExecInitStoredGenerated(ResultRelInfo *resultRelInfo, + EState *estate, + CmdType cmdtype); + +extern void ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, + EState *estate, TupleTableSlot *slot, + CmdType cmdtype); + +extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags); +extern void ExecEndModifyTable(ModifyTableState *node); +extern void ExecReScanModifyTable(ModifyTableState *node); + +extern void ExecInitMergeTupleSlots(ModifyTableState *mtstate, + ResultRelInfo *resultRelInfo); + +#endif /* NODEMODIFYTABLE_H */ diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h new file mode 100644 index 0000000..d595124 --- /dev/null +++ b/src/include/executor/nodeNamedtuplestorescan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeNamedtuplestorescan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeNamedtuplestorescan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODENAMEDTUPLESTORESCAN_H +#define NODENAMEDTUPLESTORESCAN_H + +#include "nodes/execnodes.h" + +extern NamedTuplestoreScanState *ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags); +extern void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node); +extern void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node); + +#endif /* NODENAMEDTUPLESTORESCAN_H */ diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h new file mode 100644 index 0000000..b1411fa --- /dev/null +++ b/src/include/executor/nodeNestloop.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeNestloop.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeNestloop.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODENESTLOOP_H +#define NODENESTLOOP_H + +#include "nodes/execnodes.h" + +extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags); +extern void ExecEndNestLoop(NestLoopState *node); +extern void ExecReScanNestLoop(NestLoopState *node); + +#endif /* NODENESTLOOP_H */ diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h new file mode 100644 index 0000000..2c2b582 --- /dev/null +++ b/src/include/executor/nodeProjectSet.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeProjectSet.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeProjectSet.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEPROJECTSET_H +#define NODEPROJECTSET_H + +#include "nodes/execnodes.h" + +extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags); +extern void ExecEndProjectSet(ProjectSetState *node); +extern void ExecReScanProjectSet(ProjectSetState *node); + +#endif /* NODEPROJECTSET_H */ diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h new file mode 100644 index 0000000..2d20470 --- /dev/null +++ b/src/include/executor/nodeRecursiveunion.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeRecursiveunion.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeRecursiveunion.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODERECURSIVEUNION_H +#define NODERECURSIVEUNION_H + +#include "nodes/execnodes.h" + +extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags); +extern void ExecEndRecursiveUnion(RecursiveUnionState *node); +extern void ExecReScanRecursiveUnion(RecursiveUnionState *node); + +#endif /* NODERECURSIVEUNION_H */ diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h new file mode 100644 index 0000000..ebb131d --- /dev/null +++ b/src/include/executor/nodeResult.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * nodeResult.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeResult.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODERESULT_H +#define NODERESULT_H + +#include "nodes/execnodes.h" + +extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags); +extern void ExecEndResult(ResultState *node); +extern void ExecResultMarkPos(ResultState *node); +extern void ExecResultRestrPos(ResultState *node); +extern void ExecReScanResult(ResultState *node); + +#endif /* NODERESULT_H */ diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h new file mode 100644 index 0000000..340b41a --- /dev/null +++ b/src/include/executor/nodeSamplescan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeSamplescan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSamplescan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESAMPLESCAN_H +#define NODESAMPLESCAN_H + +#include "nodes/execnodes.h" + +extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags); +extern void ExecEndSampleScan(SampleScanState *node); +extern void ExecReScanSampleScan(SampleScanState *node); + +#endif /* NODESAMPLESCAN_H */ diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h new file mode 100644 index 0000000..c225ba6 --- /dev/null +++ b/src/include/executor/nodeSeqscan.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * nodeSeqscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSeqscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESEQSCAN_H +#define NODESEQSCAN_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags); +extern void ExecEndSeqScan(SeqScanState *node); +extern void ExecReScanSeqScan(SeqScanState *node); + +/* parallel scan support */ +extern void ExecSeqScanEstimate(SeqScanState *node, ParallelContext *pcxt); +extern void ExecSeqScanInitializeDSM(SeqScanState *node, ParallelContext *pcxt); +extern void ExecSeqScanReInitializeDSM(SeqScanState *node, ParallelContext *pcxt); +extern void ExecSeqScanInitializeWorker(SeqScanState *node, + ParallelWorkerContext *pwcxt); + +#endif /* NODESEQSCAN_H */ diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h new file mode 100644 index 0000000..a504cf8 --- /dev/null +++ b/src/include/executor/nodeSetOp.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeSetOp.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSetOp.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESETOP_H +#define NODESETOP_H + +#include "nodes/execnodes.h" + +extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags); +extern void ExecEndSetOp(SetOpState *node); +extern void ExecReScanSetOp(SetOpState *node); + +#endif /* NODESETOP_H */ diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h new file mode 100644 index 0000000..008e6a6 --- /dev/null +++ b/src/include/executor/nodeSort.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * nodeSort.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSort.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESORT_H +#define NODESORT_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" + +extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags); +extern void ExecEndSort(SortState *node); +extern void ExecSortMarkPos(SortState *node); +extern void ExecSortRestrPos(SortState *node); +extern void ExecReScanSort(SortState *node); + +/* parallel instrumentation support */ +extern void ExecSortEstimate(SortState *node, ParallelContext *pcxt); +extern void ExecSortInitializeDSM(SortState *node, ParallelContext *pcxt); +extern void ExecSortInitializeWorker(SortState *node, ParallelWorkerContext *pwcxt); +extern void ExecSortRetrieveInstrumentation(SortState *node); + +#endif /* NODESORT_H */ diff --git a/src/include/executor/nodeSubplan.h b/src/include/executor/nodeSubplan.h new file mode 100644 index 0000000..75cc6d5 --- /dev/null +++ b/src/include/executor/nodeSubplan.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * nodeSubplan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSubplan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESUBPLAN_H +#define NODESUBPLAN_H + +#include "nodes/execnodes.h" + +extern SubPlanState *ExecInitSubPlan(SubPlan *subplan, PlanState *parent); + +extern Datum ExecSubPlan(SubPlanState *node, ExprContext *econtext, bool *isNull); + +extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent); + +extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext); + +extern void ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext); + +#endif /* NODESUBPLAN_H */ diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h new file mode 100644 index 0000000..a09e2be --- /dev/null +++ b/src/include/executor/nodeSubqueryscan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeSubqueryscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeSubqueryscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODESUBQUERYSCAN_H +#define NODESUBQUERYSCAN_H + +#include "nodes/execnodes.h" + +extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags); +extern void ExecEndSubqueryScan(SubqueryScanState *node); +extern void ExecReScanSubqueryScan(SubqueryScanState *node); + +#endif /* NODESUBQUERYSCAN_H */ diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h new file mode 100644 index 0000000..2b82e7d --- /dev/null +++ b/src/include/executor/nodeTableFuncscan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeTableFuncscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeTableFuncscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODETABLEFUNCSCAN_H +#define NODETABLEFUNCSCAN_H + +#include "nodes/execnodes.h" + +extern TableFuncScanState *ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags); +extern void ExecEndTableFuncScan(TableFuncScanState *node); +extern void ExecReScanTableFuncScan(TableFuncScanState *node); + +#endif /* NODETABLEFUNCSCAN_H */ diff --git a/src/include/executor/nodeTidrangescan.h b/src/include/executor/nodeTidrangescan.h new file mode 100644 index 0000000..f122e09 --- /dev/null +++ b/src/include/executor/nodeTidrangescan.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * nodeTidrangescan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeTidrangescan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODETIDRANGESCAN_H +#define NODETIDRANGESCAN_H + +#include "nodes/execnodes.h" + +extern TidRangeScanState *ExecInitTidRangeScan(TidRangeScan *node, + EState *estate, int eflags); +extern void ExecEndTidRangeScan(TidRangeScanState *node); +extern void ExecReScanTidRangeScan(TidRangeScanState *node); + +#endif /* NODETIDRANGESCAN_H */ diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h new file mode 100644 index 0000000..91a5f89 --- /dev/null +++ b/src/include/executor/nodeTidscan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeTidscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeTidscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODETIDSCAN_H +#define NODETIDSCAN_H + +#include "nodes/execnodes.h" + +extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags); +extern void ExecEndTidScan(TidScanState *node); +extern void ExecReScanTidScan(TidScanState *node); + +#endif /* NODETIDSCAN_H */ diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h new file mode 100644 index 0000000..61f09d9 --- /dev/null +++ b/src/include/executor/nodeUnique.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeUnique.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeUnique.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEUNIQUE_H +#define NODEUNIQUE_H + +#include "nodes/execnodes.h" + +extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags); +extern void ExecEndUnique(UniqueState *node); +extern void ExecReScanUnique(UniqueState *node); + +#endif /* NODEUNIQUE_H */ diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h new file mode 100644 index 0000000..07c13ef --- /dev/null +++ b/src/include/executor/nodeValuesscan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeValuesscan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeValuesscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEVALUESSCAN_H +#define NODEVALUESSCAN_H + +#include "nodes/execnodes.h" + +extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags); +extern void ExecEndValuesScan(ValuesScanState *node); +extern void ExecReScanValuesScan(ValuesScanState *node); + +#endif /* NODEVALUESSCAN_H */ diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h new file mode 100644 index 0000000..4e62c89 --- /dev/null +++ b/src/include/executor/nodeWindowAgg.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeWindowAgg.h + * prototypes for nodeWindowAgg.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeWindowAgg.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEWINDOWAGG_H +#define NODEWINDOWAGG_H + +#include "nodes/execnodes.h" + +extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags); +extern void ExecEndWindowAgg(WindowAggState *node); +extern void ExecReScanWindowAgg(WindowAggState *node); + +#endif /* NODEWINDOWAGG_H */ diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h new file mode 100644 index 0000000..17842de --- /dev/null +++ b/src/include/executor/nodeWorktablescan.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * nodeWorktablescan.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/nodeWorktablescan.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEWORKTABLESCAN_H +#define NODEWORKTABLESCAN_H + +#include "nodes/execnodes.h" + +extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags); +extern void ExecEndWorkTableScan(WorkTableScanState *node); +extern void ExecReScanWorkTableScan(WorkTableScanState *node); + +#endif /* NODEWORKTABLESCAN_H */ diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h new file mode 100644 index 0000000..b2c0c74 --- /dev/null +++ b/src/include/executor/spi.h @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------- + * + * spi.h + * Server Programming Interface public declarations + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/spi.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPI_H +#define SPI_H + +#include "commands/trigger.h" +#include "lib/ilist.h" +#include "parser/parser.h" +#include "utils/portal.h" + + +typedef struct SPITupleTable +{ + /* Public members */ + TupleDesc tupdesc; /* tuple descriptor */ + HeapTuple *vals; /* array of tuples */ + uint64 numvals; /* number of valid tuples */ + + /* Private members, not intended for external callers */ + uint64 alloced; /* allocated length of vals array */ + MemoryContext tuptabcxt; /* memory context of result table */ + slist_node next; /* link for internal bookkeeping */ + SubTransactionId subid; /* subxact in which tuptable was created */ +} SPITupleTable; + +/* Optional arguments for SPI_prepare_extended */ +typedef struct SPIPrepareOptions +{ + ParserSetupHook parserSetup; + void *parserSetupArg; + RawParseMode parseMode; + int cursorOptions; +} SPIPrepareOptions; + +/* Optional arguments for SPI_execute[_plan]_extended */ +typedef struct SPIExecuteOptions +{ + ParamListInfo params; + bool read_only; + bool allow_nonatomic; + bool must_return_tuples; + uint64 tcount; + DestReceiver *dest; + ResourceOwner owner; +} SPIExecuteOptions; + +/* Optional arguments for SPI_cursor_parse_open */ +typedef struct SPIParseOpenOptions +{ + ParamListInfo params; + int cursorOptions; + bool read_only; +} SPIParseOpenOptions; + +/* Plans are opaque structs for standard users of SPI */ +typedef struct _SPI_plan *SPIPlanPtr; + +#define SPI_ERROR_CONNECT (-1) +#define SPI_ERROR_COPY (-2) +#define SPI_ERROR_OPUNKNOWN (-3) +#define SPI_ERROR_UNCONNECTED (-4) +#define SPI_ERROR_CURSOR (-5) /* not used anymore */ +#define SPI_ERROR_ARGUMENT (-6) +#define SPI_ERROR_PARAM (-7) +#define SPI_ERROR_TRANSACTION (-8) +#define SPI_ERROR_NOATTRIBUTE (-9) +#define SPI_ERROR_NOOUTFUNC (-10) +#define SPI_ERROR_TYPUNKNOWN (-11) +#define SPI_ERROR_REL_DUPLICATE (-12) +#define SPI_ERROR_REL_NOT_FOUND (-13) + +#define SPI_OK_CONNECT 1 +#define SPI_OK_FINISH 2 +#define SPI_OK_FETCH 3 +#define SPI_OK_UTILITY 4 +#define SPI_OK_SELECT 5 +#define SPI_OK_SELINTO 6 +#define SPI_OK_INSERT 7 +#define SPI_OK_DELETE 8 +#define SPI_OK_UPDATE 9 +#define SPI_OK_CURSOR 10 +#define SPI_OK_INSERT_RETURNING 11 +#define SPI_OK_DELETE_RETURNING 12 +#define SPI_OK_UPDATE_RETURNING 13 +#define SPI_OK_REWRITTEN 14 +#define SPI_OK_REL_REGISTER 15 +#define SPI_OK_REL_UNREGISTER 16 +#define SPI_OK_TD_REGISTER 17 +#define SPI_OK_MERGE 18 + +#define SPI_OPT_NONATOMIC (1 << 0) + +/* These used to be functions, now just no-ops for backwards compatibility */ +#define SPI_push() ((void) 0) +#define SPI_pop() ((void) 0) +#define SPI_push_conditional() false +#define SPI_pop_conditional(pushed) ((void) 0) +#define SPI_restore_connection() ((void) 0) + +extern PGDLLIMPORT uint64 SPI_processed; +extern PGDLLIMPORT SPITupleTable *SPI_tuptable; +extern PGDLLIMPORT int SPI_result; + +extern int SPI_connect(void); +extern int SPI_connect_ext(int options); +extern int SPI_finish(void); +extern int SPI_execute(const char *src, bool read_only, long tcount); +extern int SPI_execute_extended(const char *src, + const SPIExecuteOptions *options); +extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, + bool read_only, long tcount); +extern int SPI_execute_plan_extended(SPIPlanPtr plan, + const SPIExecuteOptions *options); +extern int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, + ParamListInfo params, + bool read_only, long tcount); +extern int SPI_exec(const char *src, long tcount); +extern int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, + long tcount); +extern int SPI_execute_snapshot(SPIPlanPtr plan, + Datum *Values, const char *Nulls, + Snapshot snapshot, + Snapshot crosscheck_snapshot, + bool read_only, bool fire_triggers, long tcount); +extern int SPI_execute_with_args(const char *src, + int nargs, Oid *argtypes, + Datum *Values, const char *Nulls, + bool read_only, long tcount); +extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); +extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, + int cursorOptions); +extern SPIPlanPtr SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options); +extern SPIPlanPtr SPI_prepare_params(const char *src, + ParserSetupHook parserSetup, + void *parserSetupArg, + int cursorOptions); +extern int SPI_keepplan(SPIPlanPtr plan); +extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan); +extern int SPI_freeplan(SPIPlanPtr plan); + +extern Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex); +extern int SPI_getargcount(SPIPlanPtr plan); +extern bool SPI_is_cursor_plan(SPIPlanPtr plan); +extern bool SPI_plan_is_valid(SPIPlanPtr plan); +extern const char *SPI_result_code_string(int code); + +extern List *SPI_plan_get_plan_sources(SPIPlanPtr plan); +extern CachedPlan *SPI_plan_get_cached_plan(SPIPlanPtr plan); + +extern HeapTuple SPI_copytuple(HeapTuple tuple); +extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc); +extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, + int *attnum, Datum *Values, const char *Nulls); +extern int SPI_fnumber(TupleDesc tupdesc, const char *fname); +extern char *SPI_fname(TupleDesc tupdesc, int fnumber); +extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber); +extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull); +extern char *SPI_gettype(TupleDesc tupdesc, int fnumber); +extern Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber); +extern char *SPI_getrelname(Relation rel); +extern char *SPI_getnspname(Relation rel); +extern void *SPI_palloc(Size size); +extern void *SPI_repalloc(void *pointer, Size size); +extern void SPI_pfree(void *pointer); +extern Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen); +extern void SPI_freetuple(HeapTuple pointer); +extern void SPI_freetuptable(SPITupleTable *tuptable); + +extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, + Datum *Values, const char *Nulls, bool read_only); +extern Portal SPI_cursor_open_with_args(const char *name, + const char *src, + int nargs, Oid *argtypes, + Datum *Values, const char *Nulls, + bool read_only, int cursorOptions); +extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, + ParamListInfo params, bool read_only); +extern Portal SPI_cursor_parse_open(const char *name, + const char *src, + const SPIParseOpenOptions *options); +extern Portal SPI_cursor_find(const char *name); +extern void SPI_cursor_fetch(Portal portal, bool forward, long count); +extern void SPI_cursor_move(Portal portal, bool forward, long count); +extern void SPI_scroll_cursor_fetch(Portal, FetchDirection direction, long count); +extern void SPI_scroll_cursor_move(Portal, FetchDirection direction, long count); +extern void SPI_cursor_close(Portal portal); + +extern int SPI_register_relation(EphemeralNamedRelation enr); +extern int SPI_unregister_relation(const char *name); +extern int SPI_register_trigger_data(TriggerData *tdata); + +extern void SPI_start_transaction(void); +extern void SPI_commit(void); +extern void SPI_commit_and_chain(void); +extern void SPI_rollback(void); +extern void SPI_rollback_and_chain(void); + +extern void AtEOXact_SPI(bool isCommit); +extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid); +extern bool SPI_inside_nonatomic_context(void); + +#endif /* SPI_H */ diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h new file mode 100644 index 0000000..950e2b1 --- /dev/null +++ b/src/include/executor/spi_priv.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------- + * + * spi_priv.h + * Server Programming Interface private declarations + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/spi_priv.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPI_PRIV_H +#define SPI_PRIV_H + +#include "executor/spi.h" +#include "utils/queryenvironment.h" + + +#define _SPI_PLAN_MAGIC 569278163 + +typedef struct +{ + /* current results */ + uint64 processed; /* by Executor */ + SPITupleTable *tuptable; /* tuptable currently being built */ + + /* subtransaction in which current Executor call was started */ + SubTransactionId execSubid; + + /* resources of this execution context */ + slist_head tuptables; /* list of all live SPITupleTables */ + MemoryContext procCxt; /* procedure context */ + MemoryContext execCxt; /* executor context */ + MemoryContext savedcxt; /* context of SPI_connect's caller */ + SubTransactionId connectSubid; /* ID of connecting subtransaction */ + QueryEnvironment *queryEnv; /* query environment setup for SPI level */ + + /* transaction management support */ + bool atomic; /* atomic execution context, does not allow + * transactions */ + bool internal_xact; /* SPI-managed transaction boundary, skip + * cleanup */ + + /* saved values of API global variables for previous nesting level */ + uint64 outer_processed; + SPITupleTable *outer_tuptable; + int outer_result; +} _SPI_connection; + +/* + * SPI plans have three states: saved, unsaved, or temporary. + * + * Ordinarily, the _SPI_plan struct itself as well as the argtypes array + * are in a dedicated memory context identified by plancxt (which can be + * really small). All the other subsidiary state is in plancache entries + * identified by plancache_list (note: the list cells themselves are in + * plancxt). + * + * In an unsaved plan, the plancxt as well as the plancache entries' contexts + * are children of the SPI procedure context, so they'll all disappear at + * function exit. plancache.c also knows that the plancache entries are + * "unsaved", so it doesn't link them into its global list; hence they do + * not respond to inval events. This is OK since we are presumably holding + * adequate locks to prevent other backends from messing with the tables. + * + * For a saved plan, the plancxt is made a child of CacheMemoryContext + * since it should persist until explicitly destroyed. Likewise, the + * plancache entries will be under CacheMemoryContext since we tell + * plancache.c to save them. We rely on plancache.c to keep the cache + * entries up-to-date as needed in the face of invalidation events. + * + * There are also "temporary" SPI plans, in which the _SPI_plan struct is + * not even palloc'd but just exists in some function's local variable. + * The plancache entries are unsaved and exist under the SPI executor context, + * while additional data such as argtypes and list cells is loose in the SPI + * executor context. Such plans can be identified by having plancxt == NULL. + * + * We can also have "one-shot" SPI plans (which are typically temporary, + * as described above). These are meant to be executed once and discarded, + * and various optimizations are made on the assumption of single use. + * Note in particular that the CachedPlanSources within such an SPI plan + * are not "complete" until execution. + * + * Note: if the original query string contained only whitespace and comments, + * the plancache_list will be NIL and so there is no place to store the + * query string. We don't care about that, but we do care about the + * argument type array, which is why it's seemingly-redundantly stored. + */ +typedef struct _SPI_plan +{ + int magic; /* should equal _SPI_PLAN_MAGIC */ + bool saved; /* saved or unsaved plan? */ + bool oneshot; /* one-shot plan? */ + List *plancache_list; /* one CachedPlanSource per parsetree */ + MemoryContext plancxt; /* Context containing _SPI_plan and data */ + RawParseMode parse_mode; /* raw_parser() mode */ + int cursor_options; /* Cursor options used for planning */ + int nargs; /* number of plan arguments */ + Oid *argtypes; /* Argument types (NULL if nargs is 0) */ + ParserSetupHook parserSetup; /* alternative parameter spec method */ + void *parserSetupArg; +} _SPI_plan; + +#endif /* SPI_PRIV_H */ diff --git a/src/include/executor/tablefunc.h b/src/include/executor/tablefunc.h new file mode 100644 index 0000000..23b7ae5 --- /dev/null +++ b/src/include/executor/tablefunc.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * tablefunc.h + * interface for TableFunc executor node + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/tablefunc.h + * + *------------------------------------------------------------------------- + */ +#ifndef _TABLEFUNC_H +#define _TABLEFUNC_H + +/* Forward-declare this to avoid including execnodes.h here */ +struct TableFuncScanState; + +/* + * TableFuncRoutine holds function pointers used for generating content of + * table-producer functions, such as XMLTABLE. + * + * InitOpaque initializes table builder private objects. The output tuple + * descriptor, input functions for the columns, and typioparams are passed + * from executor state. + * + * SetDocument is called to define the input document. The table builder may + * apply additional transformations not exposed outside the table builder + * context. + * + * SetNamespace is called to pass namespace declarations from the table + * expression. This function may be NULL if namespaces are not supported by + * the table builder. Namespaces must be given before setting the row and + * column filters. If the name is given as NULL, the entry shall be for the + * default namespace. + * + * SetRowFilter is called do define the row-generating filter, which shall be + * used to extract each row from the input document. + * + * SetColumnFilter is called once for each column, to define the column- + * generating filter for the given column. + * + * FetchRow shall be called repeatedly until it returns that no more rows are + * found in the document. On each invocation it shall set state in the table + * builder context such that each subsequent GetValue call returns the values + * for the indicated column for the row being processed. + * + * DestroyOpaque shall release all resources associated with a table builder + * context. It may be called either because all rows have been consumed, or + * because an error occurred while processing the table expression. + */ +typedef struct TableFuncRoutine +{ + void (*InitOpaque) (struct TableFuncScanState *state, int natts); + void (*SetDocument) (struct TableFuncScanState *state, Datum value); + void (*SetNamespace) (struct TableFuncScanState *state, const char *name, + const char *uri); + void (*SetRowFilter) (struct TableFuncScanState *state, const char *path); + void (*SetColumnFilter) (struct TableFuncScanState *state, + const char *path, int colnum); + bool (*FetchRow) (struct TableFuncScanState *state); + Datum (*GetValue) (struct TableFuncScanState *state, int colnum, + Oid typid, int32 typmod, bool *isnull); + void (*DestroyOpaque) (struct TableFuncScanState *state); +} TableFuncRoutine; + +#endif /* _TABLEFUNC_H */ diff --git a/src/include/executor/tqueue.h b/src/include/executor/tqueue.h new file mode 100644 index 0000000..c9e3ffd --- /dev/null +++ b/src/include/executor/tqueue.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * tqueue.h + * Use shm_mq to send & receive tuples between parallel backends + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/tqueue.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TQUEUE_H +#define TQUEUE_H + +#include "storage/shm_mq.h" +#include "tcop/dest.h" + +/* Opaque struct, only known inside tqueue.c. */ +typedef struct TupleQueueReader TupleQueueReader; + +/* Use this to send tuples to a shm_mq. */ +extern DestReceiver *CreateTupleQueueDestReceiver(shm_mq_handle *handle); + +/* Use these to receive tuples from a shm_mq. */ +extern TupleQueueReader *CreateTupleQueueReader(shm_mq_handle *handle); +extern void DestroyTupleQueueReader(TupleQueueReader *reader); +extern MinimalTuple TupleQueueReaderNext(TupleQueueReader *reader, + bool nowait, bool *done); + +#endif /* TQUEUE_H */ diff --git a/src/include/executor/tstoreReceiver.h b/src/include/executor/tstoreReceiver.h new file mode 100644 index 0000000..4e168b6 --- /dev/null +++ b/src/include/executor/tstoreReceiver.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * tstoreReceiver.h + * prototypes for tstoreReceiver.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/tstoreReceiver.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TSTORE_RECEIVER_H +#define TSTORE_RECEIVER_H + +#include "tcop/dest.h" +#include "utils/tuplestore.h" + + +extern DestReceiver *CreateTuplestoreDestReceiver(void); + +extern void SetTuplestoreDestReceiverParams(DestReceiver *self, + Tuplestorestate *tStore, + MemoryContext tContext, + bool detoast, + TupleDesc target_tupdesc, + const char *map_failure_msg); + +#endif /* TSTORE_RECEIVER_H */ diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h new file mode 100644 index 0000000..6306bb6 --- /dev/null +++ b/src/include/executor/tuptable.h @@ -0,0 +1,487 @@ +/*------------------------------------------------------------------------- + * + * tuptable.h + * tuple table support stuff + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/executor/tuptable.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPTABLE_H +#define TUPTABLE_H + +#include "access/htup.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/tupdesc.h" +#include "storage/buf.h" + +/*---------- + * The executor stores tuples in a "tuple table" which is a List of + * independent TupleTableSlots. + * + * There's various different types of tuple table slots, each being able to + * store different types of tuples. Additional types of slots can be added + * without modifying core code. The type of a slot is determined by the + * TupleTableSlotOps* passed to the slot creation routine. The builtin types + * of slots are + * + * 1. physical tuple in a disk buffer page (TTSOpsBufferHeapTuple) + * 2. physical tuple constructed in palloc'ed memory (TTSOpsHeapTuple) + * 3. "minimal" physical tuple constructed in palloc'ed memory + * (TTSOpsMinimalTuple) + * 4. "virtual" tuple consisting of Datum/isnull arrays (TTSOpsVirtual) + * + * + * The first two cases are similar in that they both deal with "materialized" + * tuples, but resource management is different. For a tuple in a disk page + * we need to hold a pin on the buffer until the TupleTableSlot's reference + * to the tuple is dropped; while for a palloc'd tuple we usually want the + * tuple pfree'd when the TupleTableSlot's reference is dropped. + * + * A "minimal" tuple is handled similarly to a palloc'd regular tuple. + * At present, minimal tuples never are stored in buffers, so there is no + * parallel to case 1. Note that a minimal tuple has no "system columns". + * (Actually, it could have an OID, but we have no need to access the OID.) + * + * A "virtual" tuple is an optimization used to minimize physical data copying + * in a nest of plan nodes. Until materialized pass-by-reference Datums in + * the slot point to storage that is not directly associated with the + * TupleTableSlot; generally they will point to part of a tuple stored in a + * lower plan node's output TupleTableSlot, or to a function result + * constructed in a plan node's per-tuple econtext. It is the responsibility + * of the generating plan node to be sure these resources are not released for + * as long as the virtual tuple needs to be valid or is materialized. Note + * also that a virtual tuple does not have any "system columns". + * + * The Datum/isnull arrays of a TupleTableSlot serve double duty. For virtual + * slots they are the authoritative data. For the other builtin slots, + * the arrays contain data extracted from the tuple. (In this state, any + * pass-by-reference Datums point into the physical tuple.) The extracted + * information is built "lazily", ie, only as needed. This serves to avoid + * repeated extraction of data from the physical tuple. + * + * A TupleTableSlot can also be "empty", indicated by flag TTS_FLAG_EMPTY set + * in tts_flags, holding no valid data. This is the only valid state for a + * freshly-created slot that has not yet had a tuple descriptor assigned to + * it. In this state, TTS_SHOULDFREE should not be set in tts_flags, tts_tuple + * must be NULL and tts_nvalid zero. + * + * The tupleDescriptor is simply referenced, not copied, by the TupleTableSlot + * code. The caller of ExecSetSlotDescriptor() is responsible for providing + * a descriptor that will live as long as the slot does. (Typically, both + * slots and descriptors are in per-query memory and are freed by memory + * context deallocation at query end; so it's not worth providing any extra + * mechanism to do more. However, the slot will increment the tupdesc + * reference count if a reference-counted tupdesc is supplied.) + * + * When TTS_SHOULDFREE is set in tts_flags, the physical tuple is "owned" by + * the slot and should be freed when the slot's reference to the tuple is + * dropped. + * + * tts_values/tts_isnull are allocated either when the slot is created (when + * the descriptor is provided), or when a descriptor is assigned to the slot; + * they are of length equal to the descriptor's natts. + * + * The TTS_FLAG_SLOW flag is saved state for + * slot_deform_heap_tuple, and should not be touched by any other code. + *---------- + */ + +/* true = slot is empty */ +#define TTS_FLAG_EMPTY (1 << 1) +#define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0) + +/* should pfree tuple "owned" by the slot? */ +#define TTS_FLAG_SHOULDFREE (1 << 2) +#define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0) + +/* saved state for slot_deform_heap_tuple */ +#define TTS_FLAG_SLOW (1 << 3) +#define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0) + +/* fixed tuple descriptor */ +#define TTS_FLAG_FIXED (1 << 4) +#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0) + +struct TupleTableSlotOps; +typedef struct TupleTableSlotOps TupleTableSlotOps; + +/* base tuple table slot type */ +typedef struct TupleTableSlot +{ + NodeTag type; +#define FIELDNO_TUPLETABLESLOT_FLAGS 1 + uint16 tts_flags; /* Boolean states */ +#define FIELDNO_TUPLETABLESLOT_NVALID 2 + AttrNumber tts_nvalid; /* # of valid values in tts_values */ + const TupleTableSlotOps *const tts_ops; /* implementation of slot */ +#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4 + TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */ +#define FIELDNO_TUPLETABLESLOT_VALUES 5 + Datum *tts_values; /* current per-attribute values */ +#define FIELDNO_TUPLETABLESLOT_ISNULL 6 + bool *tts_isnull; /* current per-attribute isnull flags */ + MemoryContext tts_mcxt; /* slot itself is in this context */ + ItemPointerData tts_tid; /* stored tuple's tid */ + Oid tts_tableOid; /* table oid of tuple */ +} TupleTableSlot; + +/* routines for a TupleTableSlot implementation */ +struct TupleTableSlotOps +{ + /* Minimum size of the slot */ + size_t base_slot_size; + + /* Initialization. */ + void (*init) (TupleTableSlot *slot); + + /* Destruction. */ + void (*release) (TupleTableSlot *slot); + + /* + * Clear the contents of the slot. Only the contents are expected to be + * cleared and not the tuple descriptor. Typically an implementation of + * this callback should free the memory allocated for the tuple contained + * in the slot. + */ + void (*clear) (TupleTableSlot *slot); + + /* + * Fill up first natts entries of tts_values and tts_isnull arrays with + * values from the tuple contained in the slot. The function may be called + * with natts more than the number of attributes available in the tuple, + * in which case it should set tts_nvalid to the number of returned + * columns. + */ + void (*getsomeattrs) (TupleTableSlot *slot, int natts); + + /* + * Returns value of the given system attribute as a datum and sets isnull + * to false, if it's not NULL. Throws an error if the slot type does not + * support system attributes. + */ + Datum (*getsysattr) (TupleTableSlot *slot, int attnum, bool *isnull); + + /* + * Make the contents of the slot solely depend on the slot, and not on + * underlying resources (like another memory context, buffers, etc). + */ + void (*materialize) (TupleTableSlot *slot); + + /* + * Copy the contents of the source slot into the destination slot's own + * context. Invoked using callback of the destination slot. + */ + void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot); + + /* + * Return a heap tuple "owned" by the slot. It is slot's responsibility to + * free the memory consumed by the heap tuple. If the slot can not "own" a + * heap tuple, it should not implement this callback and should set it as + * NULL. + */ + HeapTuple (*get_heap_tuple) (TupleTableSlot *slot); + + /* + * Return a minimal tuple "owned" by the slot. It is slot's responsibility + * to free the memory consumed by the minimal tuple. If the slot can not + * "own" a minimal tuple, it should not implement this callback and should + * set it as NULL. + */ + MinimalTuple (*get_minimal_tuple) (TupleTableSlot *slot); + + /* + * Return a copy of heap tuple representing the contents of the slot. The + * copy needs to be palloc'd in the current memory context. The slot + * itself is expected to remain unaffected. It is *not* expected to have + * meaningful "system columns" in the copy. The copy is not be "owned" by + * the slot i.e. the caller has to take responsibility to free memory + * consumed by the slot. + */ + HeapTuple (*copy_heap_tuple) (TupleTableSlot *slot); + + /* + * Return a copy of minimal tuple representing the contents of the slot. + * The copy needs to be palloc'd in the current memory context. The slot + * itself is expected to remain unaffected. It is *not* expected to have + * meaningful "system columns" in the copy. The copy is not be "owned" by + * the slot i.e. the caller has to take responsibility to free memory + * consumed by the slot. + */ + MinimalTuple (*copy_minimal_tuple) (TupleTableSlot *slot); +}; + +/* + * Predefined TupleTableSlotOps for various types of TupleTableSlotOps. The + * same are used to identify the type of a given slot. + */ +extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual; +extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple; +extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple; +extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferHeapTuple; + +#define TTS_IS_VIRTUAL(slot) ((slot)->tts_ops == &TTSOpsVirtual) +#define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_ops == &TTSOpsHeapTuple) +#define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_ops == &TTSOpsMinimalTuple) +#define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsBufferHeapTuple) + + +/* + * Tuple table slot implementations. + */ + +typedef struct VirtualTupleTableSlot +{ + TupleTableSlot base; + + char *data; /* data for materialized slots */ +} VirtualTupleTableSlot; + +typedef struct HeapTupleTableSlot +{ + TupleTableSlot base; + +#define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1 + HeapTuple tuple; /* physical tuple */ +#define FIELDNO_HEAPTUPLETABLESLOT_OFF 2 + uint32 off; /* saved state for slot_deform_heap_tuple */ + HeapTupleData tupdata; /* optional workspace for storing tuple */ +} HeapTupleTableSlot; + +/* heap tuple residing in a buffer */ +typedef struct BufferHeapTupleTableSlot +{ + HeapTupleTableSlot base; + + /* + * If buffer is not InvalidBuffer, then the slot is holding a pin on the + * indicated buffer page; drop the pin when we release the slot's + * reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set in + * such a case, since presumably tts_tuple is pointing into the buffer.) + */ + Buffer buffer; /* tuple's buffer, or InvalidBuffer */ +} BufferHeapTupleTableSlot; + +typedef struct MinimalTupleTableSlot +{ + TupleTableSlot base; + + /* + * In a minimal slot tuple points at minhdr and the fields of that struct + * are set correctly for access to the minimal tuple; in particular, + * minhdr.t_data points MINIMAL_TUPLE_OFFSET bytes before mintuple. This + * allows column extraction to treat the case identically to regular + * physical tuples. + */ +#define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1 + HeapTuple tuple; /* tuple wrapper */ + MinimalTuple mintuple; /* minimal tuple, or NULL if none */ + HeapTupleData minhdr; /* workspace for minimal-tuple-only case */ +#define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4 + uint32 off; /* saved state for slot_deform_heap_tuple */ +} MinimalTupleTableSlot; + +/* + * TupIsNull -- is a TupleTableSlot empty? + */ +#define TupIsNull(slot) \ + ((slot) == NULL || TTS_EMPTY(slot)) + +/* in executor/execTuples.c */ +extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc, + const TupleTableSlotOps *tts_ops); +extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc, + const TupleTableSlotOps *tts_ops); +extern void ExecResetTupleTable(List *tupleTable, bool shouldFree); +extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc, + const TupleTableSlotOps *tts_ops); +extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot); +extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc); +extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + bool shouldFree); +extern void ExecForceStoreHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + bool shouldFree); +extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + Buffer buffer); +extern TupleTableSlot *ExecStorePinnedBufferHeapTuple(HeapTuple tuple, + TupleTableSlot *slot, + Buffer buffer); +extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup, + TupleTableSlot *slot, + bool shouldFree); +extern void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, + bool shouldFree); +extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot); +extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot); +extern void ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot); +extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree); +extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, + bool *shouldFree); +extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot); +extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, + int lastAttNum); +extern void slot_getsomeattrs_int(TupleTableSlot *slot, int attnum); + + +#ifndef FRONTEND + +/* + * This function forces the entries of the slot's Datum/isnull arrays to be + * valid at least up through the attnum'th entry. + */ +static inline void +slot_getsomeattrs(TupleTableSlot *slot, int attnum) +{ + if (slot->tts_nvalid < attnum) + slot_getsomeattrs_int(slot, attnum); +} + +/* + * slot_getallattrs + * This function forces all the entries of the slot's Datum/isnull + * arrays to be valid. The caller may then extract data directly + * from those arrays instead of using slot_getattr. + */ +static inline void +slot_getallattrs(TupleTableSlot *slot) +{ + slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts); +} + + +/* + * slot_attisnull + * + * Detect whether an attribute of the slot is null, without actually fetching + * it. + */ +static inline bool +slot_attisnull(TupleTableSlot *slot, int attnum) +{ + AssertArg(attnum > 0); + + if (attnum > slot->tts_nvalid) + slot_getsomeattrs(slot, attnum); + + return slot->tts_isnull[attnum - 1]; +} + +/* + * slot_getattr - fetch one attribute of the slot's contents. + */ +static inline Datum +slot_getattr(TupleTableSlot *slot, int attnum, + bool *isnull) +{ + AssertArg(attnum > 0); + + if (attnum > slot->tts_nvalid) + slot_getsomeattrs(slot, attnum); + + *isnull = slot->tts_isnull[attnum - 1]; + + return slot->tts_values[attnum - 1]; +} + +/* + * slot_getsysattr - fetch a system attribute of the slot's current tuple. + * + * If the slot type does not contain system attributes, this will throw an + * error. Hence before calling this function, callers should make sure that + * the slot type is the one that supports system attributes. + */ +static inline Datum +slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) +{ + AssertArg(attnum < 0); /* caller error */ + + if (attnum == TableOidAttributeNumber) + { + *isnull = false; + return ObjectIdGetDatum(slot->tts_tableOid); + } + else if (attnum == SelfItemPointerAttributeNumber) + { + *isnull = false; + return PointerGetDatum(&slot->tts_tid); + } + + /* Fetch the system attribute from the underlying tuple. */ + return slot->tts_ops->getsysattr(slot, attnum, isnull); +} + +/* + * ExecClearTuple - clear the slot's contents + */ +static inline TupleTableSlot * +ExecClearTuple(TupleTableSlot *slot) +{ + slot->tts_ops->clear(slot); + + return slot; +} + +/* ExecMaterializeSlot - force a slot into the "materialized" state. + * + * This causes the slot's tuple to be a local copy not dependent on any + * external storage (i.e. pointing into a Buffer, or having allocations in + * another memory context). + * + * A typical use for this operation is to prepare a computed tuple for being + * stored on disk. The original data may or may not be virtual, but in any + * case we need a private copy for heap_insert to scribble on. + */ +static inline void +ExecMaterializeSlot(TupleTableSlot *slot) +{ + slot->tts_ops->materialize(slot); +} + +/* + * ExecCopySlotHeapTuple - return HeapTuple allocated in caller's context + */ +static inline HeapTuple +ExecCopySlotHeapTuple(TupleTableSlot *slot) +{ + Assert(!TTS_EMPTY(slot)); + + return slot->tts_ops->copy_heap_tuple(slot); +} + +/* + * ExecCopySlotMinimalTuple - return MinimalTuple allocated in caller's context + */ +static inline MinimalTuple +ExecCopySlotMinimalTuple(TupleTableSlot *slot) +{ + return slot->tts_ops->copy_minimal_tuple(slot); +} + +/* + * ExecCopySlot - copy one slot's contents into another. + * + * If a source's system attributes are supposed to be accessed in the target + * slot, the target slot and source slot types need to match. + */ +static inline TupleTableSlot * +ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) +{ + Assert(!TTS_EMPTY(srcslot)); + AssertArg(srcslot != dstslot); + + dstslot->tts_ops->copyslot(dstslot, srcslot); + + return dstslot; +} + +#endif /* FRONTEND */ + +#endif /* TUPTABLE_H */ diff --git a/src/include/fe_utils/archive.h b/src/include/fe_utils/archive.h new file mode 100644 index 0000000..22e64a5 --- /dev/null +++ b/src/include/fe_utils/archive.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * archive.h + * Routines to access WAL archives from frontend + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/archive.h + * + *------------------------------------------------------------------------- + */ +#ifndef FE_ARCHIVE_H +#define FE_ARCHIVE_H + +extern int RestoreArchivedFile(const char *path, + const char *xlogfname, + off_t expectedSize, + const char *restoreCommand); + +#endif /* FE_ARCHIVE_H */ diff --git a/src/include/fe_utils/cancel.h b/src/include/fe_utils/cancel.h new file mode 100644 index 0000000..3b84daf --- /dev/null +++ b/src/include/fe_utils/cancel.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * Query cancellation support for frontend code + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/cancel.h + * + *------------------------------------------------------------------------- + */ + +#ifndef CANCEL_H +#define CANCEL_H + +#include <signal.h> + +#include "libpq-fe.h" + +extern PGDLLIMPORT volatile sig_atomic_t CancelRequested; + +extern void SetCancelConn(PGconn *conn); +extern void ResetCancelConn(void); + +/* + * A callback can be optionally set up to be called at cancellation + * time. + */ +extern void setup_cancel_handler(void (*cancel_callback) (void)); + +#endif /* CANCEL_H */ diff --git a/src/include/fe_utils/conditional.h b/src/include/fe_utils/conditional.h new file mode 100644 index 0000000..fa53d86 --- /dev/null +++ b/src/include/fe_utils/conditional.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------- + * A stack of automaton states to handle nested conditionals. + * + * This file describes a stack of automaton states which + * allow a manage nested conditionals. + * + * It is used by: + * - "psql" interpreter for handling \if ... \endif + * - "pgbench" interpreter for handling \if ... \endif + * - "pgbench" syntax checker to test for proper nesting + * + * The stack holds the state of enclosing conditionals (are we in + * a true branch? in a false branch? have we already encountered + * a true branch?) so that the interpreter knows whether to execute + * code and whether to evaluate conditions. + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/fe_utils/conditional.h + * + *------------------------------------------------------------------------- + */ +#ifndef CONDITIONAL_H +#define CONDITIONAL_H + +/* + * Possible states of a single level of \if block. + */ +typedef enum ifState +{ + IFSTATE_NONE = 0, /* not currently in an \if block */ + IFSTATE_TRUE, /* currently in an \if or \elif that is true + * and all parent branches (if any) are true */ + IFSTATE_FALSE, /* currently in an \if or \elif that is false + * but no true branch has yet been seen, and + * all parent branches (if any) are true */ + IFSTATE_IGNORED, /* currently in an \elif that follows a true + * branch, or the whole \if is a child of a + * false parent branch */ + IFSTATE_ELSE_TRUE, /* currently in an \else that is true and all + * parent branches (if any) are true */ + IFSTATE_ELSE_FALSE /* currently in an \else that is false or + * ignored */ +} ifState; + +/* + * The state of nested \ifs is stored in a stack. + * + * query_len is used to determine what accumulated text to throw away at the + * end of an inactive branch. (We could, perhaps, teach the lexer to not add + * stuff to the query buffer in the first place when inside an inactive branch; + * but that would be very invasive.) We also need to save and restore the + * lexer's parenthesis nesting depth when throwing away text. (We don't need + * to save and restore any of its other state, such as comment nesting depth, + * because a backslash command could never appear inside a comment or SQL + * literal.) + */ +typedef struct IfStackElem +{ + ifState if_state; /* current state, see enum above */ + int query_len; /* length of query_buf at last branch start */ + int paren_depth; /* parenthesis depth at last branch start */ + struct IfStackElem *next; /* next surrounding \if, if any */ +} IfStackElem; + +typedef struct ConditionalStackData +{ + IfStackElem *head; +} ConditionalStackData; + +typedef struct ConditionalStackData *ConditionalStack; + + +extern ConditionalStack conditional_stack_create(void); + +extern void conditional_stack_reset(ConditionalStack cstack); + +extern void conditional_stack_destroy(ConditionalStack cstack); + +extern int conditional_stack_depth(ConditionalStack cstack); + +extern void conditional_stack_push(ConditionalStack cstack, ifState new_state); + +extern bool conditional_stack_pop(ConditionalStack cstack); + +extern ifState conditional_stack_peek(ConditionalStack cstack); + +extern bool conditional_stack_poke(ConditionalStack cstack, ifState new_state); + +extern bool conditional_stack_empty(ConditionalStack cstack); + +extern bool conditional_active(ConditionalStack cstack); + +extern void conditional_stack_set_query_len(ConditionalStack cstack, int len); + +extern int conditional_stack_get_query_len(ConditionalStack cstack); + +extern void conditional_stack_set_paren_depth(ConditionalStack cstack, int depth); + +extern int conditional_stack_get_paren_depth(ConditionalStack cstack); + +#endif /* CONDITIONAL_H */ diff --git a/src/include/fe_utils/connect_utils.h b/src/include/fe_utils/connect_utils.h new file mode 100644 index 0000000..7461396 --- /dev/null +++ b/src/include/fe_utils/connect_utils.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * Facilities for frontend code to connect to and disconnect from databases. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/connect_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef CONNECT_UTILS_H +#define CONNECT_UTILS_H + +#include "libpq-fe.h" + +enum trivalue +{ + TRI_DEFAULT, + TRI_NO, + TRI_YES +}; + +/* Parameters needed by connectDatabase/connectMaintenanceDatabase */ +typedef struct _connParams +{ + /* These fields record the actual command line parameters */ + const char *dbname; /* this may be a connstring! */ + const char *pghost; + const char *pgport; + const char *pguser; + enum trivalue prompt_password; + /* If not NULL, this overrides the dbname obtained from command line */ + /* (but *only* the DB name, not anything else in the connstring) */ + const char *override_dbname; +} ConnParams; + +extern PGconn *connectDatabase(const ConnParams *cparams, + const char *progname, + bool echo, bool fail_ok, + bool allow_password_reuse); + +extern PGconn *connectMaintenanceDatabase(ConnParams *cparams, + const char *progname, bool echo); + +extern void disconnectDatabase(PGconn *conn); + +#endif /* CONNECT_UTILS_H */ diff --git a/src/include/fe_utils/mbprint.h b/src/include/fe_utils/mbprint.h new file mode 100644 index 0000000..5dd2181 --- /dev/null +++ b/src/include/fe_utils/mbprint.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * Multibyte character printing support for frontend code + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/mbprint.h + * + *------------------------------------------------------------------------- + */ +#ifndef MBPRINT_H +#define MBPRINT_H + +struct lineptr +{ + unsigned char *ptr; + int width; +}; + +extern unsigned char *mbvalidate(unsigned char *pwcs, int encoding); +extern int pg_wcswidth(const char *pwcs, size_t len, int encoding); +extern void pg_wcsformat(const unsigned char *pwcs, size_t len, int encoding, + struct lineptr *lines, int count); +extern void pg_wcssize(const unsigned char *pwcs, size_t len, int encoding, + int *width, int *height, int *format_size); + +#endif /* MBPRINT_H */ diff --git a/src/include/fe_utils/option_utils.h b/src/include/fe_utils/option_utils.h new file mode 100644 index 0000000..03c09fd --- /dev/null +++ b/src/include/fe_utils/option_utils.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * Command line option processing facilities for frontend code + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/option_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef OPTION_UTILS_H +#define OPTION_UTILS_H + +#include "postgres_fe.h" + +typedef void (*help_handler) (const char *progname); + +extern void handle_help_version_opts(int argc, char *argv[], + const char *fixed_progname, + help_handler hlp); +extern bool option_parse_int(const char *optarg, const char *optname, + int min_range, int max_range, + int *result); + +#endif /* OPTION_UTILS_H */ diff --git a/src/include/fe_utils/parallel_slot.h b/src/include/fe_utils/parallel_slot.h new file mode 100644 index 0000000..8ce63c9 --- /dev/null +++ b/src/include/fe_utils/parallel_slot.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * parallel_slot.h + * Parallel support for bin/scripts/ + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/fe_utils/parallel_slot.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARALLEL_SLOT_H +#define PARALLEL_SLOT_H + +#include "fe_utils/connect_utils.h" +#include "libpq-fe.h" + +typedef bool (*ParallelSlotResultHandler) (PGresult *res, PGconn *conn, + void *context); + +typedef struct ParallelSlot +{ + PGconn *connection; /* One connection */ + bool inUse; /* Is the slot being used? */ + + /* + * Prior to issuing a command or query on 'connection', a handler callback + * function may optionally be registered to be invoked to process the + * results, and context information may optionally be registered for use + * by the handler. If unset, these fields should be NULL. + */ + ParallelSlotResultHandler handler; + void *handler_context; +} ParallelSlot; + +typedef struct ParallelSlotArray +{ + int numslots; + ConnParams *cparams; + const char *progname; + bool echo; + const char *initcmd; + ParallelSlot slots[FLEXIBLE_ARRAY_MEMBER]; +} ParallelSlotArray; + +static inline void +ParallelSlotSetHandler(ParallelSlot *slot, ParallelSlotResultHandler handler, + void *context) +{ + slot->handler = handler; + slot->handler_context = context; +} + +static inline void +ParallelSlotClearHandler(ParallelSlot *slot) +{ + slot->handler = NULL; + slot->handler_context = NULL; +} + +extern ParallelSlot *ParallelSlotsGetIdle(ParallelSlotArray *slots, + const char *dbname); + +extern ParallelSlotArray *ParallelSlotsSetup(int numslots, ConnParams *cparams, + const char *progname, bool echo, + const char *initcmd); + +extern void ParallelSlotsAdoptConn(ParallelSlotArray *sa, PGconn *conn); + +extern void ParallelSlotsTerminate(ParallelSlotArray *sa); + +extern bool ParallelSlotsWaitCompletion(ParallelSlotArray *sa); + +extern bool TableCommandResultHandler(PGresult *res, PGconn *conn, + void *context); + +#endif /* PARALLEL_SLOT_H */ diff --git a/src/include/fe_utils/print.h b/src/include/fe_utils/print.h new file mode 100644 index 0000000..bb2f1bf --- /dev/null +++ b/src/include/fe_utils/print.h @@ -0,0 +1,220 @@ +/*------------------------------------------------------------------------- + * + * Query-result printing support for frontend code + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/print.h + * + *------------------------------------------------------------------------- + */ +#ifndef PRINT_H +#define PRINT_H + +#include <signal.h> + +#include "libpq-fe.h" + + +/* This is not a particularly great place for this ... */ +#ifndef __CYGWIN__ +#define DEFAULT_PAGER "more" +#else +#define DEFAULT_PAGER "less" +#endif + +enum printFormat +{ + PRINT_NOTHING = 0, /* to make sure someone initializes this */ + PRINT_ALIGNED, + PRINT_ASCIIDOC, + PRINT_CSV, + PRINT_HTML, + PRINT_LATEX, + PRINT_LATEX_LONGTABLE, + PRINT_TROFF_MS, + PRINT_UNALIGNED, + PRINT_WRAPPED + /* add your favourite output format here ... */ +}; + +typedef struct printTextLineFormat +{ + /* Line drawing characters to be used in various contexts */ + const char *hrule; /* horizontal line character */ + const char *leftvrule; /* left vertical line (+horizontal) */ + const char *midvrule; /* intra-column vertical line (+horizontal) */ + const char *rightvrule; /* right vertical line (+horizontal) */ +} printTextLineFormat; + +typedef enum printTextRule +{ + /* Additional context for selecting line drawing characters */ + PRINT_RULE_TOP, /* top horizontal line */ + PRINT_RULE_MIDDLE, /* intra-data horizontal line */ + PRINT_RULE_BOTTOM, /* bottom horizontal line */ + PRINT_RULE_DATA /* data line (hrule is unused here) */ +} printTextRule; + +typedef enum printTextLineWrap +{ + /* Line wrapping conditions */ + PRINT_LINE_WRAP_NONE, /* No wrapping */ + PRINT_LINE_WRAP_WRAP, /* Wraparound due to overlength line */ + PRINT_LINE_WRAP_NEWLINE /* Newline in data */ +} printTextLineWrap; + +typedef struct printTextFormat +{ + /* A complete line style */ + const char *name; /* for display purposes */ + printTextLineFormat lrule[4]; /* indexed by enum printTextRule */ + const char *midvrule_nl; /* vertical line for continue after newline */ + const char *midvrule_wrap; /* vertical line for wrapped data */ + const char *midvrule_blank; /* vertical line for blank data */ + const char *header_nl_left; /* left mark after newline */ + const char *header_nl_right; /* right mark for newline */ + const char *nl_left; /* left mark after newline */ + const char *nl_right; /* right mark for newline */ + const char *wrap_left; /* left mark after wrapped data */ + const char *wrap_right; /* right mark for wrapped data */ + bool wrap_right_border; /* use right-hand border for wrap marks + * when border=0? */ +} printTextFormat; + +typedef enum unicode_linestyle +{ + UNICODE_LINESTYLE_SINGLE = 0, + UNICODE_LINESTYLE_DOUBLE +} unicode_linestyle; + +struct separator +{ + char *separator; + bool separator_zero; +}; + +typedef struct printTableOpt +{ + enum printFormat format; /* see enum above */ + unsigned short int expanded; /* expanded/vertical output (if supported + * by output format); 0=no, 1=yes, 2=auto */ + unsigned short int border; /* Print a border around the table. 0=none, + * 1=dividing lines, 2=full */ + unsigned short int pager; /* use pager for output (if to stdout and + * stdout is a tty) 0=off 1=on 2=always */ + int pager_min_lines; /* don't use pager unless there are at + * least this many lines */ + bool tuples_only; /* don't output headers, row counts, etc. */ + bool start_table; /* print start decoration, eg <table> */ + bool stop_table; /* print stop decoration, eg </table> */ + bool default_footer; /* allow "(xx rows)" default footer */ + unsigned long prior_records; /* start offset for record counters */ + const printTextFormat *line_style; /* line style (NULL for default) */ + struct separator fieldSep; /* field separator for unaligned text mode */ + struct separator recordSep; /* record separator for unaligned text mode */ + char csvFieldSep[2]; /* field separator for csv format */ + bool numericLocale; /* locale-aware numeric units separator and + * decimal marker */ + char *tableAttr; /* attributes for HTML <table ...> */ + int encoding; /* character encoding */ + int env_columns; /* $COLUMNS on psql start, 0 is unset */ + int columns; /* target width for wrapped format */ + unicode_linestyle unicode_border_linestyle; + unicode_linestyle unicode_column_linestyle; + unicode_linestyle unicode_header_linestyle; +} printTableOpt; + +/* + * Table footers are implemented as a singly-linked list. + * + * This is so that you don't need to know the number of footers in order to + * initialise the printTableContent struct, which is very convenient when + * preparing complex footers (as in describeOneTableDetails). + */ +typedef struct printTableFooter +{ + char *data; + struct printTableFooter *next; +} printTableFooter; + +/* + * The table content struct holds all the information which will be displayed + * by printTable(). + */ +typedef struct printTableContent +{ + const printTableOpt *opt; + const char *title; /* May be NULL */ + int ncolumns; /* Specified in Init() */ + int nrows; /* Specified in Init() */ + const char **headers; /* NULL-terminated array of header strings */ + const char **header; /* Pointer to the last added header */ + const char **cells; /* NULL-terminated array of cell content + * strings */ + const char **cell; /* Pointer to the last added cell */ + long cellsadded; /* Number of cells added this far */ + bool *cellmustfree; /* true for cells that need to be free()d */ + printTableFooter *footers; /* Pointer to the first footer */ + printTableFooter *footer; /* Pointer to the last added footer */ + char *aligns; /* Array of alignment specifiers; 'l' or 'r', + * one per column */ + char *align; /* Pointer to the last added alignment */ +} printTableContent; + +typedef struct printQueryOpt +{ + printTableOpt topt; /* the options above */ + char *nullPrint; /* how to print null entities */ + char *title; /* override title */ + char **footers; /* override footer (default is "(xx rows)") */ + bool translate_header; /* do gettext on column headers */ + const bool *translate_columns; /* translate_columns[i-1] => do gettext on + * col i */ + int n_translate_columns; /* length of translate_columns[] */ +} printQueryOpt; + + +extern PGDLLIMPORT volatile sig_atomic_t cancel_pressed; + +extern PGDLLIMPORT const printTextFormat pg_asciiformat; +extern PGDLLIMPORT const printTextFormat pg_asciiformat_old; +extern PGDLLIMPORT printTextFormat pg_utf8format; /* ideally would be const, + * but... */ + + +extern void disable_sigpipe_trap(void); +extern void restore_sigpipe_trap(void); +extern void set_sigpipe_trap_state(bool ignore); + +extern FILE *PageOutput(int lines, const printTableOpt *topt); +extern void ClosePager(FILE *pagerpipe); + +extern void html_escaped_print(const char *in, FILE *fout); + +extern void printTableInit(printTableContent *const content, + const printTableOpt *opt, const char *title, + const int ncolumns, const int nrows); +extern void printTableAddHeader(printTableContent *const content, + char *header, const bool translate, const char align); +extern void printTableAddCell(printTableContent *const content, + char *cell, const bool translate, const bool mustfree); +extern void printTableAddFooter(printTableContent *const content, + const char *footer); +extern void printTableSetFooter(printTableContent *const content, + const char *footer); +extern void printTableCleanup(printTableContent *const content); +extern void printTable(const printTableContent *cont, + FILE *fout, bool is_pager, FILE *flog); +extern void printQuery(const PGresult *result, const printQueryOpt *opt, + FILE *fout, bool is_pager, FILE *flog); + +extern char column_type_alignment(Oid); + +extern void setDecimalLocale(void); +extern const printTextFormat *get_line_style(const printTableOpt *opt); +extern void refresh_utf8format(const printTableOpt *opt); + +#endif /* PRINT_H */ diff --git a/src/include/fe_utils/psqlscan.h b/src/include/fe_utils/psqlscan.h new file mode 100644 index 0000000..249acab --- /dev/null +++ b/src/include/fe_utils/psqlscan.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * psqlscan.h + * lexical scanner for SQL commands + * + * This lexer used to be part of psql, and that heritage is reflected in + * the file name as well as function and typedef names, though it can now + * be used by other frontend programs as well. It's also possible to extend + * this lexer with a compatible add-on lexer to handle program-specific + * backslash commands. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/psqlscan.h + * + *------------------------------------------------------------------------- + */ +#ifndef PSQLSCAN_H +#define PSQLSCAN_H + +#include "pqexpbuffer.h" + + +/* Abstract type for lexer's internal state */ +typedef struct PsqlScanStateData *PsqlScanState; + +/* Termination states for psql_scan() */ +typedef enum +{ + PSCAN_SEMICOLON, /* found command-ending semicolon */ + PSCAN_BACKSLASH, /* found backslash command */ + PSCAN_INCOMPLETE, /* end of line, SQL statement incomplete */ + PSCAN_EOL /* end of line, SQL possibly complete */ +} PsqlScanResult; + +/* Prompt type returned by psql_scan() */ +typedef enum _promptStatus +{ + PROMPT_READY, + PROMPT_CONTINUE, + PROMPT_COMMENT, + PROMPT_SINGLEQUOTE, + PROMPT_DOUBLEQUOTE, + PROMPT_DOLLARQUOTE, + PROMPT_PAREN, + PROMPT_COPY +} promptStatus_t; + +/* Quoting request types for get_variable() callback */ +typedef enum +{ + PQUOTE_PLAIN, /* just return the actual value */ + PQUOTE_SQL_LITERAL, /* add quotes to make a valid SQL literal */ + PQUOTE_SQL_IDENT, /* quote if needed to make a SQL identifier */ + PQUOTE_SHELL_ARG /* quote if needed to be safe in a shell cmd */ +} PsqlScanQuoteType; + +/* Callback functions to be used by the lexer */ +typedef struct PsqlScanCallbacks +{ + /* Fetch value of a variable, as a free'able string; NULL if unknown */ + /* This pointer can be NULL if no variable substitution is wanted */ + char *(*get_variable) (const char *varname, PsqlScanQuoteType quote, + void *passthrough); +} PsqlScanCallbacks; + + +extern PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks); +extern void psql_scan_destroy(PsqlScanState state); + +extern void psql_scan_set_passthrough(PsqlScanState state, void *passthrough); + +extern void psql_scan_setup(PsqlScanState state, + const char *line, int line_len, + int encoding, bool std_strings); +extern void psql_scan_finish(PsqlScanState state); + +extern PsqlScanResult psql_scan(PsqlScanState state, + PQExpBuffer query_buf, + promptStatus_t *prompt); + +extern void psql_scan_reset(PsqlScanState state); + +extern void psql_scan_reselect_sql_lexer(PsqlScanState state); + +extern bool psql_scan_in_quote(PsqlScanState state); + +#endif /* PSQLSCAN_H */ diff --git a/src/include/fe_utils/psqlscan_int.h b/src/include/fe_utils/psqlscan_int.h new file mode 100644 index 0000000..4905aae --- /dev/null +++ b/src/include/fe_utils/psqlscan_int.h @@ -0,0 +1,157 @@ +/*------------------------------------------------------------------------- + * + * psqlscan_int.h + * lexical scanner internal declarations + * + * This file declares the PsqlScanStateData structure used by psqlscan.l + * and shared by other lexers compatible with it, such as psqlscanslash.l. + * + * One difficult aspect of this code is that we need to work in multibyte + * encodings that are not ASCII-safe. A "safe" encoding is one in which each + * byte of a multibyte character has the high bit set (it's >= 0x80). Since + * all our lexing rules treat all high-bit-set characters alike, we don't + * really need to care whether such a byte is part of a sequence or not. + * In an "unsafe" encoding, we still expect the first byte of a multibyte + * sequence to be >= 0x80, but later bytes might not be. If we scan such + * a sequence as-is, the lexing rules could easily be fooled into matching + * such bytes to ordinary ASCII characters. Our solution for this is to + * substitute 0xFF for each non-first byte within the data presented to flex. + * The flex rules will then pass the FF's through unmolested. The + * psqlscan_emit() subroutine is responsible for looking back to the original + * string and replacing FF's with the corresponding original bytes. + * + * Another interesting thing we do here is scan different parts of the same + * input with physically separate flex lexers (ie, lexers written in separate + * .l files). We can get away with this because the only part of the + * persistent state of a flex lexer that depends on its parsing rule tables + * is the start state number, which is easy enough to manage --- usually, + * in fact, we just need to set it to INITIAL when changing lexers. But to + * make that work at all, we must use re-entrant lexers, so that all the + * relevant state is in the yyscan_t attached to the PsqlScanState; + * if we were using lexers with separate static state we would soon end up + * with dangling buffer pointers in one or the other. Also note that this + * is unlikely to work very nicely if the lexers aren't all built with the + * same flex version, or if they don't use the same flex options. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/psqlscan_int.h + * + *------------------------------------------------------------------------- + */ +#ifndef PSQLSCAN_INT_H +#define PSQLSCAN_INT_H + +#include "fe_utils/psqlscan.h" + +/* + * These are just to allow this file to be compilable standalone for header + * validity checking; in actual use, this file should always be included + * from the body of a flex file, where these symbols are already defined. + */ +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; +#endif + +/* + * We use a stack of flex buffers to handle substitution of psql variables. + * Each stacked buffer contains the as-yet-unread text from one psql variable. + * When we pop the stack all the way, we resume reading from the outer buffer + * identified by scanbufhandle. + */ +typedef struct StackElem +{ + YY_BUFFER_STATE buf; /* flex input control structure */ + char *bufstring; /* data actually being scanned by flex */ + char *origstring; /* copy of original data, if needed */ + char *varname; /* name of variable providing data, or NULL */ + struct StackElem *next; +} StackElem; + +/* + * All working state of the lexer must be stored in PsqlScanStateData + * between calls. This allows us to have multiple open lexer operations, + * which is needed for nested include files. The lexer itself is not + * recursive, but it must be re-entrant. + */ +typedef struct PsqlScanStateData +{ + yyscan_t scanner; /* Flex's state for this PsqlScanState */ + + PQExpBuffer output_buf; /* current output buffer */ + + StackElem *buffer_stack; /* stack of variable expansion buffers */ + + /* + * These variables always refer to the outer buffer, never to any stacked + * variable-expansion buffer. + */ + YY_BUFFER_STATE scanbufhandle; + char *scanbuf; /* start of outer-level input buffer */ + const char *scanline; /* current input line at outer level */ + + /* safe_encoding, curline, refline are used by emit() to replace FFs */ + int encoding; /* encoding being used now */ + bool safe_encoding; /* is current encoding "safe"? */ + bool std_strings; /* are string literals standard? */ + const char *curline; /* actual flex input string for cur buf */ + const char *refline; /* original data for cur buffer */ + + /* + * All this state lives across successive input lines, until explicitly + * reset by psql_scan_reset. start_state is adopted by yylex() on entry, + * and updated with its finishing state on exit. + */ + int start_state; /* yylex's starting/finishing state */ + int state_before_str_stop; /* start cond. before end quote */ + int paren_depth; /* depth of nesting in parentheses */ + int xcdepth; /* depth of nesting in slash-star comments */ + char *dolqstart; /* current $foo$ quote start string */ + + /* + * State to track boundaries of BEGIN ... END blocks in function + * definitions, so that semicolons do not send query too early. + */ + int identifier_count; /* identifiers since start of statement */ + char identifiers[4]; /* records the first few identifiers */ + int begin_depth; /* depth of begin/end pairs */ + + /* + * Callback functions provided by the program making use of the lexer, + * plus a void* callback passthrough argument. + */ + const PsqlScanCallbacks *callbacks; + void *cb_passthrough; +} PsqlScanStateData; + + +/* + * Functions exported by psqlscan.l, but only meant for use within + * compatible lexers. + */ +extern void psqlscan_push_new_buffer(PsqlScanState state, + const char *newstr, const char *varname); +extern void psqlscan_pop_buffer_stack(PsqlScanState state); +extern void psqlscan_select_top_buffer(PsqlScanState state); +extern bool psqlscan_var_is_current_source(PsqlScanState state, + const char *varname); +extern YY_BUFFER_STATE psqlscan_prepare_buffer(PsqlScanState state, + const char *txt, int len, + char **txtcopy); +extern void psqlscan_emit(PsqlScanState state, const char *txt, int len); +extern char *psqlscan_extract_substring(PsqlScanState state, + const char *txt, int len); +extern void psqlscan_escape_variable(PsqlScanState state, + const char *txt, int len, + PsqlScanQuoteType quote); +extern void psqlscan_test_variable(PsqlScanState state, + const char *txt, int len); + +#endif /* PSQLSCAN_INT_H */ diff --git a/src/include/fe_utils/query_utils.h b/src/include/fe_utils/query_utils.h new file mode 100644 index 0000000..90cb3db --- /dev/null +++ b/src/include/fe_utils/query_utils.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * Facilities for frontend code to query a databases. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/query_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef QUERY_UTILS_H +#define QUERY_UTILS_H + +#include "postgres_fe.h" + +#include "libpq-fe.h" + +extern PGresult *executeQuery(PGconn *conn, const char *query, bool echo); + +extern void executeCommand(PGconn *conn, const char *query, bool echo); + +extern bool executeMaintenanceCommand(PGconn *conn, const char *query, + bool echo); + +#endif /* QUERY_UTILS_H */ diff --git a/src/include/fe_utils/recovery_gen.h b/src/include/fe_utils/recovery_gen.h new file mode 100644 index 0000000..83e181a --- /dev/null +++ b/src/include/fe_utils/recovery_gen.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * Generator for recovery configuration + * + * Portions Copyright (c) 2011-2022, PostgreSQL Global Development Group + * + * src/include/fe_utils/recovery_gen.h + * + *------------------------------------------------------------------------- + */ +#ifndef RECOVERY_GEN_H +#define RECOVERY_GEN_H + +#include "libpq-fe.h" +#include "pqexpbuffer.h" + +/* + * recovery configuration is part of postgresql.conf in version 12 and up, and + * in recovery.conf before that. + */ +#define MINIMUM_VERSION_FOR_RECOVERY_GUC 120000 + +extern PQExpBuffer GenerateRecoveryConfig(PGconn *pgconn, + char *pg_replication_slot); +extern void WriteRecoveryConfig(PGconn *pgconn, char *target_dir, + PQExpBuffer contents); + +#endif /* RECOVERY_GEN_H */ diff --git a/src/include/fe_utils/simple_list.h b/src/include/fe_utils/simple_list.h new file mode 100644 index 0000000..9261a7b --- /dev/null +++ b/src/include/fe_utils/simple_list.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------- + * + * Simple list facilities for frontend code + * + * Data structures for simple lists of OIDs, strings, and pointers. The + * support for these is very primitive compared to the backend's List + * facilities, but it's all we need in, eg, pg_dump. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/simple_list.h + * + *------------------------------------------------------------------------- + */ +#ifndef SIMPLE_LIST_H +#define SIMPLE_LIST_H + +typedef struct SimpleOidListCell +{ + struct SimpleOidListCell *next; + Oid val; +} SimpleOidListCell; + +typedef struct SimpleOidList +{ + SimpleOidListCell *head; + SimpleOidListCell *tail; +} SimpleOidList; + +typedef struct SimpleStringListCell +{ + struct SimpleStringListCell *next; + bool touched; /* true, when this string was searched and + * touched */ + char val[FLEXIBLE_ARRAY_MEMBER]; /* null-terminated string here */ +} SimpleStringListCell; + +typedef struct SimpleStringList +{ + SimpleStringListCell *head; + SimpleStringListCell *tail; +} SimpleStringList; + +typedef struct SimplePtrListCell +{ + struct SimplePtrListCell *next; + void *ptr; +} SimplePtrListCell; + +typedef struct SimplePtrList +{ + SimplePtrListCell *head; + SimplePtrListCell *tail; +} SimplePtrList; + +extern void simple_oid_list_append(SimpleOidList *list, Oid val); +extern bool simple_oid_list_member(SimpleOidList *list, Oid val); +extern void simple_oid_list_destroy(SimpleOidList *list); + +extern void simple_string_list_append(SimpleStringList *list, const char *val); +extern bool simple_string_list_member(SimpleStringList *list, const char *val); +extern void simple_string_list_destroy(SimpleStringList *list); + +extern const char *simple_string_list_not_touched(SimpleStringList *list); + +extern void simple_ptr_list_append(SimplePtrList *list, void *val); + +#endif /* SIMPLE_LIST_H */ diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h new file mode 100644 index 0000000..fa4deb2 --- /dev/null +++ b/src/include/fe_utils/string_utils.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * String-processing utility routines for frontend code + * + * Utility functions that interpret backend output or quote strings for + * assorted contexts. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fe_utils/string_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +#include "libpq-fe.h" +#include "pqexpbuffer.h" + +/* Global variables controlling behavior of fmtId() and fmtQualifiedId() */ +extern PGDLLIMPORT int quote_all_identifiers; +extern PQExpBuffer (*getLocalPQExpBuffer) (void); + +/* Functions */ +extern const char *fmtId(const char *identifier); +extern const char *fmtQualifiedId(const char *schema, const char *id); + +extern char *formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen); + +extern void appendStringLiteral(PQExpBuffer buf, const char *str, + int encoding, bool std_strings); +extern void appendStringLiteralConn(PQExpBuffer buf, const char *str, + PGconn *conn); +extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str, + const char *dqprefix); +extern void appendByteaLiteral(PQExpBuffer buf, + const unsigned char *str, size_t length, + bool std_strings); + +extern void appendShellString(PQExpBuffer buf, const char *str); +extern bool appendShellStringNoError(PQExpBuffer buf, const char *str); +extern void appendConnStrVal(PQExpBuffer buf, const char *str); +extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname); + +extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems); +extern void appendPGArray(PQExpBuffer buffer, const char *value); + +extern bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions, + const char *prefix, int encoding, bool std_strings); + +extern bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, + const char *pattern, + bool have_where, bool force_escape, + const char *schemavar, const char *namevar, + const char *altnamevar, const char *visibilityrule, + PQExpBuffer dbnamebuf, int *dotcnt); + +extern void patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, + PQExpBuffer schemabuf, PQExpBuffer namebuf, + const char *pattern, bool force_escape, + bool want_literal_dbname, int *dotcnt); + +#endif /* STRING_UTILS_H */ diff --git a/src/include/fmgr.h b/src/include/fmgr.h new file mode 100644 index 0000000..5314b73 --- /dev/null +++ b/src/include/fmgr.h @@ -0,0 +1,781 @@ +/*------------------------------------------------------------------------- + * + * fmgr.h + * Definitions for the Postgres function manager and function-call + * interface. + * + * This file must be included by all Postgres modules that either define + * or call fmgr-callable functions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/fmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef FMGR_H +#define FMGR_H + +/* We don't want to include primnodes.h here, so make some stub references */ +typedef struct Node *fmNodePtr; +typedef struct Aggref *fmAggrefPtr; + +/* Likewise, avoid including execnodes.h here */ +typedef void (*fmExprContextCallbackFunction) (Datum arg); + +/* Likewise, avoid including stringinfo.h here */ +typedef struct StringInfoData *fmStringInfo; + + +/* + * All functions that can be called directly by fmgr must have this signature. + * (Other functions can be called by using a handler that does have this + * signature.) + */ + +typedef struct FunctionCallInfoBaseData *FunctionCallInfo; + +typedef Datum (*PGFunction) (FunctionCallInfo fcinfo); + +/* + * This struct holds the system-catalog information that must be looked up + * before a function can be called through fmgr. If the same function is + * to be called multiple times, the lookup need be done only once and the + * info struct saved for re-use. + * + * Note that fn_expr really is parse-time-determined information about the + * arguments, rather than about the function itself. But it's convenient to + * store it here rather than in FunctionCallInfoBaseData, where it might more + * logically belong. + * + * fn_extra is available for use by the called function; all other fields + * should be treated as read-only after the struct is created. + */ +typedef struct FmgrInfo +{ + PGFunction fn_addr; /* pointer to function or handler to be called */ + Oid fn_oid; /* OID of function (NOT of handler, if any) */ + short fn_nargs; /* number of input args (0..FUNC_MAX_ARGS) */ + bool fn_strict; /* function is "strict" (NULL in => NULL out) */ + bool fn_retset; /* function returns a set */ + unsigned char fn_stats; /* collect stats if track_functions > this */ + void *fn_extra; /* extra space for use by handler */ + MemoryContext fn_mcxt; /* memory context to store fn_extra in */ + fmNodePtr fn_expr; /* expression parse tree for call, or NULL */ +} FmgrInfo; + +/* + * This struct is the data actually passed to an fmgr-called function. + * + * The called function is expected to set isnull, and possibly resultinfo or + * fields in whatever resultinfo points to. It should not change any other + * fields. (In particular, scribbling on the argument arrays is a bad idea, + * since some callers assume they can re-call with the same arguments.) + * + * Note that enough space for arguments needs to be provided, either by using + * SizeForFunctionCallInfo() in dynamic allocations, or by using + * LOCAL_FCINFO() for on-stack allocations. + * + * This struct is named *BaseData, rather than *Data, to break pre v12 code + * that allocated FunctionCallInfoData itself, as it'd often silently break + * old code due to no space for arguments being provided. + */ +typedef struct FunctionCallInfoBaseData +{ + FmgrInfo *flinfo; /* ptr to lookup info used for this call */ + fmNodePtr context; /* pass info about context of call */ + fmNodePtr resultinfo; /* pass or return extra info about result */ + Oid fncollation; /* collation for function to use */ +#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4 + bool isnull; /* function must set true if result is NULL */ + short nargs; /* # arguments actually passed */ +#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6 + NullableDatum args[FLEXIBLE_ARRAY_MEMBER]; +} FunctionCallInfoBaseData; + +/* + * Space needed for a FunctionCallInfoBaseData struct with sufficient space + * for `nargs` arguments. + */ +#define SizeForFunctionCallInfo(nargs) \ + (offsetof(FunctionCallInfoBaseData, args) + \ + sizeof(NullableDatum) * (nargs)) + +/* + * This macro ensures that `name` points to a stack-allocated + * FunctionCallInfoBaseData struct with sufficient space for `nargs` arguments. + */ +#define LOCAL_FCINFO(name, nargs) \ + /* use union with FunctionCallInfoBaseData to guarantee alignment */ \ + union \ + { \ + FunctionCallInfoBaseData fcinfo; \ + /* ensure enough space for nargs args is available */ \ + char fcinfo_data[SizeForFunctionCallInfo(nargs)]; \ + } name##data; \ + FunctionCallInfo name = &name##data.fcinfo + +/* + * This routine fills a FmgrInfo struct, given the OID + * of the function to be called. + */ +extern void fmgr_info(Oid functionId, FmgrInfo *finfo); + +/* + * Same, when the FmgrInfo struct is in a memory context longer-lived than + * CurrentMemoryContext. The specified context will be set as fn_mcxt + * and used to hold all subsidiary data of finfo. + */ +extern void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, + MemoryContext mcxt); + +/* Convenience macro for setting the fn_expr field */ +#define fmgr_info_set_expr(expr, finfo) \ + ((finfo)->fn_expr = (expr)) + +/* + * Copy an FmgrInfo struct + */ +extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, + MemoryContext destcxt); + +extern void fmgr_symbol(Oid functionId, char **mod, char **fn); + +/* + * This macro initializes all the fields of a FunctionCallInfoBaseData except + * for the args[] array. + */ +#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \ + do { \ + (Fcinfo).flinfo = (Flinfo); \ + (Fcinfo).context = (Context); \ + (Fcinfo).resultinfo = (Resultinfo); \ + (Fcinfo).fncollation = (Collation); \ + (Fcinfo).isnull = false; \ + (Fcinfo).nargs = (Nargs); \ + } while (0) + +/* + * This macro invokes a function given a filled-in FunctionCallInfoBaseData + * struct. The macro result is the returned Datum --- but note that + * caller must still check fcinfo->isnull! Also, if function is strict, + * it is caller's responsibility to verify that no null arguments are present + * before calling. + * + * Some code performs multiple calls without redoing InitFunctionCallInfoData, + * possibly altering the argument values. This is okay, but be sure to reset + * the fcinfo->isnull flag before each call, since callees are permitted to + * assume that starts out false. + */ +#define FunctionCallInvoke(fcinfo) ((* (fcinfo)->flinfo->fn_addr) (fcinfo)) + + +/*------------------------------------------------------------------------- + * Support macros to ease writing fmgr-compatible functions + * + * A C-coded fmgr-compatible function should be declared as + * + * Datum + * function_name(PG_FUNCTION_ARGS) + * { + * ... + * } + * + * It should access its arguments using appropriate PG_GETARG_xxx macros + * and should return its result using PG_RETURN_xxx. + * + *------------------------------------------------------------------------- + */ + +/* Standard parameter list for fmgr-compatible functions */ +#define PG_FUNCTION_ARGS FunctionCallInfo fcinfo + +/* + * Get collation function should use. + */ +#define PG_GET_COLLATION() (fcinfo->fncollation) + +/* + * Get number of arguments passed to function. + */ +#define PG_NARGS() (fcinfo->nargs) + +/* + * If function is not marked "proisstrict" in pg_proc, it must check for + * null arguments using this macro. Do not try to GETARG a null argument! + */ +#define PG_ARGISNULL(n) (fcinfo->args[n].isnull) + +/* + * Support for fetching detoasted copies of toastable datatypes (all of + * which are varlena types). pg_detoast_datum() gives you either the input + * datum (if not toasted) or a detoasted copy allocated with palloc(). + * pg_detoast_datum_copy() always gives you a palloc'd copy --- use it + * if you need a modifiable copy of the input. Caller is expected to have + * checked for null inputs first, if necessary. + * + * pg_detoast_datum_packed() will return packed (1-byte header) datums + * unmodified. It will still expand an externally toasted or compressed datum. + * The resulting datum can be accessed using VARSIZE_ANY() and VARDATA_ANY() + * (beware of multiple evaluations in those macros!) + * + * In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(), + * VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call + * PG_DETOAST_DATUM(), VARDATA() and VARSIZE(). Directly fetching an int16, + * int32 or wider field in the struct representing the datum layout requires + * aligned data. memcpy() is alignment-oblivious, as are most operations on + * datatypes, such as text, whose layout struct contains only char fields. + * + * Note: it'd be nice if these could be macros, but I see no way to do that + * without evaluating the arguments multiple times, which is NOT acceptable. + */ +extern struct varlena *pg_detoast_datum(struct varlena *datum); +extern struct varlena *pg_detoast_datum_copy(struct varlena *datum); +extern struct varlena *pg_detoast_datum_slice(struct varlena *datum, + int32 first, int32 count); +extern struct varlena *pg_detoast_datum_packed(struct varlena *datum); + +#define PG_DETOAST_DATUM(datum) \ + pg_detoast_datum((struct varlena *) DatumGetPointer(datum)) +#define PG_DETOAST_DATUM_COPY(datum) \ + pg_detoast_datum_copy((struct varlena *) DatumGetPointer(datum)) +#define PG_DETOAST_DATUM_SLICE(datum,f,c) \ + pg_detoast_datum_slice((struct varlena *) DatumGetPointer(datum), \ + (int32) (f), (int32) (c)) +/* WARNING -- unaligned pointer */ +#define PG_DETOAST_DATUM_PACKED(datum) \ + pg_detoast_datum_packed((struct varlena *) DatumGetPointer(datum)) + +/* + * Support for cleaning up detoasted copies of inputs. This must only + * be used for pass-by-ref datatypes, and normally would only be used + * for toastable types. If the given pointer is different from the + * original argument, assume it's a palloc'd detoasted copy, and pfree it. + * NOTE: most functions on toastable types do not have to worry about this, + * but we currently require that support functions for indexes not leak + * memory. + */ +#define PG_FREE_IF_COPY(ptr,n) \ + do { \ + if ((Pointer) (ptr) != PG_GETARG_POINTER(n)) \ + pfree(ptr); \ + } while (0) + +/* Macros for fetching arguments of standard types */ + +#define PG_GETARG_DATUM(n) (fcinfo->args[n].value) +#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n)) +#define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n)) +#define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n)) +#define PG_GETARG_UINT16(n) DatumGetUInt16(PG_GETARG_DATUM(n)) +#define PG_GETARG_CHAR(n) DatumGetChar(PG_GETARG_DATUM(n)) +#define PG_GETARG_BOOL(n) DatumGetBool(PG_GETARG_DATUM(n)) +#define PG_GETARG_OID(n) DatumGetObjectId(PG_GETARG_DATUM(n)) +#define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n)) +#define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n)) +#define PG_GETARG_NAME(n) DatumGetName(PG_GETARG_DATUM(n)) +#define PG_GETARG_TRANSACTIONID(n) DatumGetTransactionId(PG_GETARG_DATUM(n)) +/* these macros hide the pass-by-reference-ness of the datatype: */ +#define PG_GETARG_FLOAT4(n) DatumGetFloat4(PG_GETARG_DATUM(n)) +#define PG_GETARG_FLOAT8(n) DatumGetFloat8(PG_GETARG_DATUM(n)) +#define PG_GETARG_INT64(n) DatumGetInt64(PG_GETARG_DATUM(n)) +/* use this if you want the raw, possibly-toasted input datum: */ +#define PG_GETARG_RAW_VARLENA_P(n) ((struct varlena *) PG_GETARG_POINTER(n)) +/* use this if you want the input datum de-toasted: */ +#define PG_GETARG_VARLENA_P(n) PG_DETOAST_DATUM(PG_GETARG_DATUM(n)) +/* and this if you can handle 1-byte-header datums: */ +#define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n)) +/* DatumGetFoo macros for varlena types will typically look like this: */ +#define DatumGetByteaPP(X) ((bytea *) PG_DETOAST_DATUM_PACKED(X)) +#define DatumGetTextPP(X) ((text *) PG_DETOAST_DATUM_PACKED(X)) +#define DatumGetBpCharPP(X) ((BpChar *) PG_DETOAST_DATUM_PACKED(X)) +#define DatumGetVarCharPP(X) ((VarChar *) PG_DETOAST_DATUM_PACKED(X)) +#define DatumGetHeapTupleHeader(X) ((HeapTupleHeader) PG_DETOAST_DATUM(X)) +/* And we also offer variants that return an OK-to-write copy */ +#define DatumGetByteaPCopy(X) ((bytea *) PG_DETOAST_DATUM_COPY(X)) +#define DatumGetTextPCopy(X) ((text *) PG_DETOAST_DATUM_COPY(X)) +#define DatumGetBpCharPCopy(X) ((BpChar *) PG_DETOAST_DATUM_COPY(X)) +#define DatumGetVarCharPCopy(X) ((VarChar *) PG_DETOAST_DATUM_COPY(X)) +#define DatumGetHeapTupleHeaderCopy(X) ((HeapTupleHeader) PG_DETOAST_DATUM_COPY(X)) +/* Variants which return n bytes starting at pos. m */ +#define DatumGetByteaPSlice(X,m,n) ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n)) +#define DatumGetTextPSlice(X,m,n) ((text *) PG_DETOAST_DATUM_SLICE(X,m,n)) +#define DatumGetBpCharPSlice(X,m,n) ((BpChar *) PG_DETOAST_DATUM_SLICE(X,m,n)) +#define DatumGetVarCharPSlice(X,m,n) ((VarChar *) PG_DETOAST_DATUM_SLICE(X,m,n)) +/* GETARG macros for varlena types will typically look like this: */ +#define PG_GETARG_BYTEA_PP(n) DatumGetByteaPP(PG_GETARG_DATUM(n)) +#define PG_GETARG_TEXT_PP(n) DatumGetTextPP(PG_GETARG_DATUM(n)) +#define PG_GETARG_BPCHAR_PP(n) DatumGetBpCharPP(PG_GETARG_DATUM(n)) +#define PG_GETARG_VARCHAR_PP(n) DatumGetVarCharPP(PG_GETARG_DATUM(n)) +#define PG_GETARG_HEAPTUPLEHEADER(n) DatumGetHeapTupleHeader(PG_GETARG_DATUM(n)) +/* And we also offer variants that return an OK-to-write copy */ +#define PG_GETARG_BYTEA_P_COPY(n) DatumGetByteaPCopy(PG_GETARG_DATUM(n)) +#define PG_GETARG_TEXT_P_COPY(n) DatumGetTextPCopy(PG_GETARG_DATUM(n)) +#define PG_GETARG_BPCHAR_P_COPY(n) DatumGetBpCharPCopy(PG_GETARG_DATUM(n)) +#define PG_GETARG_VARCHAR_P_COPY(n) DatumGetVarCharPCopy(PG_GETARG_DATUM(n)) +#define PG_GETARG_HEAPTUPLEHEADER_COPY(n) DatumGetHeapTupleHeaderCopy(PG_GETARG_DATUM(n)) +/* And a b-byte slice from position a -also OK to write */ +#define PG_GETARG_BYTEA_P_SLICE(n,a,b) DatumGetByteaPSlice(PG_GETARG_DATUM(n),a,b) +#define PG_GETARG_TEXT_P_SLICE(n,a,b) DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b) +#define PG_GETARG_BPCHAR_P_SLICE(n,a,b) DatumGetBpCharPSlice(PG_GETARG_DATUM(n),a,b) +#define PG_GETARG_VARCHAR_P_SLICE(n,a,b) DatumGetVarCharPSlice(PG_GETARG_DATUM(n),a,b) +/* + * Obsolescent variants that guarantee INT alignment for the return value. + * Few operations on these particular types need alignment, mainly operations + * that cast the VARDATA pointer to a type like int16[]. Most code should use + * the ...PP(X) counterpart. Nonetheless, these appear frequently in code + * predating the PostgreSQL 8.3 introduction of the ...PP(X) variants. + */ +#define DatumGetByteaP(X) ((bytea *) PG_DETOAST_DATUM(X)) +#define DatumGetTextP(X) ((text *) PG_DETOAST_DATUM(X)) +#define DatumGetBpCharP(X) ((BpChar *) PG_DETOAST_DATUM(X)) +#define DatumGetVarCharP(X) ((VarChar *) PG_DETOAST_DATUM(X)) +#define PG_GETARG_BYTEA_P(n) DatumGetByteaP(PG_GETARG_DATUM(n)) +#define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n)) +#define PG_GETARG_BPCHAR_P(n) DatumGetBpCharP(PG_GETARG_DATUM(n)) +#define PG_GETARG_VARCHAR_P(n) DatumGetVarCharP(PG_GETARG_DATUM(n)) + +/* To access options from opclass support functions use this: */ +#define PG_HAS_OPCLASS_OPTIONS() has_fn_opclass_options(fcinfo->flinfo) +#define PG_GET_OPCLASS_OPTIONS() get_fn_opclass_options(fcinfo->flinfo) + +/* To return a NULL do this: */ +#define PG_RETURN_NULL() \ + do { fcinfo->isnull = true; return (Datum) 0; } while (0) + +/* A few internal functions return void (which is not the same as NULL!) */ +#define PG_RETURN_VOID() return (Datum) 0 + +/* Macros for returning results of standard types */ + +#define PG_RETURN_DATUM(x) return (x) +#define PG_RETURN_INT32(x) return Int32GetDatum(x) +#define PG_RETURN_UINT32(x) return UInt32GetDatum(x) +#define PG_RETURN_INT16(x) return Int16GetDatum(x) +#define PG_RETURN_UINT16(x) return UInt16GetDatum(x) +#define PG_RETURN_CHAR(x) return CharGetDatum(x) +#define PG_RETURN_BOOL(x) return BoolGetDatum(x) +#define PG_RETURN_OID(x) return ObjectIdGetDatum(x) +#define PG_RETURN_POINTER(x) return PointerGetDatum(x) +#define PG_RETURN_CSTRING(x) return CStringGetDatum(x) +#define PG_RETURN_NAME(x) return NameGetDatum(x) +#define PG_RETURN_TRANSACTIONID(x) return TransactionIdGetDatum(x) +/* these macros hide the pass-by-reference-ness of the datatype: */ +#define PG_RETURN_FLOAT4(x) return Float4GetDatum(x) +#define PG_RETURN_FLOAT8(x) return Float8GetDatum(x) +#define PG_RETURN_INT64(x) return Int64GetDatum(x) +#define PG_RETURN_UINT64(x) return UInt64GetDatum(x) +/* RETURN macros for other pass-by-ref types will typically look like this: */ +#define PG_RETURN_BYTEA_P(x) PG_RETURN_POINTER(x) +#define PG_RETURN_TEXT_P(x) PG_RETURN_POINTER(x) +#define PG_RETURN_BPCHAR_P(x) PG_RETURN_POINTER(x) +#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x) +#define PG_RETURN_HEAPTUPLEHEADER(x) return HeapTupleHeaderGetDatum(x) + + +/*------------------------------------------------------------------------- + * Support for detecting call convention of dynamically-loaded functions + * + * Dynamically loaded functions currently can only use the version-1 ("new + * style") calling convention. Version-0 ("old style") is not supported + * anymore. Version 1 is the call convention defined in this header file, and + * must be accompanied by the macro call + * + * PG_FUNCTION_INFO_V1(function_name); + * + * Note that internal functions do not need this decoration since they are + * assumed to be version-1. + * + *------------------------------------------------------------------------- + */ + +typedef struct +{ + int api_version; /* specifies call convention version number */ + /* More fields may be added later, for version numbers > 1. */ +} Pg_finfo_record; + +/* Expected signature of an info function */ +typedef const Pg_finfo_record *(*PGFInfoFunction) (void); + +/* + * Macro to build an info function associated with the given function name. + * + * As a convenience, also provide an "extern" declaration for the given + * function name, so that writers of C functions need not write that too. + * + * On Windows, the function and info function must be exported. Our normal + * build processes take care of that via .DEF files or --export-all-symbols. + * Module authors using a different build process might need to manually + * declare the function PGDLLEXPORT. We do that automatically here for the + * info function, since authors shouldn't need to be explicitly aware of it. + */ +#define PG_FUNCTION_INFO_V1(funcname) \ +extern Datum funcname(PG_FUNCTION_ARGS); \ +extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \ +const Pg_finfo_record * \ +CppConcat(pg_finfo_,funcname) (void) \ +{ \ + static const Pg_finfo_record my_finfo = { 1 }; \ + return &my_finfo; \ +} \ +extern int no_such_variable + + +/*------------------------------------------------------------------------- + * Support for verifying backend compatibility of loaded modules + * + * We require dynamically-loaded modules to include the macro call + * PG_MODULE_MAGIC; + * so that we can check for obvious incompatibility, such as being compiled + * for a different major PostgreSQL version. + * + * To compile with versions of PostgreSQL that do not support this, + * you may put an #ifdef/#endif test around it. Note that in a multiple- + * source-file module, the macro call should only appear once. + * + * The specific items included in the magic block are intended to be ones that + * are custom-configurable and especially likely to break dynamically loaded + * modules if they were compiled with other values. Also, the length field + * can be used to detect definition changes. + * + * Note: we compare magic blocks with memcmp(), so there had better not be + * any alignment pad bytes in them. + * + * Note: when changing the contents of magic blocks, be sure to adjust the + * incompatible_module_error() function in dfmgr.c. + *------------------------------------------------------------------------- + */ + +/* Definition of the magic block structure */ +typedef struct +{ + int len; /* sizeof(this struct) */ + int version; /* PostgreSQL major version */ + int funcmaxargs; /* FUNC_MAX_ARGS */ + int indexmaxkeys; /* INDEX_MAX_KEYS */ + int namedatalen; /* NAMEDATALEN */ + int float8byval; /* FLOAT8PASSBYVAL */ + char abi_extra[32]; /* see pg_config_manual.h */ +} Pg_magic_struct; + +/* The actual data block contents */ +#define PG_MODULE_MAGIC_DATA \ +{ \ + sizeof(Pg_magic_struct), \ + PG_VERSION_NUM / 100, \ + FUNC_MAX_ARGS, \ + INDEX_MAX_KEYS, \ + NAMEDATALEN, \ + FLOAT8PASSBYVAL, \ + FMGR_ABI_EXTRA, \ +} + +StaticAssertDecl(sizeof(FMGR_ABI_EXTRA) <= sizeof(((Pg_magic_struct *) 0)->abi_extra), + "FMGR_ABI_EXTRA too long"); + +/* + * Declare the module magic function. It needs to be a function as the dlsym + * in the backend is only guaranteed to work on functions, not data + */ +typedef const Pg_magic_struct *(*PGModuleMagicFunction) (void); + +#define PG_MAGIC_FUNCTION_NAME Pg_magic_func +#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func" + +#define PG_MODULE_MAGIC \ +extern PGDLLEXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ +const Pg_magic_struct * \ +PG_MAGIC_FUNCTION_NAME(void) \ +{ \ + static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ + return &Pg_magic_data; \ +} \ +extern int no_such_variable + + +/*------------------------------------------------------------------------- + * Support routines and macros for callers of fmgr-compatible functions + *------------------------------------------------------------------------- + */ + +/* These are for invocation of a specifically named function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. Also, the function cannot be one that needs to + * look at FmgrInfo, since there won't be any. + */ +extern Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, + Datum arg1); +extern Datum DirectFunctionCall2Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2); +extern Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3); +extern Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4); +extern Datum DirectFunctionCall5Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5); +extern Datum DirectFunctionCall6Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6); +extern Datum DirectFunctionCall7Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7); +extern Datum DirectFunctionCall8Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8); +extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9); + +/* + * These functions work like the DirectFunctionCall functions except that + * they use the flinfo parameter to initialise the fcinfo for the call. + * It's recommended that the callee only use the fn_extra and fn_mcxt + * fields, as other fields will typically describe the calling function + * not the callee. Conversely, the calling function should not have + * used fn_extra, unless its use is known to be compatible with the callee's. + */ +extern Datum CallerFInfoFunctionCall1(PGFunction func, FmgrInfo *flinfo, + Oid collation, Datum arg1); +extern Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, + Oid collation, Datum arg1, Datum arg2); + +/* These are for invocation of a previously-looked-up function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. + */ +extern Datum FunctionCall0Coll(FmgrInfo *flinfo, Oid collation); +extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1); +extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2); +extern Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3); +extern Datum FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4); +extern Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5); +extern Datum FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6); +extern Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7); +extern Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8); +extern Datum FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9); + +/* These are for invocation of a function identified by OID with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. These are essentially fmgr_info() followed by + * FunctionCallN(). If the same function is to be invoked repeatedly, do the + * fmgr_info() once and then use FunctionCallN(). + */ +extern Datum OidFunctionCall0Coll(Oid functionId, Oid collation); +extern Datum OidFunctionCall1Coll(Oid functionId, Oid collation, + Datum arg1); +extern Datum OidFunctionCall2Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2); +extern Datum OidFunctionCall3Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3); +extern Datum OidFunctionCall4Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4); +extern Datum OidFunctionCall5Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5); +extern Datum OidFunctionCall6Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6); +extern Datum OidFunctionCall7Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7); +extern Datum OidFunctionCall8Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8); +extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation, + Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9); + +/* These macros allow the collation argument to be omitted (with a default of + * InvalidOid, ie, no collation). They exist mostly for backwards + * compatibility of source code. + */ +#define DirectFunctionCall1(func, arg1) \ + DirectFunctionCall1Coll(func, InvalidOid, arg1) +#define DirectFunctionCall2(func, arg1, arg2) \ + DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2) +#define DirectFunctionCall3(func, arg1, arg2, arg3) \ + DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3) +#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \ + DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4) +#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \ + DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5) +#define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ + DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) +#define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ + DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) +#define FunctionCall1(flinfo, arg1) \ + FunctionCall1Coll(flinfo, InvalidOid, arg1) +#define FunctionCall2(flinfo, arg1, arg2) \ + FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2) +#define FunctionCall3(flinfo, arg1, arg2, arg3) \ + FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3) +#define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) \ + FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4) +#define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \ + FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5) +#define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \ + FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) +#define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ + FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) +#define OidFunctionCall0(functionId) \ + OidFunctionCall0Coll(functionId, InvalidOid) +#define OidFunctionCall1(functionId, arg1) \ + OidFunctionCall1Coll(functionId, InvalidOid, arg1) +#define OidFunctionCall2(functionId, arg1, arg2) \ + OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2) +#define OidFunctionCall3(functionId, arg1, arg2, arg3) \ + OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3) +#define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \ + OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4) +#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \ + OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5) +#define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \ + OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6) +#define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7) +#define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) +#define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \ + OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) + + +/* Special cases for convenient invocation of datatype I/O functions. */ +extern Datum InputFunctionCall(FmgrInfo *flinfo, char *str, + Oid typioparam, int32 typmod); +extern Datum OidInputFunctionCall(Oid functionId, char *str, + Oid typioparam, int32 typmod); +extern char *OutputFunctionCall(FmgrInfo *flinfo, Datum val); +extern char *OidOutputFunctionCall(Oid functionId, Datum val); +extern Datum ReceiveFunctionCall(FmgrInfo *flinfo, fmStringInfo buf, + Oid typioparam, int32 typmod); +extern Datum OidReceiveFunctionCall(Oid functionId, fmStringInfo buf, + Oid typioparam, int32 typmod); +extern bytea *SendFunctionCall(FmgrInfo *flinfo, Datum val); +extern bytea *OidSendFunctionCall(Oid functionId, Datum val); + + +/* + * Routines in fmgr.c + */ +extern const Pg_finfo_record *fetch_finfo_record(void *filehandle, const char *funcname); +extern Oid fmgr_internal_function(const char *proname); +extern Oid get_fn_expr_rettype(FmgrInfo *flinfo); +extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum); +extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum); +extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum); +extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum); +extern bool get_fn_expr_variadic(FmgrInfo *flinfo); +extern bytea *get_fn_opclass_options(FmgrInfo *flinfo); +extern bool has_fn_opclass_options(FmgrInfo *flinfo); +extern void set_fn_opclass_options(FmgrInfo *flinfo, bytea *options); +extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid); + +/* + * Routines in dfmgr.c + */ +extern PGDLLIMPORT char *Dynamic_library_path; + +extern void *load_external_function(const char *filename, const char *funcname, + bool signalNotFound, void **filehandle); +extern void *lookup_external_function(void *filehandle, const char *funcname); +extern void load_file(const char *filename, bool restricted); +extern void **find_rendezvous_variable(const char *varName); +extern Size EstimateLibraryStateSpace(void); +extern void SerializeLibraryState(Size maxsize, char *start_address); +extern void RestoreLibraryState(char *start_address); + +/* + * Support for aggregate functions + * + * These are actually in executor/nodeAgg.c, but we declare them here since + * the whole point is for callers to not be overly friendly with nodeAgg. + */ + +/* AggCheckCallContext can return one of the following codes, or 0: */ +#define AGG_CONTEXT_AGGREGATE 1 /* regular aggregate */ +#define AGG_CONTEXT_WINDOW 2 /* window function */ + +extern int AggCheckCallContext(FunctionCallInfo fcinfo, + MemoryContext *aggcontext); +extern fmAggrefPtr AggGetAggref(FunctionCallInfo fcinfo); +extern MemoryContext AggGetTempMemoryContext(FunctionCallInfo fcinfo); +extern bool AggStateIsShared(FunctionCallInfo fcinfo); +extern void AggRegisterCallback(FunctionCallInfo fcinfo, + fmExprContextCallbackFunction func, + Datum arg); + +/* + * We allow plugin modules to hook function entry/exit. This is intended + * as support for loadable security policy modules, which may want to + * perform additional privilege checks on function entry or exit, or to do + * other internal bookkeeping. To make this possible, such modules must be + * able not only to support normal function entry and exit, but also to trap + * the case where we bail out due to an error; and they must also be able to + * prevent inlining. + */ +typedef enum FmgrHookEventType +{ + FHET_START, + FHET_END, + FHET_ABORT +} FmgrHookEventType; + +typedef bool (*needs_fmgr_hook_type) (Oid fn_oid); + +typedef void (*fmgr_hook_type) (FmgrHookEventType event, + FmgrInfo *flinfo, Datum *arg); + +extern PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook; +extern PGDLLIMPORT fmgr_hook_type fmgr_hook; + +#define FmgrHookIsNeeded(fn_oid) \ + (!needs_fmgr_hook ? false : (*needs_fmgr_hook)(fn_oid)) + +#endif /* FMGR_H */ diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h new file mode 100644 index 0000000..57c02bf --- /dev/null +++ b/src/include/foreign/fdwapi.h @@ -0,0 +1,294 @@ +/*------------------------------------------------------------------------- + * + * fdwapi.h + * API for foreign-data wrappers + * + * Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/foreign/fdwapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef FDWAPI_H +#define FDWAPI_H + +#include "access/parallel.h" +#include "nodes/execnodes.h" +#include "nodes/pathnodes.h" + +/* To avoid including explain.h here, reference ExplainState thus: */ +struct ExplainState; + + +/* + * Callback function signatures --- see fdwhandler.sgml for more info. + */ + +typedef void (*GetForeignRelSize_function) (PlannerInfo *root, + RelOptInfo *baserel, + Oid foreigntableid); + +typedef void (*GetForeignPaths_function) (PlannerInfo *root, + RelOptInfo *baserel, + Oid foreigntableid); + +typedef ForeignScan *(*GetForeignPlan_function) (PlannerInfo *root, + RelOptInfo *baserel, + Oid foreigntableid, + ForeignPath *best_path, + List *tlist, + List *scan_clauses, + Plan *outer_plan); + +typedef void (*BeginForeignScan_function) (ForeignScanState *node, + int eflags); + +typedef TupleTableSlot *(*IterateForeignScan_function) (ForeignScanState *node); + +typedef bool (*RecheckForeignScan_function) (ForeignScanState *node, + TupleTableSlot *slot); + +typedef void (*ReScanForeignScan_function) (ForeignScanState *node); + +typedef void (*EndForeignScan_function) (ForeignScanState *node); + +typedef void (*GetForeignJoinPaths_function) (PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + JoinType jointype, + JoinPathExtraData *extra); + +typedef void (*GetForeignUpperPaths_function) (PlannerInfo *root, + UpperRelationKind stage, + RelOptInfo *input_rel, + RelOptInfo *output_rel, + void *extra); + +typedef void (*AddForeignUpdateTargets_function) (PlannerInfo *root, + Index rtindex, + RangeTblEntry *target_rte, + Relation target_relation); + +typedef List *(*PlanForeignModify_function) (PlannerInfo *root, + ModifyTable *plan, + Index resultRelation, + int subplan_index); + +typedef void (*BeginForeignModify_function) (ModifyTableState *mtstate, + ResultRelInfo *rinfo, + List *fdw_private, + int subplan_index, + int eflags); + +typedef TupleTableSlot *(*ExecForeignInsert_function) (EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot *slot, + TupleTableSlot *planSlot); + +typedef TupleTableSlot **(*ExecForeignBatchInsert_function) (EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot **slots, + TupleTableSlot **planSlots, + int *numSlots); + +typedef int (*GetForeignModifyBatchSize_function) (ResultRelInfo *rinfo); + +typedef TupleTableSlot *(*ExecForeignUpdate_function) (EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot *slot, + TupleTableSlot *planSlot); + +typedef TupleTableSlot *(*ExecForeignDelete_function) (EState *estate, + ResultRelInfo *rinfo, + TupleTableSlot *slot, + TupleTableSlot *planSlot); + +typedef void (*EndForeignModify_function) (EState *estate, + ResultRelInfo *rinfo); + +typedef void (*BeginForeignInsert_function) (ModifyTableState *mtstate, + ResultRelInfo *rinfo); + +typedef void (*EndForeignInsert_function) (EState *estate, + ResultRelInfo *rinfo); + +typedef int (*IsForeignRelUpdatable_function) (Relation rel); + +typedef bool (*PlanDirectModify_function) (PlannerInfo *root, + ModifyTable *plan, + Index resultRelation, + int subplan_index); + +typedef void (*BeginDirectModify_function) (ForeignScanState *node, + int eflags); + +typedef TupleTableSlot *(*IterateDirectModify_function) (ForeignScanState *node); + +typedef void (*EndDirectModify_function) (ForeignScanState *node); + +typedef RowMarkType (*GetForeignRowMarkType_function) (RangeTblEntry *rte, + LockClauseStrength strength); + +typedef void (*RefetchForeignRow_function) (EState *estate, + ExecRowMark *erm, + Datum rowid, + TupleTableSlot *slot, + bool *updated); + +typedef void (*ExplainForeignScan_function) (ForeignScanState *node, + struct ExplainState *es); + +typedef void (*ExplainForeignModify_function) (ModifyTableState *mtstate, + ResultRelInfo *rinfo, + List *fdw_private, + int subplan_index, + struct ExplainState *es); + +typedef void (*ExplainDirectModify_function) (ForeignScanState *node, + struct ExplainState *es); + +typedef int (*AcquireSampleRowsFunc) (Relation relation, int elevel, + HeapTuple *rows, int targrows, + double *totalrows, + double *totaldeadrows); + +typedef bool (*AnalyzeForeignTable_function) (Relation relation, + AcquireSampleRowsFunc *func, + BlockNumber *totalpages); + +typedef List *(*ImportForeignSchema_function) (ImportForeignSchemaStmt *stmt, + Oid serverOid); + +typedef void (*ExecForeignTruncate_function) (List *rels, + DropBehavior behavior, + bool restart_seqs); + +typedef Size (*EstimateDSMForeignScan_function) (ForeignScanState *node, + ParallelContext *pcxt); +typedef void (*InitializeDSMForeignScan_function) (ForeignScanState *node, + ParallelContext *pcxt, + void *coordinate); +typedef void (*ReInitializeDSMForeignScan_function) (ForeignScanState *node, + ParallelContext *pcxt, + void *coordinate); +typedef void (*InitializeWorkerForeignScan_function) (ForeignScanState *node, + shm_toc *toc, + void *coordinate); +typedef void (*ShutdownForeignScan_function) (ForeignScanState *node); +typedef bool (*IsForeignScanParallelSafe_function) (PlannerInfo *root, + RelOptInfo *rel, + RangeTblEntry *rte); +typedef List *(*ReparameterizeForeignPathByChild_function) (PlannerInfo *root, + List *fdw_private, + RelOptInfo *child_rel); + +typedef bool (*IsForeignPathAsyncCapable_function) (ForeignPath *path); + +typedef void (*ForeignAsyncRequest_function) (AsyncRequest *areq); + +typedef void (*ForeignAsyncConfigureWait_function) (AsyncRequest *areq); + +typedef void (*ForeignAsyncNotify_function) (AsyncRequest *areq); + +/* + * FdwRoutine is the struct returned by a foreign-data wrapper's handler + * function. It provides pointers to the callback functions needed by the + * planner and executor. + * + * More function pointers are likely to be added in the future. Therefore + * it's recommended that the handler initialize the struct with + * makeNode(FdwRoutine) so that all fields are set to NULL. This will + * ensure that no fields are accidentally left undefined. + */ +typedef struct FdwRoutine +{ + NodeTag type; + + /* Functions for scanning foreign tables */ + GetForeignRelSize_function GetForeignRelSize; + GetForeignPaths_function GetForeignPaths; + GetForeignPlan_function GetForeignPlan; + BeginForeignScan_function BeginForeignScan; + IterateForeignScan_function IterateForeignScan; + ReScanForeignScan_function ReScanForeignScan; + EndForeignScan_function EndForeignScan; + + /* + * Remaining functions are optional. Set the pointer to NULL for any that + * are not provided. + */ + + /* Functions for remote-join planning */ + GetForeignJoinPaths_function GetForeignJoinPaths; + + /* Functions for remote upper-relation (post scan/join) planning */ + GetForeignUpperPaths_function GetForeignUpperPaths; + + /* Functions for updating foreign tables */ + AddForeignUpdateTargets_function AddForeignUpdateTargets; + PlanForeignModify_function PlanForeignModify; + BeginForeignModify_function BeginForeignModify; + ExecForeignInsert_function ExecForeignInsert; + ExecForeignBatchInsert_function ExecForeignBatchInsert; + GetForeignModifyBatchSize_function GetForeignModifyBatchSize; + ExecForeignUpdate_function ExecForeignUpdate; + ExecForeignDelete_function ExecForeignDelete; + EndForeignModify_function EndForeignModify; + BeginForeignInsert_function BeginForeignInsert; + EndForeignInsert_function EndForeignInsert; + IsForeignRelUpdatable_function IsForeignRelUpdatable; + PlanDirectModify_function PlanDirectModify; + BeginDirectModify_function BeginDirectModify; + IterateDirectModify_function IterateDirectModify; + EndDirectModify_function EndDirectModify; + + /* Functions for SELECT FOR UPDATE/SHARE row locking */ + GetForeignRowMarkType_function GetForeignRowMarkType; + RefetchForeignRow_function RefetchForeignRow; + RecheckForeignScan_function RecheckForeignScan; + + /* Support functions for EXPLAIN */ + ExplainForeignScan_function ExplainForeignScan; + ExplainForeignModify_function ExplainForeignModify; + ExplainDirectModify_function ExplainDirectModify; + + /* Support functions for ANALYZE */ + AnalyzeForeignTable_function AnalyzeForeignTable; + + /* Support functions for IMPORT FOREIGN SCHEMA */ + ImportForeignSchema_function ImportForeignSchema; + + /* Support functions for TRUNCATE */ + ExecForeignTruncate_function ExecForeignTruncate; + + /* Support functions for parallelism under Gather node */ + IsForeignScanParallelSafe_function IsForeignScanParallelSafe; + EstimateDSMForeignScan_function EstimateDSMForeignScan; + InitializeDSMForeignScan_function InitializeDSMForeignScan; + ReInitializeDSMForeignScan_function ReInitializeDSMForeignScan; + InitializeWorkerForeignScan_function InitializeWorkerForeignScan; + ShutdownForeignScan_function ShutdownForeignScan; + + /* Support functions for path reparameterization. */ + ReparameterizeForeignPathByChild_function ReparameterizeForeignPathByChild; + + /* Support functions for asynchronous execution */ + IsForeignPathAsyncCapable_function IsForeignPathAsyncCapable; + ForeignAsyncRequest_function ForeignAsyncRequest; + ForeignAsyncConfigureWait_function ForeignAsyncConfigureWait; + ForeignAsyncNotify_function ForeignAsyncNotify; +} FdwRoutine; + + +/* Functions in foreign/foreign.c */ +extern FdwRoutine *GetFdwRoutine(Oid fdwhandler); +extern Oid GetForeignServerIdByRelId(Oid relid); +extern FdwRoutine *GetFdwRoutineByServerId(Oid serverid); +extern FdwRoutine *GetFdwRoutineByRelId(Oid relid); +extern FdwRoutine *GetFdwRoutineForRelation(Relation relation, bool makecopy); +extern bool IsImportableForeignTable(const char *tablename, + ImportForeignSchemaStmt *stmt); +extern Path *GetExistingLocalJoinPath(RelOptInfo *joinrel); + +#endif /* FDWAPI_H */ diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h new file mode 100644 index 0000000..7553811 --- /dev/null +++ b/src/include/foreign/foreign.h @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + * + * foreign.h + * support for foreign-data wrappers, servers and user mappings. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/foreign/foreign.h + * + *------------------------------------------------------------------------- + */ +#ifndef FOREIGN_H +#define FOREIGN_H + +#include "nodes/parsenodes.h" + + +/* Helper for obtaining username for user mapping */ +#define MappingUserName(userid) \ + (OidIsValid(userid) ? GetUserNameFromId(userid, false) : "public") + + +typedef struct ForeignDataWrapper +{ + Oid fdwid; /* FDW Oid */ + Oid owner; /* FDW owner user Oid */ + char *fdwname; /* Name of the FDW */ + Oid fdwhandler; /* Oid of handler function, or 0 */ + Oid fdwvalidator; /* Oid of validator function, or 0 */ + List *options; /* fdwoptions as DefElem list */ +} ForeignDataWrapper; + +typedef struct ForeignServer +{ + Oid serverid; /* server Oid */ + Oid fdwid; /* foreign-data wrapper */ + Oid owner; /* server owner user Oid */ + char *servername; /* name of the server */ + char *servertype; /* server type, optional */ + char *serverversion; /* server version, optional */ + List *options; /* srvoptions as DefElem list */ +} ForeignServer; + +typedef struct UserMapping +{ + Oid umid; /* Oid of user mapping */ + Oid userid; /* local user Oid */ + Oid serverid; /* server Oid */ + List *options; /* useoptions as DefElem list */ +} UserMapping; + +typedef struct ForeignTable +{ + Oid relid; /* relation Oid */ + Oid serverid; /* server Oid */ + List *options; /* ftoptions as DefElem list */ +} ForeignTable; + +/* Flags for GetForeignServerExtended */ +#define FSV_MISSING_OK 0x01 + +/* Flags for GetForeignDataWrapperExtended */ +#define FDW_MISSING_OK 0x01 + + +extern ForeignServer *GetForeignServer(Oid serverid); +extern ForeignServer *GetForeignServerExtended(Oid serverid, + bits16 flags); +extern ForeignServer *GetForeignServerByName(const char *name, bool missing_ok); +extern UserMapping *GetUserMapping(Oid userid, Oid serverid); +extern ForeignDataWrapper *GetForeignDataWrapper(Oid fdwid); +extern ForeignDataWrapper *GetForeignDataWrapperExtended(Oid fdwid, + bits16 flags); +extern ForeignDataWrapper *GetForeignDataWrapperByName(const char *name, + bool missing_ok); +extern ForeignTable *GetForeignTable(Oid relid); + +extern List *GetForeignColumnOptions(Oid relid, AttrNumber attnum); + +extern Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok); +extern Oid get_foreign_server_oid(const char *servername, bool missing_ok); + +#endif /* FOREIGN_H */ diff --git a/src/include/funcapi.h b/src/include/funcapi.h new file mode 100644 index 0000000..8c47054 --- /dev/null +++ b/src/include/funcapi.h @@ -0,0 +1,360 @@ +/*------------------------------------------------------------------------- + * + * funcapi.h + * Definitions for functions which return composite type and/or sets + * or work on VARIADIC inputs. + * + * This file must be included by all Postgres modules that either define + * or call FUNCAPI-callable functions or macros. + * + * + * Copyright (c) 2002-2022, PostgreSQL Global Development Group + * + * src/include/funcapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef FUNCAPI_H +#define FUNCAPI_H + +#include "access/tupdesc.h" +#include "executor/executor.h" +#include "executor/tuptable.h" +#include "fmgr.h" + +/*------------------------------------------------------------------------- + * Support to ease writing Functions returning composite types + *------------------------------------------------------------------------- + * + * This struct holds arrays of individual attribute information + * needed to create a tuple from raw C strings. It also requires + * a copy of the TupleDesc. The information carried here + * is derived from the TupleDesc, but it is stored here to + * avoid redundant cpu cycles on each call to an SRF. + */ +typedef struct AttInMetadata +{ + /* full TupleDesc */ + TupleDesc tupdesc; + + /* array of attribute type input function finfo */ + FmgrInfo *attinfuncs; + + /* array of attribute type i/o parameter OIDs */ + Oid *attioparams; + + /* array of attribute typmod */ + int32 *atttypmods; +} AttInMetadata; + +/*------------------------------------------------------------------------- + * Support struct to ease writing Set Returning Functions (SRFs) + *------------------------------------------------------------------------- + * + * This struct holds function context for Set Returning Functions. + * Use fn_extra to hold a pointer to it across calls + */ +typedef struct FuncCallContext +{ + /* + * Number of times we've been called before + * + * call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and + * incremented for you every time SRF_RETURN_NEXT() is called. + */ + uint64 call_cntr; + + /* + * OPTIONAL maximum number of calls + * + * max_calls is here for convenience only and setting it is optional. If + * not set, you must provide alternative means to know when the function + * is done. + */ + uint64 max_calls; + + /* + * OPTIONAL pointer to miscellaneous user-provided context information + * + * user_fctx is for use as a pointer to your own struct to retain + * arbitrary context information between calls of your function. + */ + void *user_fctx; + + /* + * OPTIONAL pointer to struct containing attribute type input metadata + * + * attinmeta is for use when returning tuples (i.e. composite data types) + * and is not used when returning base data types. It is only needed if + * you intend to use BuildTupleFromCStrings() to create the return tuple. + */ + AttInMetadata *attinmeta; + + /* + * memory context used for structures that must live for multiple calls + * + * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used + * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory + * context for any memory that is to be reused across multiple calls of + * the SRF. + */ + MemoryContext multi_call_memory_ctx; + + /* + * OPTIONAL pointer to struct containing tuple description + * + * tuple_desc is for use when returning tuples (i.e. composite data types) + * and is only needed if you are going to build the tuples with + * heap_form_tuple() rather than with BuildTupleFromCStrings(). Note that + * the TupleDesc pointer stored here should usually have been run through + * BlessTupleDesc() first. + */ + TupleDesc tuple_desc; + +} FuncCallContext; + +/*---------- + * Support to ease writing functions returning composite types + * + * External declarations: + * get_call_result_type: + * Given a function's call info record, determine the kind of datatype + * it is supposed to return. If resultTypeId isn't NULL, *resultTypeId + * receives the actual datatype OID (this is mainly useful for scalar + * result types). If resultTupleDesc isn't NULL, *resultTupleDesc + * receives a pointer to a TupleDesc when the result is of a composite + * type, or NULL when it's a scalar result or the rowtype could not be + * determined. NB: the tupledesc should be copied if it is to be + * accessed over a long period. + * get_expr_result_type: + * Given an expression node, return the same info as for + * get_call_result_type. Note: the cases in which rowtypes cannot be + * determined are different from the cases for get_call_result_type. + * get_func_result_type: + * Given only a function's OID, return the same info as for + * get_call_result_type. Note: the cases in which rowtypes cannot be + * determined are different from the cases for get_call_result_type. + * Do *not* use this if you can use one of the others. + * + * See also get_expr_result_tupdesc(), which is a convenient wrapper around + * get_expr_result_type() for use when the caller only cares about + * determinable-rowtype cases. + *---------- + */ + +/* Type categories for get_call_result_type and siblings */ +typedef enum TypeFuncClass +{ + TYPEFUNC_SCALAR, /* scalar result type */ + TYPEFUNC_COMPOSITE, /* determinable rowtype result */ + TYPEFUNC_COMPOSITE_DOMAIN, /* domain over determinable rowtype result */ + TYPEFUNC_RECORD, /* indeterminate rowtype result */ + TYPEFUNC_OTHER /* bogus type, eg pseudotype */ +} TypeFuncClass; + +extern TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, + Oid *resultTypeId, + TupleDesc *resultTupleDesc); +extern TypeFuncClass get_expr_result_type(Node *expr, + Oid *resultTypeId, + TupleDesc *resultTupleDesc); +extern TypeFuncClass get_func_result_type(Oid functionId, + Oid *resultTypeId, + TupleDesc *resultTupleDesc); + +extern TupleDesc get_expr_result_tupdesc(Node *expr, bool noError); + +extern bool resolve_polymorphic_argtypes(int numargs, Oid *argtypes, + char *argmodes, + Node *call_expr); + +extern int get_func_arg_info(HeapTuple procTup, + Oid **p_argtypes, char ***p_argnames, + char **p_argmodes); + +extern int get_func_input_arg_names(Datum proargnames, Datum proargmodes, + char ***arg_names); + +extern int get_func_trftypes(HeapTuple procTup, Oid **p_trftypes); +extern char *get_func_result_name(Oid functionId); + +extern TupleDesc build_function_result_tupdesc_d(char prokind, + Datum proallargtypes, + Datum proargmodes, + Datum proargnames); +extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple); + + +/*---------- + * Support to ease writing functions returning composite types + * + * External declarations: + * TupleDesc BlessTupleDesc(TupleDesc tupdesc) - "Bless" a completed tuple + * descriptor so that it can be used to return properly labeled tuples. + * You need to call this if you are going to use heap_form_tuple directly. + * TupleDescGetAttInMetadata does it for you, however, so no need to call + * it if you call TupleDescGetAttInMetadata. + * AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) - Build an + * AttInMetadata struct based on the given TupleDesc. AttInMetadata can + * be used in conjunction with C strings to produce a properly formed + * tuple. + * HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) - + * build a HeapTuple given user data in C string form. values is an array + * of C strings, one for each attribute of the return tuple. + * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a + * HeapTupleHeader to a Datum. + * + * Macro declarations: + * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum. + * + * Obsolete routines and macros: + * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a + * TupleDesc based on a named relation. + * TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) - Use to get a + * TupleDesc based on a type OID. + * TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) - get a Datum + * given a tuple and a slot. + *---------- + */ + +#define HeapTupleGetDatum(tuple) HeapTupleHeaderGetDatum((tuple)->t_data) +/* obsolete version of above */ +#define TupleGetDatum(_slot, _tuple) HeapTupleGetDatum(_tuple) + +extern TupleDesc RelationNameGetTupleDesc(const char *relname); +extern TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases); + +/* from execTuples.c */ +extern TupleDesc BlessTupleDesc(TupleDesc tupdesc); +extern AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc); +extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values); +extern Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple); + + +/*---------- + * Support for Set Returning Functions (SRFs) + * + * The basic API for SRFs using ValuePerCall mode looks something like this: + * + * Datum + * my_Set_Returning_Function(PG_FUNCTION_ARGS) + * { + * FuncCallContext *funcctx; + * Datum result; + * MemoryContext oldcontext; + * <user defined declarations> + * + * if (SRF_IS_FIRSTCALL()) + * { + * funcctx = SRF_FIRSTCALL_INIT(); + * // switch context when allocating stuff to be used in later calls + * oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + * <user defined code> + * <if returning composite> + * <build TupleDesc, and perhaps AttInMetadata> + * <endif returning composite> + * <user defined code> + * // return to original context when allocating transient memory + * MemoryContextSwitchTo(oldcontext); + * } + * <user defined code> + * funcctx = SRF_PERCALL_SETUP(); + * <user defined code> + * + * if (funcctx->call_cntr < funcctx->max_calls) + * { + * <user defined code> + * <obtain result Datum> + * SRF_RETURN_NEXT(funcctx, result); + * } + * else + * SRF_RETURN_DONE(funcctx); + * } + * + * NOTE: there is no guarantee that a SRF using ValuePerCall mode will be + * run to completion; for example, a query with LIMIT might stop short of + * fetching all the rows. Therefore, do not expect that you can do resource + * cleanup just before SRF_RETURN_DONE(). You need not worry about releasing + * memory allocated in multi_call_memory_ctx, but holding file descriptors or + * other non-memory resources open across calls is a bug. SRFs that need + * such resources should not use these macros, but instead populate a + * tuplestore during a single call, as set up by InitMaterializedSRF() (see + * fmgr/README). Alternatively, set up a callback to release resources + * at query shutdown, using RegisterExprContextCallback(). + * + *---------- + */ + +/* from funcapi.c */ + +/* flag bits for InitMaterializedSRF() */ +#define MAT_SRF_USE_EXPECTED_DESC 0x01 /* use expectedDesc as tupdesc. */ +#define MAT_SRF_BLESS 0x02 /* "Bless" a tuple descriptor with + * BlessTupleDesc(). */ +extern void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags); + +/* Compatibility declarations, for v15 */ +#define SRF_SINGLE_USE_EXPECTED MAT_SRF_USE_EXPECTED_DESC +#define SRF_SINGLE_BLESS MAT_SRF_BLESS +extern void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags); + +extern FuncCallContext *init_MultiFuncCall(PG_FUNCTION_ARGS); +extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS); +extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx); + +#define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL) + +#define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo) + +#define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo) + +#define SRF_RETURN_NEXT(_funcctx, _result) \ + do { \ + ReturnSetInfo *rsi; \ + (_funcctx)->call_cntr++; \ + rsi = (ReturnSetInfo *) fcinfo->resultinfo; \ + rsi->isDone = ExprMultipleResult; \ + PG_RETURN_DATUM(_result); \ + } while (0) + +#define SRF_RETURN_NEXT_NULL(_funcctx) \ + do { \ + ReturnSetInfo *rsi; \ + (_funcctx)->call_cntr++; \ + rsi = (ReturnSetInfo *) fcinfo->resultinfo; \ + rsi->isDone = ExprMultipleResult; \ + PG_RETURN_NULL(); \ + } while (0) + +#define SRF_RETURN_DONE(_funcctx) \ + do { \ + ReturnSetInfo *rsi; \ + end_MultiFuncCall(fcinfo, _funcctx); \ + rsi = (ReturnSetInfo *) fcinfo->resultinfo; \ + rsi->isDone = ExprEndResult; \ + PG_RETURN_NULL(); \ + } while (0) + +/*---------- + * Support to ease writing of functions dealing with VARIADIC inputs + *---------- + * + * This function extracts a set of argument values, types and NULL markers + * for a given input function. This returns a set of data: + * - **values includes the set of Datum values extracted. + * - **types the data type OID for each element. + * - **nulls tracks if an element is NULL. + * + * variadic_start indicates the argument number where the VARIADIC argument + * starts. + * convert_unknown set to true will enforce the conversion of arguments + * with unknown data type to text. + * + * The return result is the number of elements stored, or -1 in the case of + * "VARIADIC NULL". + */ +extern int extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, + bool convert_unknown, Datum **values, + Oid **types, bool **nulls); + +#endif /* FUNCAPI_H */ diff --git a/src/include/getaddrinfo.h b/src/include/getaddrinfo.h new file mode 100644 index 0000000..2042c2d --- /dev/null +++ b/src/include/getaddrinfo.h @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------- + * + * getaddrinfo.h + * Support getaddrinfo() on platforms that don't have it. + * + * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, + * whether or not the library routine getaddrinfo() can be found. This + * policy is needed because on some platforms a manually installed libbind.a + * may provide getaddrinfo(), yet the system headers may not provide the + * struct definitions needed to call it. To avoid conflict with the libbind + * definition in such cases, we rename our routines to pg_xxx() via macros. + * + * This code will also work on platforms where struct addrinfo is defined + * in the system headers but no getaddrinfo() can be located. + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/getaddrinfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef GETADDRINFO_H +#define GETADDRINFO_H + +#include <sys/socket.h> +#include <netdb.h> + + +/* Various macros that ought to be in <netdb.h>, but might not be */ + +#ifndef EAI_FAIL +#ifndef WIN32 +#define EAI_BADFLAGS (-1) +#define EAI_NONAME (-2) +#define EAI_AGAIN (-3) +#define EAI_FAIL (-4) +#define EAI_FAMILY (-6) +#define EAI_SOCKTYPE (-7) +#define EAI_SERVICE (-8) +#define EAI_MEMORY (-10) +#define EAI_SYSTEM (-11) +#else /* WIN32 */ +#ifdef _MSC_VER +#ifndef WSA_NOT_ENOUGH_MEMORY +#define WSA_NOT_ENOUGH_MEMORY (WSAENOBUFS) +#endif +#define WSATYPE_NOT_FOUND (WSABASEERR+109) +#endif +#define EAI_AGAIN WSATRY_AGAIN +#define EAI_BADFLAGS WSAEINVAL +#define EAI_FAIL WSANO_RECOVERY +#define EAI_FAMILY WSAEAFNOSUPPORT +#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY +#define EAI_NODATA WSANO_DATA +#define EAI_NONAME WSAHOST_NOT_FOUND +#define EAI_SERVICE WSATYPE_NOT_FOUND +#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT +#endif /* !WIN32 */ +#endif /* !EAI_FAIL */ + +#ifndef AI_PASSIVE +#define AI_PASSIVE 0x0001 +#endif + +#ifndef AI_NUMERICHOST +/* + * some platforms don't support AI_NUMERICHOST; define as zero if using + * the system version of getaddrinfo... + */ +#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) +#define AI_NUMERICHOST 0 +#else +#define AI_NUMERICHOST 0x0004 +#endif +#endif + +#ifndef NI_NUMERICHOST +#define NI_NUMERICHOST 1 +#endif +#ifndef NI_NUMERICSERV +#define NI_NUMERICSERV 2 +#endif +#ifndef NI_NAMEREQD +#define NI_NAMEREQD 4 +#endif + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif +#ifndef NI_MAXSERV +#define NI_MAXSERV 32 +#endif + + +#ifndef HAVE_STRUCT_ADDRINFO + +#ifndef WIN32 +struct addrinfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; +#else +/* + * The order of the structure elements on Win32 doesn't match the + * order specified in the standard, but we have to match it for + * IPv6 to work. + */ +struct addrinfo +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#endif /* HAVE_STRUCT_ADDRINFO */ + + +#ifndef HAVE_GETADDRINFO + +/* Rename private copies per comments above */ +#ifdef getaddrinfo +#undef getaddrinfo +#endif +#define getaddrinfo pg_getaddrinfo + +#ifdef freeaddrinfo +#undef freeaddrinfo +#endif +#define freeaddrinfo pg_freeaddrinfo + +#ifdef gai_strerror +#undef gai_strerror +#endif +#define gai_strerror pg_gai_strerror + +#ifdef getnameinfo +#undef getnameinfo +#endif +#define getnameinfo pg_getnameinfo + +extern int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +extern void freeaddrinfo(struct addrinfo *res); +extern const char *gai_strerror(int errcode); +extern int getnameinfo(const struct sockaddr *sa, int salen, + char *node, int nodelen, + char *service, int servicelen, int flags); +#endif /* HAVE_GETADDRINFO */ + +#endif /* GETADDRINFO_H */ diff --git a/src/include/getopt_long.h b/src/include/getopt_long.h new file mode 100644 index 0000000..83dde67 --- /dev/null +++ b/src/include/getopt_long.h @@ -0,0 +1,36 @@ +/* + * Portions Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Portions Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/getopt_long.h + */ +#ifndef GETOPT_LONG_H +#define GETOPT_LONG_H + +#include "pg_getopt.h" + +#ifndef HAVE_STRUCT_OPTION + +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 +#endif + +#ifndef HAVE_GETOPT_LONG + +extern int getopt_long(int argc, char *const argv[], + const char *optstring, + const struct option *longopts, int *longindex); +#endif + +#endif /* GETOPT_LONG_H */ diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h new file mode 100644 index 0000000..d194033 --- /dev/null +++ b/src/include/jit/jit.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------- + * jit.h + * Provider independent JIT infrastructure. + * + * Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/jit/jit.h + * + *------------------------------------------------------------------------- + */ +#ifndef JIT_H +#define JIT_H + +#include "executor/instrument.h" +#include "utils/resowner.h" + + +/* Flags determining what kind of JIT operations to perform */ +#define PGJIT_NONE 0 +#define PGJIT_PERFORM (1 << 0) +#define PGJIT_OPT3 (1 << 1) +#define PGJIT_INLINE (1 << 2) +#define PGJIT_EXPR (1 << 3) +#define PGJIT_DEFORM (1 << 4) + + +typedef struct JitInstrumentation +{ + /* number of emitted functions */ + size_t created_functions; + + /* accumulated time to generate code */ + instr_time generation_counter; + + /* accumulated time for inlining */ + instr_time inlining_counter; + + /* accumulated time for optimization */ + instr_time optimization_counter; + + /* accumulated time for code emission */ + instr_time emission_counter; +} JitInstrumentation; + +/* + * DSM structure for accumulating jit instrumentation of all workers. + */ +typedef struct SharedJitInstrumentation +{ + int num_workers; + JitInstrumentation jit_instr[FLEXIBLE_ARRAY_MEMBER]; +} SharedJitInstrumentation; + +typedef struct JitContext +{ + /* see PGJIT_* above */ + int flags; + + ResourceOwner resowner; + + JitInstrumentation instr; +} JitContext; + +typedef struct JitProviderCallbacks JitProviderCallbacks; + +extern void _PG_jit_provider_init(JitProviderCallbacks *cb); +typedef void (*JitProviderInit) (JitProviderCallbacks *cb); +typedef void (*JitProviderResetAfterErrorCB) (void); +typedef void (*JitProviderReleaseContextCB) (JitContext *context); +struct ExprState; +typedef bool (*JitProviderCompileExprCB) (struct ExprState *state); + +struct JitProviderCallbacks +{ + JitProviderResetAfterErrorCB reset_after_error; + JitProviderReleaseContextCB release_context; + JitProviderCompileExprCB compile_expr; +}; + + +/* GUCs */ +extern PGDLLIMPORT bool jit_enabled; +extern PGDLLIMPORT char *jit_provider; +extern PGDLLIMPORT bool jit_debugging_support; +extern PGDLLIMPORT bool jit_dump_bitcode; +extern PGDLLIMPORT bool jit_expressions; +extern PGDLLIMPORT bool jit_profiling_support; +extern PGDLLIMPORT bool jit_tuple_deforming; +extern PGDLLIMPORT double jit_above_cost; +extern PGDLLIMPORT double jit_inline_above_cost; +extern PGDLLIMPORT double jit_optimize_above_cost; + + +extern void jit_reset_after_error(void); +extern void jit_release_context(JitContext *context); + +/* + * Functions for attempting to JIT code. Callers must accept that these might + * not be able to perform JIT (i.e. return false). + */ +extern bool jit_compile_expr(struct ExprState *state); +extern void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add); + + +#endif /* JIT_H */ diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h new file mode 100644 index 0000000..fe769e0 --- /dev/null +++ b/src/include/jit/llvmjit.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- + * llvmjit.h + * LLVM JIT provider. + * + * Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/jit/llvmjit.h + * + *------------------------------------------------------------------------- + */ +#ifndef LLVMJIT_H +#define LLVMJIT_H + +/* + * To avoid breaking cpluspluscheck, allow including the file even when LLVM + * is not available. + */ +#ifdef USE_LLVM + +#include <llvm-c/Types.h> + + +/* + * File needs to be includable by both C and C++ code, and include other + * headers doing the same. Therefore wrap C portion in our own extern "C" if + * in C++ mode. + */ +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "access/tupdesc.h" +#include "fmgr.h" +#include "jit/jit.h" +#include "nodes/pg_list.h" + +typedef struct LLVMJitContext +{ + JitContext base; + + /* number of modules created */ + size_t module_generation; + + /* current, "open for write", module */ + LLVMModuleRef module; + + /* is there any pending code that needs to be emitted */ + bool compiled; + + /* # of objects emitted, used to generate non-conflicting names */ + int counter; + + /* list of handles for code emitted via Orc */ + List *handles; +} LLVMJitContext; + +/* llvm module containing information about types */ +extern PGDLLIMPORT LLVMModuleRef llvm_types_module; + +/* type and struct definitions */ +extern PGDLLIMPORT LLVMTypeRef TypeParamBool; +extern PGDLLIMPORT LLVMTypeRef TypePGFunction; +extern PGDLLIMPORT LLVMTypeRef TypeSizeT; +extern PGDLLIMPORT LLVMTypeRef TypeStorageBool; + +extern PGDLLIMPORT LLVMTypeRef StructNullableDatum; +extern PGDLLIMPORT LLVMTypeRef StructTupleDescData; +extern PGDLLIMPORT LLVMTypeRef StructHeapTupleData; +extern PGDLLIMPORT LLVMTypeRef StructHeapTupleHeaderData; +extern PGDLLIMPORT LLVMTypeRef StructMinimalTupleData; +extern PGDLLIMPORT LLVMTypeRef StructTupleTableSlot; +extern PGDLLIMPORT LLVMTypeRef StructHeapTupleTableSlot; +extern PGDLLIMPORT LLVMTypeRef StructMinimalTupleTableSlot; +extern PGDLLIMPORT LLVMTypeRef StructMemoryContextData; +extern PGDLLIMPORT LLVMTypeRef StructFunctionCallInfoData; +extern PGDLLIMPORT LLVMTypeRef StructExprContext; +extern PGDLLIMPORT LLVMTypeRef StructExprEvalStep; +extern PGDLLIMPORT LLVMTypeRef StructExprState; +extern PGDLLIMPORT LLVMTypeRef StructAggState; +extern PGDLLIMPORT LLVMTypeRef StructAggStatePerTransData; +extern PGDLLIMPORT LLVMTypeRef StructAggStatePerGroupData; +extern PGDLLIMPORT LLVMTypeRef StructPlanState; + +extern PGDLLIMPORT LLVMValueRef AttributeTemplate; +extern PGDLLIMPORT LLVMValueRef ExecEvalBoolSubroutineTemplate; +extern PGDLLIMPORT LLVMValueRef ExecEvalSubroutineTemplate; + + +extern void llvm_enter_fatal_on_oom(void); +extern void llvm_leave_fatal_on_oom(void); +extern bool llvm_in_fatal_on_oom(void); +extern void llvm_reset_after_error(void); +extern void llvm_assert_in_fatal_section(void); + +extern LLVMJitContext *llvm_create_context(int jitFlags); +extern LLVMModuleRef llvm_mutable_module(LLVMJitContext *context); +extern char *llvm_expand_funcname(LLVMJitContext *context, const char *basename); +extern void *llvm_get_function(LLVMJitContext *context, const char *funcname); +extern void llvm_split_symbol_name(const char *name, char **modname, char **funcname); +extern LLVMTypeRef llvm_pg_var_type(const char *varname); +extern LLVMTypeRef llvm_pg_var_func_type(const char *varname); +extern LLVMValueRef llvm_pg_func(LLVMModuleRef mod, const char *funcname); +extern void llvm_copy_attributes(LLVMValueRef from, LLVMValueRef to); +extern LLVMValueRef llvm_function_reference(LLVMJitContext *context, + LLVMBuilderRef builder, + LLVMModuleRef mod, + FunctionCallInfo fcinfo); + +extern void llvm_inline(LLVMModuleRef mod); + +/* + **************************************************************************** + * Code generation functions. + **************************************************************************** + */ +extern bool llvm_compile_expr(struct ExprState *state); +struct TupleTableSlotOps; +extern LLVMValueRef slot_compile_deform(struct LLVMJitContext *context, TupleDesc desc, + const struct TupleTableSlotOps *ops, int natts); + +/* + **************************************************************************** + * Extensions / Backward compatibility section of the LLVM C API + * Error handling related functions. + **************************************************************************** + */ +#if defined(HAVE_DECL_LLVMGETHOSTCPUNAME) && !HAVE_DECL_LLVMGETHOSTCPUNAME +/** Get the host CPU as a string. The result needs to be disposed with + LLVMDisposeMessage. */ +extern char *LLVMGetHostCPUName(void); +#endif + +#if defined(HAVE_DECL_LLVMGETHOSTCPUFEATURES) && !HAVE_DECL_LLVMGETHOSTCPUFEATURES +/** Get the host CPU features as a string. The result needs to be disposed + with LLVMDisposeMessage. */ +extern char *LLVMGetHostCPUFeatures(void); +#endif + +extern unsigned LLVMGetAttributeCountAtIndexPG(LLVMValueRef F, uint32 Idx); +extern LLVMTypeRef LLVMGetFunctionReturnType(LLVMValueRef r); +extern LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r); + +#if LLVM_MAJOR_VERSION < 8 +extern LLVMTypeRef LLVMGlobalGetValueType(LLVMValueRef g); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* USE_LLVM */ +#endif /* LLVMJIT_H */ diff --git a/src/include/jit/llvmjit_emit.h b/src/include/jit/llvmjit_emit.h new file mode 100644 index 0000000..27a080b --- /dev/null +++ b/src/include/jit/llvmjit_emit.h @@ -0,0 +1,330 @@ +/* + * llvmjit_emit.h + * Helpers to make emitting LLVM IR a bit more concise and pgindent proof. + * + * Copyright (c) 2018-2022, PostgreSQL Global Development Group + * + * src/include/jit/llvmjit_emit.h + */ +#ifndef LLVMJIT_EMIT_H +#define LLVMJIT_EMIT_H + +/* + * To avoid breaking cpluspluscheck, allow including the file even when LLVM + * is not available. + */ +#ifdef USE_LLVM + +#include <llvm-c/Core.h> +#include <llvm-c/Target.h> + +#include "jit/llvmjit.h" + + +/* + * Emit a non-LLVM pointer as an LLVM constant. + */ +static inline LLVMValueRef +l_ptr_const(void *ptr, LLVMTypeRef type) +{ + LLVMValueRef c = LLVMConstInt(TypeSizeT, (uintptr_t) ptr, false); + + return LLVMConstIntToPtr(c, type); +} + +/* + * Emit pointer. + */ +static inline LLVMTypeRef +l_ptr(LLVMTypeRef t) +{ + return LLVMPointerType(t, 0); +} + +/* + * Emit constant integer. + */ +static inline LLVMValueRef +l_int8_const(int8 i) +{ + return LLVMConstInt(LLVMInt8Type(), i, false); +} + +/* + * Emit constant integer. + */ +static inline LLVMValueRef +l_int16_const(int16 i) +{ + return LLVMConstInt(LLVMInt16Type(), i, false); +} + +/* + * Emit constant integer. + */ +static inline LLVMValueRef +l_int32_const(int32 i) +{ + return LLVMConstInt(LLVMInt32Type(), i, false); +} + +/* + * Emit constant integer. + */ +static inline LLVMValueRef +l_int64_const(int64 i) +{ + return LLVMConstInt(LLVMInt64Type(), i, false); +} + +/* + * Emit constant integer. + */ +static inline LLVMValueRef +l_sizet_const(size_t i) +{ + return LLVMConstInt(TypeSizeT, i, false); +} + +/* + * Emit constant boolean, as used for storage (e.g. global vars, structs). + */ +static inline LLVMValueRef +l_sbool_const(bool i) +{ + return LLVMConstInt(TypeStorageBool, (int) i, false); +} + +/* + * Emit constant boolean, as used for parameters (e.g. function parameters). + */ +static inline LLVMValueRef +l_pbool_const(bool i) +{ + return LLVMConstInt(TypeParamBool, (int) i, false); +} + +static inline LLVMValueRef +l_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name) +{ +#if LLVM_VERSION_MAJOR < 16 + return LLVMBuildStructGEP(b, v, idx, ""); +#else + return LLVMBuildStructGEP2(b, t, v, idx, ""); +#endif +} + +static inline LLVMValueRef +l_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef *indices, int32 nindices, const char *name) +{ +#if LLVM_VERSION_MAJOR < 16 + return LLVMBuildGEP(b, v, indices, nindices, name); +#else + return LLVMBuildGEP2(b, t, v, indices, nindices, name); +#endif +} + +static inline LLVMValueRef +l_load(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, const char *name) +{ +#if LLVM_VERSION_MAJOR < 16 + return LLVMBuildLoad(b, v, name); +#else + return LLVMBuildLoad2(b, t, v, name); +#endif +} + +static inline LLVMValueRef +l_call(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef fn, LLVMValueRef *args, int32 nargs, const char *name) +{ +#if LLVM_VERSION_MAJOR < 16 + return LLVMBuildCall(b, fn, args, nargs, name); +#else + return LLVMBuildCall2(b, t, fn, args, nargs, name); +#endif +} + +/* + * Load a pointer member idx from a struct. + */ +static inline LLVMValueRef +l_load_struct_gep(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, int32 idx, const char *name) +{ + return l_load(b, + LLVMStructGetTypeAtIndex(t, idx), + l_struct_gep(b, t, v, idx, ""), + name); +} + +/* + * Load value of a pointer, after applying one index operation. + */ +static inline LLVMValueRef +l_load_gep1(LLVMBuilderRef b, LLVMTypeRef t, LLVMValueRef v, LLVMValueRef idx, const char *name) +{ + return l_load(b, t, l_gep(b, t, v, &idx, 1, ""), name); +} + +/* separate, because pg_attribute_printf(2, 3) can't appear in definition */ +static inline LLVMBasicBlockRef l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...) pg_attribute_printf(2, 3); + +/* + * Insert a new basic block, just before r, the name being determined by fmt + * and arguments. + */ +static inline LLVMBasicBlockRef +l_bb_before_v(LLVMBasicBlockRef r, const char *fmt,...) +{ + char buf[512]; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + return LLVMInsertBasicBlock(r, buf); +} + +/* separate, because pg_attribute_printf(2, 3) can't appear in definition */ +static inline LLVMBasicBlockRef l_bb_append_v(LLVMValueRef f, const char *fmt,...) pg_attribute_printf(2, 3); + +/* + * Insert a new basic block after previous basic blocks, the name being + * determined by fmt and arguments. + */ +static inline LLVMBasicBlockRef +l_bb_append_v(LLVMValueRef f, const char *fmt,...) +{ + char buf[512]; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + return LLVMAppendBasicBlock(f, buf); +} + +/* + * Mark a callsite as readonly. + */ +static inline void +l_callsite_ro(LLVMValueRef f) +{ + const char argname[] = "readonly"; + LLVMAttributeRef ref; + + ref = LLVMCreateStringAttribute(LLVMGetGlobalContext(), + argname, + sizeof(argname) - 1, + NULL, 0); + + LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, ref); +} + +/* + * Mark a callsite as alwaysinline. + */ +static inline void +l_callsite_alwaysinline(LLVMValueRef f) +{ + const char argname[] = "alwaysinline"; + int id; + LLVMAttributeRef attr; + + id = LLVMGetEnumAttributeKindForName(argname, + sizeof(argname) - 1); + attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), id, 0); + LLVMAddCallSiteAttribute(f, LLVMAttributeFunctionIndex, attr); +} + +/* + * Emit code to switch memory context. + */ +static inline LLVMValueRef +l_mcxt_switch(LLVMModuleRef mod, LLVMBuilderRef b, LLVMValueRef nc) +{ + const char *cmc = "CurrentMemoryContext"; + LLVMValueRef cur; + LLVMValueRef ret; + + if (!(cur = LLVMGetNamedGlobal(mod, cmc))) + cur = LLVMAddGlobal(mod, l_ptr(StructMemoryContextData), cmc); + ret = l_load(b, l_ptr(StructMemoryContextData), cur, cmc); + LLVMBuildStore(b, nc, cur); + + return ret; +} + +/* + * Return pointer to the argno'th argument nullness. + */ +static inline LLVMValueRef +l_funcnullp(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno) +{ + LLVMValueRef v_args; + LLVMValueRef v_argn; + + v_args = l_struct_gep(b, + StructFunctionCallInfoData, + v_fcinfo, + FIELDNO_FUNCTIONCALLINFODATA_ARGS, + ""); + v_argn = l_struct_gep(b, + LLVMArrayType(StructNullableDatum, 0), + v_args, + argno, + ""); + return l_struct_gep(b, + StructNullableDatum, + v_argn, + FIELDNO_NULLABLE_DATUM_ISNULL, + ""); +} + +/* + * Return pointer to the argno'th argument datum. + */ +static inline LLVMValueRef +l_funcvaluep(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno) +{ + LLVMValueRef v_args; + LLVMValueRef v_argn; + + v_args = l_struct_gep(b, + StructFunctionCallInfoData, + v_fcinfo, + FIELDNO_FUNCTIONCALLINFODATA_ARGS, + ""); + v_argn = l_struct_gep(b, + LLVMArrayType(StructNullableDatum, 0), + v_args, + argno, + ""); + return l_struct_gep(b, + StructNullableDatum, + v_argn, + FIELDNO_NULLABLE_DATUM_DATUM, + ""); +} + +/* + * Return argno'th argument nullness. + */ +static inline LLVMValueRef +l_funcnull(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno) +{ + return l_load(b, TypeStorageBool, l_funcnullp(b, v_fcinfo, argno), ""); +} + +/* + * Return argno'th argument datum. + */ +static inline LLVMValueRef +l_funcvalue(LLVMBuilderRef b, LLVMValueRef v_fcinfo, size_t argno) +{ + return l_load(b, TypeSizeT, l_funcvaluep(b, v_fcinfo, argno), ""); +} + +#endif /* USE_LLVM */ +#endif diff --git a/src/include/lib/binaryheap.h b/src/include/lib/binaryheap.h new file mode 100644 index 0000000..e420e07 --- /dev/null +++ b/src/include/lib/binaryheap.h @@ -0,0 +1,54 @@ +/* + * binaryheap.h + * + * A simple binary heap implementation + * + * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + * src/include/lib/binaryheap.h + */ + +#ifndef BINARYHEAP_H +#define BINARYHEAP_H + +/* + * For a max-heap, the comparator must return <0 iff a < b, 0 iff a == b, + * and >0 iff a > b. For a min-heap, the conditions are reversed. + */ +typedef int (*binaryheap_comparator) (Datum a, Datum b, void *arg); + +/* + * binaryheap + * + * bh_size how many nodes are currently in "nodes" + * bh_space how many nodes can be stored in "nodes" + * bh_has_heap_property no unordered operations since last heap build + * bh_compare comparison function to define the heap property + * bh_arg user data for comparison function + * bh_nodes variable-length array of "space" nodes + */ +typedef struct binaryheap +{ + int bh_size; + int bh_space; + bool bh_has_heap_property; /* debugging cross-check */ + binaryheap_comparator bh_compare; + void *bh_arg; + Datum bh_nodes[FLEXIBLE_ARRAY_MEMBER]; +} binaryheap; + +extern binaryheap *binaryheap_allocate(int capacity, + binaryheap_comparator compare, + void *arg); +extern void binaryheap_reset(binaryheap *heap); +extern void binaryheap_free(binaryheap *heap); +extern void binaryheap_add_unordered(binaryheap *heap, Datum d); +extern void binaryheap_build(binaryheap *heap); +extern void binaryheap_add(binaryheap *heap, Datum d); +extern Datum binaryheap_first(binaryheap *heap); +extern Datum binaryheap_remove_first(binaryheap *heap); +extern void binaryheap_replace_first(binaryheap *heap, Datum d); + +#define binaryheap_empty(h) ((h)->bh_size == 0) + +#endif /* BINARYHEAP_H */ diff --git a/src/include/lib/bipartite_match.h b/src/include/lib/bipartite_match.h new file mode 100644 index 0000000..7560883 --- /dev/null +++ b/src/include/lib/bipartite_match.h @@ -0,0 +1,46 @@ +/* + * bipartite_match.h + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * src/include/lib/bipartite_match.h + */ +#ifndef BIPARTITE_MATCH_H +#define BIPARTITE_MATCH_H + +/* + * Given a bipartite graph consisting of nodes U numbered 1..nU, nodes V + * numbered 1..nV, and an adjacency map of undirected edges in the form + * adjacency[u] = [k, v1, v2, v3, ... vk], we wish to find a "maximum + * cardinality matching", which is defined as follows: a matching is a subset + * of the original edges such that no node has more than one edge, and a + * matching has maximum cardinality if there exists no other matching with a + * greater number of edges. + * + * This matching has various applications in graph theory, but the motivating + * example here is Dilworth's theorem: a partially-ordered set can be divided + * into the minimum number of chains (i.e. subsets X where x1 < x2 < x3 ...) by + * a bipartite graph construction. This gives us a polynomial-time solution to + * the problem of planning a collection of grouping sets with the provably + * minimal number of sort operations. + */ +typedef struct BipartiteMatchState +{ + /* inputs: */ + int u_size; /* size of U */ + int v_size; /* size of V */ + short **adjacency; /* adjacency[u] = [k, v1,v2,v3,...,vk] */ + /* outputs: */ + int matching; /* number of edges in matching */ + short *pair_uv; /* pair_uv[u] -> v */ + short *pair_vu; /* pair_vu[v] -> u */ + /* private state for matching algorithm: */ + short *distance; /* distance[u] */ + short *queue; /* queue storage for breadth search */ +} BipartiteMatchState; + +extern BipartiteMatchState *BipartiteMatch(int u_size, int v_size, short **adjacency); + +extern void BipartiteMatchFree(BipartiteMatchState *state); + +#endif /* BIPARTITE_MATCH_H */ diff --git a/src/include/lib/bloomfilter.h b/src/include/lib/bloomfilter.h new file mode 100644 index 0000000..8146d8e --- /dev/null +++ b/src/include/lib/bloomfilter.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------- + * + * bloomfilter.h + * Space-efficient set membership testing + * + * Copyright (c) 2018-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/lib/bloomfilter.h + * + *------------------------------------------------------------------------- + */ +#ifndef BLOOMFILTER_H +#define BLOOMFILTER_H + +typedef struct bloom_filter bloom_filter; + +extern bloom_filter *bloom_create(int64 total_elems, int bloom_work_mem, + uint64 seed); +extern void bloom_free(bloom_filter *filter); +extern void bloom_add_element(bloom_filter *filter, unsigned char *elem, + size_t len); +extern bool bloom_lacks_element(bloom_filter *filter, unsigned char *elem, + size_t len); +extern double bloom_prop_bits_set(bloom_filter *filter); + +#endif /* BLOOMFILTER_H */ diff --git a/src/include/lib/dshash.h b/src/include/lib/dshash.h new file mode 100644 index 0000000..28f8db2 --- /dev/null +++ b/src/include/lib/dshash.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * dshash.h + * Concurrent hash tables backed by dynamic shared memory areas. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/lib/dshash.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSHASH_H +#define DSHASH_H + +#include "utils/dsa.h" + +/* The opaque type representing a hash table. */ +struct dshash_table; +typedef struct dshash_table dshash_table; + +/* A handle for a dshash_table which can be shared with other processes. */ +typedef dsa_pointer dshash_table_handle; + +/* The type for hash values. */ +typedef uint32 dshash_hash; + +/* A function type for comparing keys. */ +typedef int (*dshash_compare_function) (const void *a, const void *b, + size_t size, void *arg); + +/* A function type for computing hash values for keys. */ +typedef dshash_hash (*dshash_hash_function) (const void *v, size_t size, + void *arg); + +/* + * The set of parameters needed to create or attach to a hash table. The + * members tranche_id and tranche_name do not need to be initialized when + * attaching to an existing hash table. + * + * Compare and hash functions must be supplied even when attaching, because we + * can't safely share function pointers between backends in general. Either + * the arg variants or the non-arg variants should be supplied; the other + * function pointers should be NULL. If the arg variants are supplied then the + * user data pointer supplied to the create and attach functions will be + * passed to the hash and compare functions. + */ +typedef struct dshash_parameters +{ + size_t key_size; /* Size of the key (initial bytes of entry) */ + size_t entry_size; /* Total size of entry */ + dshash_compare_function compare_function; /* Compare function */ + dshash_hash_function hash_function; /* Hash function */ + int tranche_id; /* The tranche ID to use for locks */ +} dshash_parameters; + +/* Forward declaration of private types for use only by dshash.c. */ +struct dshash_table_item; +typedef struct dshash_table_item dshash_table_item; + +/* + * Sequential scan state. The detail is exposed to let users know the storage + * size but it should be considered as an opaque type by callers. + */ +typedef struct dshash_seq_status +{ + dshash_table *hash_table; /* dshash table working on */ + int curbucket; /* bucket number we are at */ + int nbuckets; /* total number of buckets in the dshash */ + dshash_table_item *curitem; /* item we are currently at */ + dsa_pointer pnextitem; /* dsa-pointer to the next item */ + int curpartition; /* partition number we are at */ + bool exclusive; /* locking mode */ +} dshash_seq_status; + +/* Creating, sharing and destroying from hash tables. */ +extern dshash_table *dshash_create(dsa_area *area, + const dshash_parameters *params, + void *arg); +extern dshash_table *dshash_attach(dsa_area *area, + const dshash_parameters *params, + dshash_table_handle handle, + void *arg); +extern void dshash_detach(dshash_table *hash_table); +extern dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table); +extern void dshash_destroy(dshash_table *hash_table); + +/* Finding, creating, deleting entries. */ +extern void *dshash_find(dshash_table *hash_table, + const void *key, bool exclusive); +extern void *dshash_find_or_insert(dshash_table *hash_table, + const void *key, bool *found); +extern bool dshash_delete_key(dshash_table *hash_table, const void *key); +extern void dshash_delete_entry(dshash_table *hash_table, void *entry); +extern void dshash_release_lock(dshash_table *hash_table, void *entry); + +/* seq scan support */ +extern void dshash_seq_init(dshash_seq_status *status, dshash_table *hash_table, + bool exclusive); +extern void *dshash_seq_next(dshash_seq_status *status); +extern void dshash_seq_term(dshash_seq_status *status); +extern void dshash_delete_current(dshash_seq_status *status); + +/* Convenience hash and compare functions wrapping memcmp and tag_hash. */ +extern int dshash_memcmp(const void *a, const void *b, size_t size, void *arg); +extern dshash_hash dshash_memhash(const void *v, size_t size, void *arg); + +/* Debugging support. */ +extern void dshash_dump(dshash_table *hash_table); + +#endif /* DSHASH_H */ diff --git a/src/include/lib/hyperloglog.h b/src/include/lib/hyperloglog.h new file mode 100644 index 0000000..414bcb4 --- /dev/null +++ b/src/include/lib/hyperloglog.h @@ -0,0 +1,68 @@ +/* + * hyperloglog.h + * + * A simple HyperLogLog cardinality estimator implementation + * + * Portions Copyright (c) 2014-2022, PostgreSQL Global Development Group + * + * Based on Hideaki Ohno's C++ implementation. The copyright terms of Ohno's + * original version (the MIT license) follow. + * + * src/include/lib/hyperloglog.h + */ + +/* + * Copyright (c) 2013 Hideaki Ohno <hide.o.j55{at}gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the 'Software'), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef HYPERLOGLOG_H +#define HYPERLOGLOG_H + +/* + * HyperLogLog is an approximate technique for computing the number of distinct + * entries in a set. Importantly, it does this by using a fixed amount of + * memory. See the 2007 paper "HyperLogLog: the analysis of a near-optimal + * cardinality estimation algorithm" for more. + * + * hyperLogLogState + * + * registerWidth register width, in bits ("k") + * nRegisters number of registers + * alphaMM alpha * m ^ 2 (see initHyperLogLog()) + * hashesArr array of hashes + * arrSize size of hashesArr + */ +typedef struct hyperLogLogState +{ + uint8 registerWidth; + Size nRegisters; + double alphaMM; + uint8 *hashesArr; + Size arrSize; +} hyperLogLogState; + +extern void initHyperLogLog(hyperLogLogState *cState, uint8 bwidth); +extern void initHyperLogLogError(hyperLogLogState *cState, double error); +extern void addHyperLogLog(hyperLogLogState *cState, uint32 hash); +extern double estimateHyperLogLog(hyperLogLogState *cState); +extern void freeHyperLogLog(hyperLogLogState *cState); + +#endif /* HYPERLOGLOG_H */ diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h new file mode 100644 index 0000000..7ab0888 --- /dev/null +++ b/src/include/lib/ilist.h @@ -0,0 +1,746 @@ +/*------------------------------------------------------------------------- + * + * ilist.h + * integrated/inline doubly- and singly-linked lists + * + * These list types are useful when there are only a predetermined set of + * lists that an object could be in. List links are embedded directly into + * the objects, and thus no extra memory management overhead is required. + * (Of course, if only a small proportion of existing objects are in a list, + * the link fields in the remainder would be wasted space. But usually, + * it saves space to not have separately-allocated list nodes.) + * + * None of the functions here allocate any memory; they just manipulate + * externally managed memory. The APIs for singly and doubly linked lists + * are identical as far as capabilities of both allow. + * + * Each list has a list header, which exists even when the list is empty. + * An empty singly-linked list has a NULL pointer in its header. + * There are two kinds of empty doubly linked lists: those that have been + * initialized to NULL, and those that have been initialized to circularity. + * (If a dlist is modified and then all its elements are deleted, it will be + * in the circular state.) We prefer circular dlists because there are some + * operations that can be done without branches (and thus faster) on lists + * that use circular representation. However, it is often convenient to + * initialize list headers to zeroes rather than setting them up with an + * explicit initialization function, so we also allow the other case. + * + * EXAMPLES + * + * Here's a simple example demonstrating how this can be used. Let's assume + * we want to store information about the tables contained in a database. + * + * #include "lib/ilist.h" + * + * // Define struct for the databases including a list header that will be + * // used to access the nodes in the table list later on. + * typedef struct my_database + * { + * char *datname; + * dlist_head tables; + * // ... + * } my_database; + * + * // Define struct for the tables. Note the list_node element which stores + * // prev/next list links. The list_node element need not be first. + * typedef struct my_table + * { + * char *tablename; + * dlist_node list_node; + * perm_t permissions; + * // ... + * } my_table; + * + * // create a database + * my_database *db = create_database(); + * + * // and add a few tables to its table list + * dlist_push_head(&db->tables, &create_table(db, "a")->list_node); + * ... + * dlist_push_head(&db->tables, &create_table(db, "b")->list_node); + * + * + * To iterate over the table list, we allocate an iterator variable and use + * a specialized looping construct. Inside a dlist_foreach, the iterator's + * 'cur' field can be used to access the current element. iter.cur points to + * a 'dlist_node', but most of the time what we want is the actual table + * information; dlist_container() gives us that, like so: + * + * dlist_iter iter; + * dlist_foreach(iter, &db->tables) + * { + * my_table *tbl = dlist_container(my_table, list_node, iter.cur); + * printf("we have a table: %s in database %s\n", + * tbl->tablename, db->datname); + * } + * + * + * While a simple iteration is useful, we sometimes also want to manipulate + * the list while iterating. There is a different iterator element and looping + * construct for that. Suppose we want to delete tables that meet a certain + * criterion: + * + * dlist_mutable_iter miter; + * dlist_foreach_modify(miter, &db->tables) + * { + * my_table *tbl = dlist_container(my_table, list_node, miter.cur); + * + * if (!tbl->to_be_deleted) + * continue; // don't touch this one + * + * // unlink the current table from the linked list + * dlist_delete(miter.cur); + * // as these lists never manage memory, we can still access the table + * // after it's been unlinked + * drop_table(db, tbl); + * } + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/lib/ilist.h + *------------------------------------------------------------------------- + */ +#ifndef ILIST_H +#define ILIST_H + +/* + * Enable for extra debugging. This is rather expensive, so it's not enabled by + * default even when USE_ASSERT_CHECKING. + */ +/* #define ILIST_DEBUG */ + +/* + * Node of a doubly linked list. + * + * Embed this in structs that need to be part of a doubly linked list. + */ +typedef struct dlist_node dlist_node; +struct dlist_node +{ + dlist_node *prev; + dlist_node *next; +}; + +/* + * Head of a doubly linked list. + * + * Non-empty lists are internally circularly linked. Circular lists have the + * advantage of not needing any branches in the most common list manipulations. + * An empty list can also be represented as a pair of NULL pointers, making + * initialization easier. + */ +typedef struct dlist_head +{ + /* + * head.next either points to the first element of the list; to &head if + * it's a circular empty list; or to NULL if empty and not circular. + * + * head.prev either points to the last element of the list; to &head if + * it's a circular empty list; or to NULL if empty and not circular. + */ + dlist_node head; +} dlist_head; + + +/* + * Doubly linked list iterator. + * + * Used as state in dlist_foreach() and dlist_reverse_foreach(). To get the + * current element of the iteration use the 'cur' member. + * + * Iterations using this are *not* allowed to change the list while iterating! + * + * NB: We use an extra "end" field here to avoid multiple evaluations of + * arguments in the dlist_foreach() macro. + */ +typedef struct dlist_iter +{ + dlist_node *cur; /* current element */ + dlist_node *end; /* last node we'll iterate to */ +} dlist_iter; + +/* + * Doubly linked list iterator allowing some modifications while iterating. + * + * Used as state in dlist_foreach_modify(). To get the current element of the + * iteration use the 'cur' member. + * + * Iterations using this are only allowed to change the list at the current + * point of iteration. It is fine to delete the current node, but it is *not* + * fine to insert or delete adjacent nodes. + * + * NB: We need a separate type for mutable iterations so that we can store + * the 'next' node of the current node in case it gets deleted or modified. + */ +typedef struct dlist_mutable_iter +{ + dlist_node *cur; /* current element */ + dlist_node *next; /* next node we'll iterate to */ + dlist_node *end; /* last node we'll iterate to */ +} dlist_mutable_iter; + +/* + * Node of a singly linked list. + * + * Embed this in structs that need to be part of a singly linked list. + */ +typedef struct slist_node slist_node; +struct slist_node +{ + slist_node *next; +}; + +/* + * Head of a singly linked list. + * + * Singly linked lists are not circularly linked, in contrast to doubly linked + * lists; we just set head.next to NULL if empty. This doesn't incur any + * additional branches in the usual manipulations. + */ +typedef struct slist_head +{ + slist_node head; +} slist_head; + +/* + * Singly linked list iterator. + * + * Used as state in slist_foreach(). To get the current element of the + * iteration use the 'cur' member. + * + * It's allowed to modify the list while iterating, with the exception of + * deleting the iterator's current node; deletion of that node requires + * care if the iteration is to be continued afterward. (Doing so and also + * deleting or inserting adjacent list elements might misbehave; also, if + * the user frees the current node's storage, continuing the iteration is + * not safe.) + * + * NB: this wouldn't really need to be an extra struct, we could use an + * slist_node * directly. We prefer a separate type for consistency. + */ +typedef struct slist_iter +{ + slist_node *cur; +} slist_iter; + +/* + * Singly linked list iterator allowing some modifications while iterating. + * + * Used as state in slist_foreach_modify(). To get the current element of the + * iteration use the 'cur' member. + * + * The only list modification allowed while iterating is to remove the current + * node via slist_delete_current() (*not* slist_delete()). Insertion or + * deletion of nodes adjacent to the current node would misbehave. + */ +typedef struct slist_mutable_iter +{ + slist_node *cur; /* current element */ + slist_node *next; /* next node we'll iterate to */ + slist_node *prev; /* prev node, for deletions */ +} slist_mutable_iter; + + +/* Static initializers */ +#define DLIST_STATIC_INIT(name) {{&(name).head, &(name).head}} +#define SLIST_STATIC_INIT(name) {{NULL}} + + +/* Prototypes for functions too big to be inline */ + +/* Caution: this is O(n); consider using slist_delete_current() instead */ +extern void slist_delete(slist_head *head, slist_node *node); + +#ifdef ILIST_DEBUG +extern void dlist_check(dlist_head *head); +extern void slist_check(slist_head *head); +#else +/* + * These seemingly useless casts to void are here to keep the compiler quiet + * about the argument being unused in many functions in a non-debug compile, + * in which functions the only point of passing the list head pointer is to be + * able to run these checks. + */ +#define dlist_check(head) ((void) (head)) +#define slist_check(head) ((void) (head)) +#endif /* ILIST_DEBUG */ + +/* doubly linked list implementation */ + +/* + * Initialize a doubly linked list. + * Previous state will be thrown away without any cleanup. + */ +static inline void +dlist_init(dlist_head *head) +{ + head->head.next = head->head.prev = &head->head; +} + +/* + * Is the list empty? + * + * An empty list has either its first 'next' pointer set to NULL, or to itself. + */ +static inline bool +dlist_is_empty(dlist_head *head) +{ + dlist_check(head); + + return head->head.next == NULL || head->head.next == &(head->head); +} + +/* + * Insert a node at the beginning of the list. + */ +static inline void +dlist_push_head(dlist_head *head, dlist_node *node) +{ + if (head->head.next == NULL) /* convert NULL header to circular */ + dlist_init(head); + + node->next = head->head.next; + node->prev = &head->head; + node->next->prev = node; + head->head.next = node; + + dlist_check(head); +} + +/* + * Insert a node at the end of the list. + */ +static inline void +dlist_push_tail(dlist_head *head, dlist_node *node) +{ + if (head->head.next == NULL) /* convert NULL header to circular */ + dlist_init(head); + + node->next = &head->head; + node->prev = head->head.prev; + node->prev->next = node; + head->head.prev = node; + + dlist_check(head); +} + +/* + * Insert a node after another *in the same list* + */ +static inline void +dlist_insert_after(dlist_node *after, dlist_node *node) +{ + node->prev = after; + node->next = after->next; + after->next = node; + node->next->prev = node; +} + +/* + * Insert a node before another *in the same list* + */ +static inline void +dlist_insert_before(dlist_node *before, dlist_node *node) +{ + node->prev = before->prev; + node->next = before; + before->prev = node; + node->prev->next = node; +} + +/* + * Delete 'node' from its list (it must be in one). + */ +static inline void +dlist_delete(dlist_node *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/* + * Remove and return the first node from a list (there must be one). + */ +static inline dlist_node * +dlist_pop_head_node(dlist_head *head) +{ + dlist_node *node; + + Assert(!dlist_is_empty(head)); + node = head->head.next; + dlist_delete(node); + return node; +} + +/* + * Move element from its current position in the list to the head position in + * the same list. + * + * Undefined behaviour if 'node' is not already part of the list. + */ +static inline void +dlist_move_head(dlist_head *head, dlist_node *node) +{ + /* fast path if it's already at the head */ + if (head->head.next == node) + return; + + dlist_delete(node); + dlist_push_head(head, node); + + dlist_check(head); +} + +/* + * Move element from its current position in the list to the tail position in + * the same list. + * + * Undefined behaviour if 'node' is not already part of the list. + */ +static inline void +dlist_move_tail(dlist_head *head, dlist_node *node) +{ + /* fast path if it's already at the tail */ + if (head->head.prev == node) + return; + + dlist_delete(node); + dlist_push_tail(head, node); + + dlist_check(head); +} + +/* + * Check whether 'node' has a following node. + * Caution: unreliable if 'node' is not in the list. + */ +static inline bool +dlist_has_next(dlist_head *head, dlist_node *node) +{ + return node->next != &head->head; +} + +/* + * Check whether 'node' has a preceding node. + * Caution: unreliable if 'node' is not in the list. + */ +static inline bool +dlist_has_prev(dlist_head *head, dlist_node *node) +{ + return node->prev != &head->head; +} + +/* + * Return the next node in the list (there must be one). + */ +static inline dlist_node * +dlist_next_node(dlist_head *head, dlist_node *node) +{ + Assert(dlist_has_next(head, node)); + return node->next; +} + +/* + * Return previous node in the list (there must be one). + */ +static inline dlist_node * +dlist_prev_node(dlist_head *head, dlist_node *node) +{ + Assert(dlist_has_prev(head, node)); + return node->prev; +} + +/* internal support function to get address of head element's struct */ +static inline void * +dlist_head_element_off(dlist_head *head, size_t off) +{ + Assert(!dlist_is_empty(head)); + return (char *) head->head.next - off; +} + +/* + * Return the first node in the list (there must be one). + */ +static inline dlist_node * +dlist_head_node(dlist_head *head) +{ + return (dlist_node *) dlist_head_element_off(head, 0); +} + +/* internal support function to get address of tail element's struct */ +static inline void * +dlist_tail_element_off(dlist_head *head, size_t off) +{ + Assert(!dlist_is_empty(head)); + return (char *) head->head.prev - off; +} + +/* + * Return the last node in the list (there must be one). + */ +static inline dlist_node * +dlist_tail_node(dlist_head *head) +{ + return (dlist_node *) dlist_tail_element_off(head, 0); +} + +/* + * Return the containing struct of 'type' where 'membername' is the dlist_node + * pointed at by 'ptr'. + * + * This is used to convert a dlist_node * back to its containing struct. + */ +#define dlist_container(type, membername, ptr) \ + (AssertVariableIsOfTypeMacro(ptr, dlist_node *), \ + AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \ + ((type *) ((char *) (ptr) - offsetof(type, membername)))) + +/* + * Return the address of the first element in the list. + * + * The list must not be empty. + */ +#define dlist_head_element(type, membername, lhead) \ + (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \ + (type *) dlist_head_element_off(lhead, offsetof(type, membername))) + +/* + * Return the address of the last element in the list. + * + * The list must not be empty. + */ +#define dlist_tail_element(type, membername, lhead) \ + (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \ + ((type *) dlist_tail_element_off(lhead, offsetof(type, membername)))) + +/* + * Iterate through the list pointed at by 'lhead' storing the state in 'iter'. + * + * Access the current element with iter.cur. + * + * It is *not* allowed to manipulate the list during iteration. + */ +#define dlist_foreach(iter, lhead) \ + for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \ + AssertVariableIsOfTypeMacro(lhead, dlist_head *), \ + (iter).end = &(lhead)->head, \ + (iter).cur = (iter).end->next ? (iter).end->next : (iter).end; \ + (iter).cur != (iter).end; \ + (iter).cur = (iter).cur->next) + +/* + * Iterate through the list pointed at by 'lhead' storing the state in 'iter'. + * + * Access the current element with iter.cur. + * + * Iterations using this are only allowed to change the list at the current + * point of iteration. It is fine to delete the current node, but it is *not* + * fine to insert or delete adjacent nodes. + */ +#define dlist_foreach_modify(iter, lhead) \ + for (AssertVariableIsOfTypeMacro(iter, dlist_mutable_iter), \ + AssertVariableIsOfTypeMacro(lhead, dlist_head *), \ + (iter).end = &(lhead)->head, \ + (iter).cur = (iter).end->next ? (iter).end->next : (iter).end, \ + (iter).next = (iter).cur->next; \ + (iter).cur != (iter).end; \ + (iter).cur = (iter).next, (iter).next = (iter).cur->next) + +/* + * Iterate through the list in reverse order. + * + * It is *not* allowed to manipulate the list during iteration. + */ +#define dlist_reverse_foreach(iter, lhead) \ + for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \ + AssertVariableIsOfTypeMacro(lhead, dlist_head *), \ + (iter).end = &(lhead)->head, \ + (iter).cur = (iter).end->prev ? (iter).end->prev : (iter).end; \ + (iter).cur != (iter).end; \ + (iter).cur = (iter).cur->prev) + + +/* singly linked list implementation */ + +/* + * Initialize a singly linked list. + * Previous state will be thrown away without any cleanup. + */ +static inline void +slist_init(slist_head *head) +{ + head->head.next = NULL; +} + +/* + * Is the list empty? + */ +static inline bool +slist_is_empty(slist_head *head) +{ + slist_check(head); + + return head->head.next == NULL; +} + +/* + * Insert a node at the beginning of the list. + */ +static inline void +slist_push_head(slist_head *head, slist_node *node) +{ + node->next = head->head.next; + head->head.next = node; + + slist_check(head); +} + +/* + * Insert a node after another *in the same list* + */ +static inline void +slist_insert_after(slist_node *after, slist_node *node) +{ + node->next = after->next; + after->next = node; +} + +/* + * Remove and return the first node from a list (there must be one). + */ +static inline slist_node * +slist_pop_head_node(slist_head *head) +{ + slist_node *node; + + Assert(!slist_is_empty(head)); + node = head->head.next; + head->head.next = node->next; + slist_check(head); + return node; +} + +/* + * Check whether 'node' has a following node. + */ +static inline bool +slist_has_next(slist_head *head, slist_node *node) +{ + slist_check(head); + + return node->next != NULL; +} + +/* + * Return the next node in the list (there must be one). + */ +static inline slist_node * +slist_next_node(slist_head *head, slist_node *node) +{ + Assert(slist_has_next(head, node)); + return node->next; +} + +/* internal support function to get address of head element's struct */ +static inline void * +slist_head_element_off(slist_head *head, size_t off) +{ + Assert(!slist_is_empty(head)); + return (char *) head->head.next - off; +} + +/* + * Return the first node in the list (there must be one). + */ +static inline slist_node * +slist_head_node(slist_head *head) +{ + return (slist_node *) slist_head_element_off(head, 0); +} + +/* + * Delete the list element the iterator currently points to. + * + * Caution: this modifies iter->cur, so don't use that again in the current + * loop iteration. + */ +static inline void +slist_delete_current(slist_mutable_iter *iter) +{ + /* + * Update previous element's forward link. If the iteration is at the + * first list element, iter->prev will point to the list header's "head" + * field, so we don't need a special case for that. + */ + iter->prev->next = iter->next; + + /* + * Reset cur to prev, so that prev will continue to point to the prior + * valid list element after slist_foreach_modify() advances to the next. + */ + iter->cur = iter->prev; +} + +/* + * Return the containing struct of 'type' where 'membername' is the slist_node + * pointed at by 'ptr'. + * + * This is used to convert a slist_node * back to its containing struct. + */ +#define slist_container(type, membername, ptr) \ + (AssertVariableIsOfTypeMacro(ptr, slist_node *), \ + AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \ + ((type *) ((char *) (ptr) - offsetof(type, membername)))) + +/* + * Return the address of the first element in the list. + * + * The list must not be empty. + */ +#define slist_head_element(type, membername, lhead) \ + (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \ + (type *) slist_head_element_off(lhead, offsetof(type, membername))) + +/* + * Iterate through the list pointed at by 'lhead' storing the state in 'iter'. + * + * Access the current element with iter.cur. + * + * It's allowed to modify the list while iterating, with the exception of + * deleting the iterator's current node; deletion of that node requires + * care if the iteration is to be continued afterward. (Doing so and also + * deleting or inserting adjacent list elements might misbehave; also, if + * the user frees the current node's storage, continuing the iteration is + * not safe.) + */ +#define slist_foreach(iter, lhead) \ + for (AssertVariableIsOfTypeMacro(iter, slist_iter), \ + AssertVariableIsOfTypeMacro(lhead, slist_head *), \ + (iter).cur = (lhead)->head.next; \ + (iter).cur != NULL; \ + (iter).cur = (iter).cur->next) + +/* + * Iterate through the list pointed at by 'lhead' storing the state in 'iter'. + * + * Access the current element with iter.cur. + * + * The only list modification allowed while iterating is to remove the current + * node via slist_delete_current() (*not* slist_delete()). Insertion or + * deletion of nodes adjacent to the current node would misbehave. + */ +#define slist_foreach_modify(iter, lhead) \ + for (AssertVariableIsOfTypeMacro(iter, slist_mutable_iter), \ + AssertVariableIsOfTypeMacro(lhead, slist_head *), \ + (iter).prev = &(lhead)->head, \ + (iter).cur = (iter).prev->next, \ + (iter).next = (iter).cur ? (iter).cur->next : NULL; \ + (iter).cur != NULL; \ + (iter).prev = (iter).cur, \ + (iter).cur = (iter).next, \ + (iter).next = (iter).next ? (iter).next->next : NULL) + +#endif /* ILIST_H */ diff --git a/src/include/lib/integerset.h b/src/include/lib/integerset.h new file mode 100644 index 0000000..081ae3c --- /dev/null +++ b/src/include/lib/integerset.h @@ -0,0 +1,24 @@ +/* + * integerset.h + * In-memory data structure to hold a large set of integers efficiently + * + * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + * src/include/lib/integerset.h + */ +#ifndef INTEGERSET_H +#define INTEGERSET_H + +typedef struct IntegerSet IntegerSet; + +extern IntegerSet *intset_create(void); +extern void intset_add_member(IntegerSet *intset, uint64 x); +extern bool intset_is_member(IntegerSet *intset, uint64 x); + +extern uint64 intset_num_entries(IntegerSet *intset); +extern uint64 intset_memory_usage(IntegerSet *intset); + +extern void intset_begin_iterate(IntegerSet *intset); +extern bool intset_iterate_next(IntegerSet *intset, uint64 *next); + +#endif /* INTEGERSET_H */ diff --git a/src/include/lib/knapsack.h b/src/include/lib/knapsack.h new file mode 100644 index 0000000..e86a0bc --- /dev/null +++ b/src/include/lib/knapsack.h @@ -0,0 +1,16 @@ +/* + * knapsack.h + * + * Copyright (c) 2017-2022, PostgreSQL Global Development Group + * + * src/include/lib/knapsack.h + */ +#ifndef KNAPSACK_H +#define KNAPSACK_H + +#include "nodes/bitmapset.h" + +extern Bitmapset *DiscreteKnapsack(int max_weight, int num_items, + int *item_weights, double *item_values); + +#endif /* KNAPSACK_H */ diff --git a/src/include/lib/pairingheap.h b/src/include/lib/pairingheap.h new file mode 100644 index 0000000..26b1cad --- /dev/null +++ b/src/include/lib/pairingheap.h @@ -0,0 +1,102 @@ +/* + * pairingheap.h + * + * A Pairing Heap implementation + * + * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + * src/include/lib/pairingheap.h + */ + +#ifndef PAIRINGHEAP_H +#define PAIRINGHEAP_H + +#include "lib/stringinfo.h" + +/* Enable if you need the pairingheap_dump() debug function */ +/* #define PAIRINGHEAP_DEBUG */ + +/* + * This represents an element stored in the heap. Embed this in a larger + * struct containing the actual data you're storing. + * + * A node can have multiple children, which form a double-linked list. + * first_child points to the node's first child, and the subsequent children + * can be found by following the next_sibling pointers. The last child has + * next_sibling == NULL. The prev_or_parent pointer points to the node's + * previous sibling, or if the node is its parent's first child, to the + * parent. + */ +typedef struct pairingheap_node +{ + struct pairingheap_node *first_child; + struct pairingheap_node *next_sibling; + struct pairingheap_node *prev_or_parent; +} pairingheap_node; + +/* + * Return the containing struct of 'type' where 'membername' is the + * pairingheap_node pointed at by 'ptr'. + * + * This is used to convert a pairingheap_node * back to its containing struct. + */ +#define pairingheap_container(type, membername, ptr) \ + (AssertVariableIsOfTypeMacro(ptr, pairingheap_node *), \ + AssertVariableIsOfTypeMacro(((type *) NULL)->membername, pairingheap_node), \ + ((type *) ((char *) (ptr) - offsetof(type, membername)))) + +/* + * Like pairingheap_container, but used when the pointer is 'const ptr' + */ +#define pairingheap_const_container(type, membername, ptr) \ + (AssertVariableIsOfTypeMacro(ptr, const pairingheap_node *), \ + AssertVariableIsOfTypeMacro(((type *) NULL)->membername, pairingheap_node), \ + ((const type *) ((const char *) (ptr) - offsetof(type, membername)))) + +/* + * For a max-heap, the comparator must return <0 iff a < b, 0 iff a == b, + * and >0 iff a > b. For a min-heap, the conditions are reversed. + */ +typedef int (*pairingheap_comparator) (const pairingheap_node *a, + const pairingheap_node *b, + void *arg); + +/* + * A pairing heap. + * + * You can use pairingheap_allocate() to create a new palloc'd heap, or embed + * this in a larger struct, set ph_compare and ph_arg directly and initialize + * ph_root to NULL. + */ +typedef struct pairingheap +{ + pairingheap_comparator ph_compare; /* comparison function */ + void *ph_arg; /* opaque argument to ph_compare */ + pairingheap_node *ph_root; /* current root of the heap */ +} pairingheap; + +extern pairingheap *pairingheap_allocate(pairingheap_comparator compare, + void *arg); +extern void pairingheap_free(pairingheap *heap); +extern void pairingheap_add(pairingheap *heap, pairingheap_node *node); +extern pairingheap_node *pairingheap_first(pairingheap *heap); +extern pairingheap_node *pairingheap_remove_first(pairingheap *heap); +extern void pairingheap_remove(pairingheap *heap, pairingheap_node *node); + +#ifdef PAIRINGHEAP_DEBUG +extern char *pairingheap_dump(pairingheap *heap, + void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque), + void *opaque); +#endif + +/* Resets the heap to be empty. */ +#define pairingheap_reset(h) ((h)->ph_root = NULL) + +/* Is the heap empty? */ +#define pairingheap_is_empty(h) ((h)->ph_root == NULL) + +/* Is there exactly one node in the heap? */ +#define pairingheap_is_singular(h) \ + ((h)->ph_root && (h)->ph_root->first_child == NULL) + +#endif /* PAIRINGHEAP_H */ diff --git a/src/include/lib/qunique.h b/src/include/lib/qunique.h new file mode 100644 index 0000000..982addf --- /dev/null +++ b/src/include/lib/qunique.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * qunique.h + * inline array unique functions + * Portions Copyright (c) 2019-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/lib/qunique.h + *------------------------------------------------------------------------- + */ + +#ifndef QUNIQUE_H +#define QUNIQUE_H + +/* + * Remove duplicates from a pre-sorted array, according to a user-supplied + * comparator. Usually the array should have been sorted with qsort() using + * the same arguments. Return the new size. + */ +static inline size_t +qunique(void *array, size_t elements, size_t width, + int (*compare) (const void *, const void *)) +{ + char *bytes = (char *) array; + size_t i, + j; + + if (elements <= 1) + return elements; + + for (i = 1, j = 0; i < elements; ++i) + { + if (compare(bytes + i * width, bytes + j * width) != 0 && + ++j != i) + memcpy(bytes + j * width, bytes + i * width, width); + } + + return j + 1; +} + +/* + * Like qunique(), but takes a comparator with an extra user data argument + * which is passed through, for compatibility with qsort_arg(). + */ +static inline size_t +qunique_arg(void *array, size_t elements, size_t width, + int (*compare) (const void *, const void *, void *), + void *arg) +{ + char *bytes = (char *) array; + size_t i, + j; + + if (elements <= 1) + return elements; + + for (i = 1, j = 0; i < elements; ++i) + { + if (compare(bytes + i * width, bytes + j * width, arg) != 0 && + ++j != i) + memcpy(bytes + j * width, bytes + i * width, width); + } + + return j + 1; +} + +#endif /* QUNIQUE_H */ diff --git a/src/include/lib/rbtree.h b/src/include/lib/rbtree.h new file mode 100644 index 0000000..580a3e3 --- /dev/null +++ b/src/include/lib/rbtree.h @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------- + * + * rbtree.h + * interface for PostgreSQL generic Red-Black binary tree package + * + * Copyright (c) 2009-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/lib/rbtree.h + * + *------------------------------------------------------------------------- + */ +#ifndef RBTREE_H +#define RBTREE_H + +/* + * RBTNode is intended to be used as the first field of a larger struct, + * whose additional fields carry whatever payload data the caller needs + * for a tree entry. (The total size of that larger struct is passed to + * rbt_create.) RBTNode is declared here to support this usage, but + * callers must treat it as an opaque struct. + */ +typedef struct RBTNode +{ + char color; /* node's current color, red or black */ + struct RBTNode *left; /* left child, or RBTNIL if none */ + struct RBTNode *right; /* right child, or RBTNIL if none */ + struct RBTNode *parent; /* parent, or NULL (not RBTNIL!) if none */ +} RBTNode; + +/* Opaque struct representing a whole tree */ +typedef struct RBTree RBTree; + +/* Available tree iteration orderings */ +typedef enum RBTOrderControl +{ + LeftRightWalk, /* inorder: left child, node, right child */ + RightLeftWalk /* reverse inorder: right, node, left */ +} RBTOrderControl; + +/* + * RBTreeIterator holds state while traversing a tree. This is declared + * here so that callers can stack-allocate this, but must otherwise be + * treated as an opaque struct. + */ +typedef struct RBTreeIterator RBTreeIterator; + +struct RBTreeIterator +{ + RBTree *rbt; + RBTNode *(*iterate) (RBTreeIterator *iter); + RBTNode *last_visited; + bool is_over; +}; + +/* Support functions to be provided by caller */ +typedef int (*rbt_comparator) (const RBTNode *a, const RBTNode *b, void *arg); +typedef void (*rbt_combiner) (RBTNode *existing, const RBTNode *newdata, void *arg); +typedef RBTNode *(*rbt_allocfunc) (void *arg); +typedef void (*rbt_freefunc) (RBTNode *x, void *arg); + +extern RBTree *rbt_create(Size node_size, + rbt_comparator comparator, + rbt_combiner combiner, + rbt_allocfunc allocfunc, + rbt_freefunc freefunc, + void *arg); + +extern RBTNode *rbt_find(RBTree *rbt, const RBTNode *data); +extern RBTNode *rbt_leftmost(RBTree *rbt); + +extern RBTNode *rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew); +extern void rbt_delete(RBTree *rbt, RBTNode *node); + +extern void rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, + RBTreeIterator *iter); +extern RBTNode *rbt_iterate(RBTreeIterator *iter); + +#endif /* RBTREE_H */ diff --git a/src/include/lib/simplehash.h b/src/include/lib/simplehash.h new file mode 100644 index 0000000..d95388d --- /dev/null +++ b/src/include/lib/simplehash.h @@ -0,0 +1,1184 @@ +/* + * simplehash.h + * + * When included this file generates a "templated" (by way of macros) + * open-addressing hash table implementation specialized to user-defined + * types. + * + * It's probably not worthwhile to generate such a specialized implementation + * for hash tables that aren't performance or space sensitive. + * + * Compared to dynahash, simplehash has the following benefits: + * + * - Due to the "templated" code generation has known structure sizes and no + * indirect function calls (which show up substantially in dynahash + * profiles). These features considerably increase speed for small + * entries. + * - Open addressing has better CPU cache behavior than dynahash's chained + * hashtables. + * - The generated interface is type-safe and easier to use than dynahash, + * though at the cost of more complex setup. + * - Allocates memory in a MemoryContext or another allocator with a + * malloc/free style interface (which isn't easily usable in a shared + * memory context) + * - Does not require the overhead of a separate memory context. + * + * Usage notes: + * + * To generate a hash-table and associated functions for a use case several + * macros have to be #define'ed before this file is included. Including + * the file #undef's all those, so a new hash table can be generated + * afterwards. + * The relevant parameters are: + * - SH_PREFIX - prefix for all symbol names generated. A prefix of 'foo' + * will result in hash table type 'foo_hash' and functions like + * 'foo_insert'/'foo_lookup' and so forth. + * - SH_ELEMENT_TYPE - type of the contained elements + * - SH_KEY_TYPE - type of the hashtable's key + * - SH_DECLARE - if defined function prototypes and type declarations are + * generated + * - SH_DEFINE - if defined function definitions are generated + * - SH_SCOPE - in which scope (e.g. extern, static inline) do function + * declarations reside + * - SH_RAW_ALLOCATOR - if defined, memory contexts are not used; instead, + * use this to allocate bytes. The allocator must zero the returned space. + * - SH_USE_NONDEFAULT_ALLOCATOR - if defined no element allocator functions + * are defined, so you can supply your own + * The following parameters are only relevant when SH_DEFINE is defined: + * - SH_KEY - name of the element in SH_ELEMENT_TYPE containing the hash key + * - SH_EQUAL(table, a, b) - compare two table keys + * - SH_HASH_KEY(table, key) - generate hash for the key + * - SH_STORE_HASH - if defined the hash is stored in the elements + * - SH_GET_HASH(tb, a) - return the field to store the hash in + * + * The element type is required to contain a "status" member that can store + * the range of values defined in the SH_STATUS enum. + * + * While SH_STORE_HASH (and subsequently SH_GET_HASH) are optional, because + * the hash table implementation needs to compare hashes to move elements + * (particularly when growing the hash), it's preferable, if possible, to + * store the element's hash in the element's data type. If the hash is so + * stored, the hash table will also compare hashes before calling SH_EQUAL + * when comparing two keys. + * + * For convenience the hash table create functions accept a void pointer + * that will be stored in the hash table type's member private_data. This + * allows callbacks to reference caller provided data. + * + * For examples of usage look at tidbitmap.c (file local definition) and + * execnodes.h/execGrouping.c (exposed declaration, file local + * implementation). + * + * Hash table design: + * + * The hash table design chosen is a variant of linear open-addressing. The + * reason for doing so is that linear addressing is CPU cache & pipeline + * friendly. The biggest disadvantage of simple linear addressing schemes + * are highly variable lookup times due to clustering, and deletions + * leaving a lot of tombstones around. To address these issues a variant + * of "robin hood" hashing is employed. Robin hood hashing optimizes + * chaining lengths by moving elements close to their optimal bucket + * ("rich" elements), out of the way if a to-be-inserted element is further + * away from its optimal position (i.e. it's "poor"). While that can make + * insertions slower, the average lookup performance is a lot better, and + * higher fill factors can be used in a still performant manner. To avoid + * tombstones - which normally solve the issue that a deleted node's + * presence is relevant to determine whether a lookup needs to continue + * looking or is done - buckets following a deleted element are shifted + * backwards, unless they're empty or already at their optimal position. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/lib/simplehash.h + */ + +#include "port/pg_bitutils.h" + +/* helpers */ +#define SH_MAKE_PREFIX(a) CppConcat(a,_) +#define SH_MAKE_NAME(name) SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX),name) +#define SH_MAKE_NAME_(a,b) CppConcat(a,b) + +/* name macros for: */ + +/* type declarations */ +#define SH_TYPE SH_MAKE_NAME(hash) +#define SH_STATUS SH_MAKE_NAME(status) +#define SH_STATUS_EMPTY SH_MAKE_NAME(SH_EMPTY) +#define SH_STATUS_IN_USE SH_MAKE_NAME(SH_IN_USE) +#define SH_ITERATOR SH_MAKE_NAME(iterator) + +/* function declarations */ +#define SH_CREATE SH_MAKE_NAME(create) +#define SH_DESTROY SH_MAKE_NAME(destroy) +#define SH_RESET SH_MAKE_NAME(reset) +#define SH_INSERT SH_MAKE_NAME(insert) +#define SH_INSERT_HASH SH_MAKE_NAME(insert_hash) +#define SH_DELETE_ITEM SH_MAKE_NAME(delete_item) +#define SH_DELETE SH_MAKE_NAME(delete) +#define SH_LOOKUP SH_MAKE_NAME(lookup) +#define SH_LOOKUP_HASH SH_MAKE_NAME(lookup_hash) +#define SH_GROW SH_MAKE_NAME(grow) +#define SH_START_ITERATE SH_MAKE_NAME(start_iterate) +#define SH_START_ITERATE_AT SH_MAKE_NAME(start_iterate_at) +#define SH_ITERATE SH_MAKE_NAME(iterate) +#define SH_ALLOCATE SH_MAKE_NAME(allocate) +#define SH_FREE SH_MAKE_NAME(free) +#define SH_STAT SH_MAKE_NAME(stat) + +/* internal helper functions (no externally visible prototypes) */ +#define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters) +#define SH_NEXT SH_MAKE_NAME(next) +#define SH_PREV SH_MAKE_NAME(prev) +#define SH_DISTANCE_FROM_OPTIMAL SH_MAKE_NAME(distance) +#define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket) +#define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash) +#define SH_INSERT_HASH_INTERNAL SH_MAKE_NAME(insert_hash_internal) +#define SH_LOOKUP_HASH_INTERNAL SH_MAKE_NAME(lookup_hash_internal) + +/* generate forward declarations necessary to use the hash table */ +#ifdef SH_DECLARE + +/* type definitions */ +typedef struct SH_TYPE +{ + /* + * Size of data / bucket array, 64 bits to handle UINT32_MAX sized hash + * tables. Note that the maximum number of elements is lower + * (SH_MAX_FILLFACTOR) + */ + uint64 size; + + /* how many elements have valid contents */ + uint32 members; + + /* mask for bucket and size calculations, based on size */ + uint32 sizemask; + + /* boundary after which to grow hashtable */ + uint32 grow_threshold; + + /* hash buckets */ + SH_ELEMENT_TYPE *data; + +#ifndef SH_RAW_ALLOCATOR + /* memory context to use for allocations */ + MemoryContext ctx; +#endif + + /* user defined data, useful for callbacks */ + void *private_data; +} SH_TYPE; + +typedef enum SH_STATUS +{ + SH_STATUS_EMPTY = 0x00, + SH_STATUS_IN_USE = 0x01 +} SH_STATUS; + +typedef struct SH_ITERATOR +{ + uint32 cur; /* current element */ + uint32 end; + bool done; /* iterator exhausted? */ +} SH_ITERATOR; + +/* externally visible function prototypes */ +#ifdef SH_RAW_ALLOCATOR +/* <prefix>_hash <prefix>_create(uint32 nelements, void *private_data) */ +SH_SCOPE SH_TYPE *SH_CREATE(uint32 nelements, void *private_data); +#else +/* + * <prefix>_hash <prefix>_create(MemoryContext ctx, uint32 nelements, + * void *private_data) + */ +SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements, + void *private_data); +#endif + +/* void <prefix>_destroy(<prefix>_hash *tb) */ +SH_SCOPE void SH_DESTROY(SH_TYPE * tb); + +/* void <prefix>_reset(<prefix>_hash *tb) */ +SH_SCOPE void SH_RESET(SH_TYPE * tb); + +/* void <prefix>_grow(<prefix>_hash *tb, uint64 newsize) */ +SH_SCOPE void SH_GROW(SH_TYPE * tb, uint64 newsize); + +/* <element> *<prefix>_insert(<prefix>_hash *tb, <key> key, bool *found) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found); + +/* + * <element> *<prefix>_insert_hash(<prefix>_hash *tb, <key> key, uint32 hash, + * bool *found) + */ +SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT_HASH(SH_TYPE * tb, SH_KEY_TYPE key, + uint32 hash, bool *found); + +/* <element> *<prefix>_lookup(<prefix>_hash *tb, <key> key) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key); + +/* <element> *<prefix>_lookup_hash(<prefix>_hash *tb, <key> key, uint32 hash) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key, + uint32 hash); + +/* void <prefix>_delete_item(<prefix>_hash *tb, <element> *entry) */ +SH_SCOPE void SH_DELETE_ITEM(SH_TYPE * tb, SH_ELEMENT_TYPE * entry); + +/* bool <prefix>_delete(<prefix>_hash *tb, <key> key) */ +SH_SCOPE bool SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key); + +/* void <prefix>_start_iterate(<prefix>_hash *tb, <prefix>_iterator *iter) */ +SH_SCOPE void SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter); + +/* + * void <prefix>_start_iterate_at(<prefix>_hash *tb, <prefix>_iterator *iter, + * uint32 at) + */ +SH_SCOPE void SH_START_ITERATE_AT(SH_TYPE * tb, SH_ITERATOR * iter, uint32 at); + +/* <element> *<prefix>_iterate(<prefix>_hash *tb, <prefix>_iterator *iter) */ +SH_SCOPE SH_ELEMENT_TYPE *SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter); + +/* void <prefix>_stat(<prefix>_hash *tb */ +SH_SCOPE void SH_STAT(SH_TYPE * tb); + +#endif /* SH_DECLARE */ + + +/* generate implementation of the hash table */ +#ifdef SH_DEFINE + +#ifndef SH_RAW_ALLOCATOR +#include "utils/memutils.h" +#endif + +/* max data array size,we allow up to PG_UINT32_MAX buckets, including 0 */ +#define SH_MAX_SIZE (((uint64) PG_UINT32_MAX) + 1) + +/* normal fillfactor, unless already close to maximum */ +#ifndef SH_FILLFACTOR +#define SH_FILLFACTOR (0.9) +#endif +/* increase fillfactor if we otherwise would error out */ +#define SH_MAX_FILLFACTOR (0.98) +/* grow if actual and optimal location bigger than */ +#ifndef SH_GROW_MAX_DIB +#define SH_GROW_MAX_DIB 25 +#endif +/* grow if more than elements to move when inserting */ +#ifndef SH_GROW_MAX_MOVE +#define SH_GROW_MAX_MOVE 150 +#endif +#ifndef SH_GROW_MIN_FILLFACTOR +/* but do not grow due to SH_GROW_MAX_* if below */ +#define SH_GROW_MIN_FILLFACTOR 0.1 +#endif + +#ifdef SH_STORE_HASH +#define SH_COMPARE_KEYS(tb, ahash, akey, b) (ahash == SH_GET_HASH(tb, b) && SH_EQUAL(tb, b->SH_KEY, akey)) +#else +#define SH_COMPARE_KEYS(tb, ahash, akey, b) (SH_EQUAL(tb, b->SH_KEY, akey)) +#endif + +/* + * Wrap the following definitions in include guards, to avoid multiple + * definition errors if this header is included more than once. The rest of + * the file deliberately has no include guards, because it can be included + * with different parameters to define functions and types with non-colliding + * names. + */ +#ifndef SIMPLEHASH_H +#define SIMPLEHASH_H + +#ifdef FRONTEND +#define sh_error(...) pg_fatal(__VA_ARGS__) +#define sh_log(...) pg_log_info(__VA_ARGS__) +#else +#define sh_error(...) elog(ERROR, __VA_ARGS__) +#define sh_log(...) elog(LOG, __VA_ARGS__) +#endif + +#endif + +/* + * Compute sizing parameters for hashtable. Called when creating and growing + * the hashtable. + */ +static inline void +SH_COMPUTE_PARAMETERS(SH_TYPE * tb, uint64 newsize) +{ + uint64 size; + + /* supporting zero sized hashes would complicate matters */ + size = Max(newsize, 2); + + /* round up size to the next power of 2, that's how bucketing works */ + size = pg_nextpower2_64(size); + Assert(size <= SH_MAX_SIZE); + + /* + * Verify that allocation of ->data is possible on this platform, without + * overflowing Size. + */ + if (unlikely((((uint64) sizeof(SH_ELEMENT_TYPE)) * size) >= SIZE_MAX / 2)) + sh_error("hash table too large"); + + /* now set size */ + tb->size = size; + tb->sizemask = (uint32) (size - 1); + + /* + * Compute the next threshold at which we need to grow the hash table + * again. + */ + if (tb->size == SH_MAX_SIZE) + tb->grow_threshold = ((double) tb->size) * SH_MAX_FILLFACTOR; + else + tb->grow_threshold = ((double) tb->size) * SH_FILLFACTOR; +} + +/* return the optimal bucket for the hash */ +static inline uint32 +SH_INITIAL_BUCKET(SH_TYPE * tb, uint32 hash) +{ + return hash & tb->sizemask; +} + +/* return next bucket after the current, handling wraparound */ +static inline uint32 +SH_NEXT(SH_TYPE * tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem + 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return bucket before the current, handling wraparound */ +static inline uint32 +SH_PREV(SH_TYPE * tb, uint32 curelem, uint32 startelem) +{ + curelem = (curelem - 1) & tb->sizemask; + + Assert(curelem != startelem); + + return curelem; +} + +/* return distance between bucket and its optimal position */ +static inline uint32 +SH_DISTANCE_FROM_OPTIMAL(SH_TYPE * tb, uint32 optimal, uint32 bucket) +{ + if (optimal <= bucket) + return bucket - optimal; + else + return (tb->size + bucket) - optimal; +} + +static inline uint32 +SH_ENTRY_HASH(SH_TYPE * tb, SH_ELEMENT_TYPE * entry) +{ +#ifdef SH_STORE_HASH + return SH_GET_HASH(tb, entry); +#else + return SH_HASH_KEY(tb, entry->SH_KEY); +#endif +} + +/* default memory allocator function */ +static inline void *SH_ALLOCATE(SH_TYPE * type, Size size); +static inline void SH_FREE(SH_TYPE * type, void *pointer); + +#ifndef SH_USE_NONDEFAULT_ALLOCATOR + +/* default memory allocator function */ +static inline void * +SH_ALLOCATE(SH_TYPE * type, Size size) +{ +#ifdef SH_RAW_ALLOCATOR + return SH_RAW_ALLOCATOR(size); +#else + return MemoryContextAllocExtended(type->ctx, size, + MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); +#endif +} + +/* default memory free function */ +static inline void +SH_FREE(SH_TYPE * type, void *pointer) +{ + pfree(pointer); +} + +#endif + +/* + * Create a hash table with enough space for `nelements` distinct members. + * Memory for the hash table is allocated from the passed-in context. If + * desired, the array of elements can be allocated using a passed-in allocator; + * this could be useful in order to place the array of elements in a shared + * memory, or in a context that will outlive the rest of the hash table. + * Memory other than for the array of elements will still be allocated from + * the passed-in context. + */ +#ifdef SH_RAW_ALLOCATOR +SH_SCOPE SH_TYPE * +SH_CREATE(uint32 nelements, void *private_data) +#else +SH_SCOPE SH_TYPE * +SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data) +#endif +{ + SH_TYPE *tb; + uint64 size; + +#ifdef SH_RAW_ALLOCATOR + tb = (SH_TYPE *) SH_RAW_ALLOCATOR(sizeof(SH_TYPE)); +#else + tb = (SH_TYPE *) MemoryContextAllocZero(ctx, sizeof(SH_TYPE)); + tb->ctx = ctx; +#endif + tb->private_data = private_data; + + /* increase nelements by fillfactor, want to store nelements elements */ + size = Min((double) SH_MAX_SIZE, ((double) nelements) / SH_FILLFACTOR); + + SH_COMPUTE_PARAMETERS(tb, size); + + tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size); + + return tb; +} + +/* destroy a previously created hash table */ +SH_SCOPE void +SH_DESTROY(SH_TYPE * tb) +{ + SH_FREE(tb, tb->data); + pfree(tb); +} + +/* reset the contents of a previously created hash table */ +SH_SCOPE void +SH_RESET(SH_TYPE * tb) +{ + memset(tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size); + tb->members = 0; +} + +/* + * Grow a hash table to at least `newsize` buckets. + * + * Usually this will automatically be called by insertions/deletions, when + * necessary. But resizing to the exact input size can be advantageous + * performance-wise, when known at some point. + */ +SH_SCOPE void +SH_GROW(SH_TYPE * tb, uint64 newsize) +{ + uint64 oldsize = tb->size; + SH_ELEMENT_TYPE *olddata = tb->data; + SH_ELEMENT_TYPE *newdata; + uint32 i; + uint32 startelem = 0; + uint32 copyelem; + + Assert(oldsize == pg_nextpower2_64(oldsize)); + Assert(oldsize != SH_MAX_SIZE); + Assert(oldsize < newsize); + + /* compute parameters for new table */ + SH_COMPUTE_PARAMETERS(tb, newsize); + + tb->data = (SH_ELEMENT_TYPE *) SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size); + + newdata = tb->data; + + /* + * Copy entries from the old data to newdata. We theoretically could use + * SH_INSERT here, to avoid code duplication, but that's more general than + * we need. We neither want tb->members increased, nor do we need to do + * deal with deleted elements, nor do we need to compare keys. So a + * special-cased implementation is lot faster. As resizing can be time + * consuming and frequent, that's worthwhile to optimize. + * + * To be able to simply move entries over, we have to start not at the + * first bucket (i.e olddata[0]), but find the first bucket that's either + * empty, or is occupied by an entry at its optimal position. Such a + * bucket has to exist in any table with a load factor under 1, as not all + * buckets are occupied, i.e. there always has to be an empty bucket. By + * starting at such a bucket we can move the entries to the larger table, + * without having to deal with conflicts. + */ + + /* search for the first element in the hash that's not wrapped around */ + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[i]; + uint32 hash; + uint32 optimal; + + if (oldentry->status != SH_STATUS_IN_USE) + { + startelem = i; + break; + } + + hash = SH_ENTRY_HASH(tb, oldentry); + optimal = SH_INITIAL_BUCKET(tb, hash); + + if (optimal == i) + { + startelem = i; + break; + } + } + + /* and copy all elements in the old table */ + copyelem = startelem; + for (i = 0; i < oldsize; i++) + { + SH_ELEMENT_TYPE *oldentry = &olddata[copyelem]; + + if (oldentry->status == SH_STATUS_IN_USE) + { + uint32 hash; + uint32 startelem; + uint32 curelem; + SH_ELEMENT_TYPE *newentry; + + hash = SH_ENTRY_HASH(tb, oldentry); + startelem = SH_INITIAL_BUCKET(tb, hash); + curelem = startelem; + + /* find empty element to put data into */ + while (true) + { + newentry = &newdata[curelem]; + + if (newentry->status == SH_STATUS_EMPTY) + { + break; + } + + curelem = SH_NEXT(tb, curelem, startelem); + } + + /* copy entry to new slot */ + memcpy(newentry, oldentry, sizeof(SH_ELEMENT_TYPE)); + } + + /* can't use SH_NEXT here, would use new size */ + copyelem++; + if (copyelem >= oldsize) + { + copyelem = 0; + } + } + + SH_FREE(tb, olddata); +} + +/* + * This is a separate static inline function, so it can be reliably be inlined + * into its wrapper functions even if SH_SCOPE is extern. + */ +static inline SH_ELEMENT_TYPE * +SH_INSERT_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found) +{ + uint32 startelem; + uint32 curelem; + SH_ELEMENT_TYPE *data; + uint32 insertdist; + +restart: + insertdist = 0; + + /* + * We do the grow check even if the key is actually present, to avoid + * doing the check inside the loop. This also lets us avoid having to + * re-find our position in the hashtable after resizing. + * + * Note that this also reached when resizing the table due to + * SH_GROW_MAX_DIB / SH_GROW_MAX_MOVE. + */ + if (unlikely(tb->members >= tb->grow_threshold)) + { + if (unlikely(tb->size == SH_MAX_SIZE)) + sh_error("hash table size exceeded"); + + /* + * When optimizing, it can be very useful to print these out. + */ + /* SH_STAT(tb); */ + SH_GROW(tb, tb->size * 2); + /* SH_STAT(tb); */ + } + + /* perform insert, start bucket search at optimal location */ + data = tb->data; + startelem = SH_INITIAL_BUCKET(tb, hash); + curelem = startelem; + while (true) + { + uint32 curdist; + uint32 curhash; + uint32 curoptimal; + SH_ELEMENT_TYPE *entry = &data[curelem]; + + /* any empty bucket can directly be used */ + if (entry->status == SH_STATUS_EMPTY) + { + tb->members++; + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + entry->status = SH_STATUS_IN_USE; + *found = false; + return entry; + } + + /* + * If the bucket is not empty, we either found a match (in which case + * we're done), or we have to decide whether to skip over or move the + * colliding entry. When the colliding element's distance to its + * optimal position is smaller than the to-be-inserted entry's, we + * shift the colliding entry (and its followers) forward by one. + */ + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + { + Assert(entry->status == SH_STATUS_IN_USE); + *found = true; + return entry; + } + + curhash = SH_ENTRY_HASH(tb, entry); + curoptimal = SH_INITIAL_BUCKET(tb, curhash); + curdist = SH_DISTANCE_FROM_OPTIMAL(tb, curoptimal, curelem); + + if (insertdist > curdist) + { + SH_ELEMENT_TYPE *lastentry = entry; + uint32 emptyelem = curelem; + uint32 moveelem; + int32 emptydist = 0; + + /* find next empty bucket */ + while (true) + { + SH_ELEMENT_TYPE *emptyentry; + + emptyelem = SH_NEXT(tb, emptyelem, startelem); + emptyentry = &data[emptyelem]; + + if (emptyentry->status == SH_STATUS_EMPTY) + { + lastentry = emptyentry; + break; + } + + /* + * To avoid negative consequences from overly imbalanced + * hashtables, grow the hashtable if collisions would require + * us to move a lot of entries. The most likely cause of such + * imbalance is filling a (currently) small table, from a + * currently big one, in hash-table order. Don't grow if the + * hashtable would be too empty, to prevent quick space + * explosion for some weird edge cases. + */ + if (unlikely(++emptydist > SH_GROW_MAX_MOVE) && + ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR) + { + tb->grow_threshold = 0; + goto restart; + } + } + + /* shift forward, starting at last occupied element */ + + /* + * TODO: This could be optimized to be one memcpy in many cases, + * excepting wrapping around at the end of ->data. Hasn't shown up + * in profiles so far though. + */ + moveelem = emptyelem; + while (moveelem != curelem) + { + SH_ELEMENT_TYPE *moveentry; + + moveelem = SH_PREV(tb, moveelem, startelem); + moveentry = &data[moveelem]; + + memcpy(lastentry, moveentry, sizeof(SH_ELEMENT_TYPE)); + lastentry = moveentry; + } + + /* and fill the now empty spot */ + tb->members++; + + entry->SH_KEY = key; +#ifdef SH_STORE_HASH + SH_GET_HASH(tb, entry) = hash; +#endif + entry->status = SH_STATUS_IN_USE; + *found = false; + return entry; + } + + curelem = SH_NEXT(tb, curelem, startelem); + insertdist++; + + /* + * To avoid negative consequences from overly imbalanced hashtables, + * grow the hashtable if collisions lead to large runs. The most + * likely cause of such imbalance is filling a (currently) small + * table, from a currently big one, in hash-table order. Don't grow + * if the hashtable would be too empty, to prevent quick space + * explosion for some weird edge cases. + */ + if (unlikely(insertdist > SH_GROW_MAX_DIB) && + ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR) + { + tb->grow_threshold = 0; + goto restart; + } + } +} + +/* + * Insert the key key into the hash-table, set *found to true if the key + * already exists, false otherwise. Returns the hash-table entry in either + * case. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found) +{ + uint32 hash = SH_HASH_KEY(tb, key); + + return SH_INSERT_HASH_INTERNAL(tb, key, hash, found); +} + +/* + * Insert the key key into the hash-table using an already-calculated + * hash. Set *found to true if the key already exists, false + * otherwise. Returns the hash-table entry in either case. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_INSERT_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found) +{ + return SH_INSERT_HASH_INTERNAL(tb, key, hash, found); +} + +/* + * This is a separate static inline function, so it can be reliably be inlined + * into its wrapper functions even if SH_SCOPE is extern. + */ +static inline SH_ELEMENT_TYPE * +SH_LOOKUP_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash) +{ + const uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + + while (true) + { + SH_ELEMENT_TYPE *entry = &tb->data[curelem]; + + if (entry->status == SH_STATUS_EMPTY) + { + return NULL; + } + + Assert(entry->status == SH_STATUS_IN_USE); + + if (SH_COMPARE_KEYS(tb, hash, key, entry)) + return entry; + + /* + * TODO: we could stop search based on distance. If the current + * buckets's distance-from-optimal is smaller than what we've skipped + * already, the entry doesn't exist. Probably only do so if + * SH_STORE_HASH is defined, to avoid re-computing hashes? + */ + + curelem = SH_NEXT(tb, curelem, startelem); + } +} + +/* + * Lookup up entry in hash table. Returns NULL if key not present. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key) +{ + uint32 hash = SH_HASH_KEY(tb, key); + + return SH_LOOKUP_HASH_INTERNAL(tb, key, hash); +} + +/* + * Lookup up entry in hash table using an already-calculated hash. + * + * Returns NULL if key not present. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash) +{ + return SH_LOOKUP_HASH_INTERNAL(tb, key, hash); +} + +/* + * Delete entry from hash table by key. Returns whether to-be-deleted key was + * present. + */ +SH_SCOPE bool +SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key) +{ + uint32 hash = SH_HASH_KEY(tb, key); + uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem = startelem; + + while (true) + { + SH_ELEMENT_TYPE *entry = &tb->data[curelem]; + + if (entry->status == SH_STATUS_EMPTY) + return false; + + if (entry->status == SH_STATUS_IN_USE && + SH_COMPARE_KEYS(tb, hash, key, entry)) + { + SH_ELEMENT_TYPE *lastentry = entry; + + tb->members--; + + /* + * Backward shift following elements till either an empty element + * or an element at its optimal position is encountered. + * + * While that sounds expensive, the average chain length is short, + * and deletions would otherwise require tombstones. + */ + while (true) + { + SH_ELEMENT_TYPE *curentry; + uint32 curhash; + uint32 curoptimal; + + curelem = SH_NEXT(tb, curelem, startelem); + curentry = &tb->data[curelem]; + + if (curentry->status != SH_STATUS_IN_USE) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + curhash = SH_ENTRY_HASH(tb, curentry); + curoptimal = SH_INITIAL_BUCKET(tb, curhash); + + /* current is at optimal position, done */ + if (curoptimal == curelem) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + /* shift */ + memcpy(lastentry, curentry, sizeof(SH_ELEMENT_TYPE)); + + lastentry = curentry; + } + + return true; + } + + /* TODO: return false; if distance too big */ + + curelem = SH_NEXT(tb, curelem, startelem); + } +} + +/* + * Delete entry from hash table by entry pointer + */ +SH_SCOPE void +SH_DELETE_ITEM(SH_TYPE * tb, SH_ELEMENT_TYPE * entry) +{ + SH_ELEMENT_TYPE *lastentry = entry; + uint32 hash = SH_ENTRY_HASH(tb, entry); + uint32 startelem = SH_INITIAL_BUCKET(tb, hash); + uint32 curelem; + + /* Calculate the index of 'entry' */ + curelem = entry - &tb->data[0]; + + tb->members--; + + /* + * Backward shift following elements till either an empty element or an + * element at its optimal position is encountered. + * + * While that sounds expensive, the average chain length is short, and + * deletions would otherwise require tombstones. + */ + while (true) + { + SH_ELEMENT_TYPE *curentry; + uint32 curhash; + uint32 curoptimal; + + curelem = SH_NEXT(tb, curelem, startelem); + curentry = &tb->data[curelem]; + + if (curentry->status != SH_STATUS_IN_USE) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + curhash = SH_ENTRY_HASH(tb, curentry); + curoptimal = SH_INITIAL_BUCKET(tb, curhash); + + /* current is at optimal position, done */ + if (curoptimal == curelem) + { + lastentry->status = SH_STATUS_EMPTY; + break; + } + + /* shift */ + memcpy(lastentry, curentry, sizeof(SH_ELEMENT_TYPE)); + + lastentry = curentry; + } +} + +/* + * Initialize iterator. + */ +SH_SCOPE void +SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter) +{ + uint64 startelem = PG_UINT64_MAX; + + /* + * Search for the first empty element. As deletions during iterations are + * supported, we want to start/end at an element that cannot be affected + * by elements being shifted. + */ + for (uint32 i = 0; i < tb->size; i++) + { + SH_ELEMENT_TYPE *entry = &tb->data[i]; + + if (entry->status != SH_STATUS_IN_USE) + { + startelem = i; + break; + } + } + + /* we should have found an empty element */ + Assert(startelem < SH_MAX_SIZE); + + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts + */ + iter->cur = startelem; + iter->end = iter->cur; + iter->done = false; +} + +/* + * Initialize iterator to a specific bucket. That's really only useful for + * cases where callers are partially iterating over the hashspace, and that + * iteration deletes and inserts elements based on visited entries. Doing that + * repeatedly could lead to an unbalanced keyspace when always starting at the + * same position. + */ +SH_SCOPE void +SH_START_ITERATE_AT(SH_TYPE * tb, SH_ITERATOR * iter, uint32 at) +{ + /* + * Iterate backwards, that allows the current element to be deleted, even + * if there are backward shifts. + */ + iter->cur = at & tb->sizemask; /* ensure at is within a valid range */ + iter->end = iter->cur; + iter->done = false; +} + +/* + * Iterate over all entries in the hash-table. Return the next occupied entry, + * or NULL if done. + * + * During iteration the current entry in the hash table may be deleted, + * without leading to elements being skipped or returned twice. Additionally + * the rest of the table may be modified (i.e. there can be insertions or + * deletions), but if so, there's neither a guarantee that all nodes are + * visited at least once, nor a guarantee that a node is visited at most once. + */ +SH_SCOPE SH_ELEMENT_TYPE * +SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter) +{ + while (!iter->done) + { + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[iter->cur]; + + /* next element in backward direction */ + iter->cur = (iter->cur - 1) & tb->sizemask; + + if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask)) + iter->done = true; + if (elem->status == SH_STATUS_IN_USE) + { + return elem; + } + } + + return NULL; +} + +/* + * Report some statistics about the state of the hashtable. For + * debugging/profiling purposes only. + */ +SH_SCOPE void +SH_STAT(SH_TYPE * tb) +{ + uint32 max_chain_length = 0; + uint32 total_chain_length = 0; + double avg_chain_length; + double fillfactor; + uint32 i; + + uint32 *collisions = (uint32 *) palloc0(tb->size * sizeof(uint32)); + uint32 total_collisions = 0; + uint32 max_collisions = 0; + double avg_collisions; + + for (i = 0; i < tb->size; i++) + { + uint32 hash; + uint32 optimal; + uint32 dist; + SH_ELEMENT_TYPE *elem; + + elem = &tb->data[i]; + + if (elem->status != SH_STATUS_IN_USE) + continue; + + hash = SH_ENTRY_HASH(tb, elem); + optimal = SH_INITIAL_BUCKET(tb, hash); + dist = SH_DISTANCE_FROM_OPTIMAL(tb, optimal, i); + + if (dist > max_chain_length) + max_chain_length = dist; + total_chain_length += dist; + + collisions[optimal]++; + } + + for (i = 0; i < tb->size; i++) + { + uint32 curcoll = collisions[i]; + + if (curcoll == 0) + continue; + + /* single contained element is not a collision */ + curcoll--; + total_collisions += curcoll; + if (curcoll > max_collisions) + max_collisions = curcoll; + } + + if (tb->members > 0) + { + fillfactor = tb->members / ((double) tb->size); + avg_chain_length = ((double) total_chain_length) / tb->members; + avg_collisions = ((double) total_collisions) / tb->members; + } + else + { + fillfactor = 0; + avg_chain_length = 0; + avg_collisions = 0; + } + + sh_log("size: " UINT64_FORMAT ", members: %u, filled: %f, total chain: %u, max chain: %u, avg chain: %f, total_collisions: %u, max_collisions: %u, avg_collisions: %f", + tb->size, tb->members, fillfactor, total_chain_length, max_chain_length, avg_chain_length, + total_collisions, max_collisions, avg_collisions); +} + +#endif /* SH_DEFINE */ + + +/* undefine external parameters, so next hash table can be defined */ +#undef SH_PREFIX +#undef SH_KEY_TYPE +#undef SH_KEY +#undef SH_ELEMENT_TYPE +#undef SH_HASH_KEY +#undef SH_SCOPE +#undef SH_DECLARE +#undef SH_DEFINE +#undef SH_GET_HASH +#undef SH_STORE_HASH +#undef SH_USE_NONDEFAULT_ALLOCATOR +#undef SH_EQUAL + +/* undefine locally declared macros */ +#undef SH_MAKE_PREFIX +#undef SH_MAKE_NAME +#undef SH_MAKE_NAME_ +#undef SH_FILLFACTOR +#undef SH_MAX_FILLFACTOR +#undef SH_GROW_MAX_DIB +#undef SH_GROW_MAX_MOVE +#undef SH_GROW_MIN_FILLFACTOR +#undef SH_MAX_SIZE + +/* types */ +#undef SH_TYPE +#undef SH_STATUS +#undef SH_STATUS_EMPTY +#undef SH_STATUS_IN_USE +#undef SH_ITERATOR + +/* external function names */ +#undef SH_CREATE +#undef SH_DESTROY +#undef SH_RESET +#undef SH_INSERT +#undef SH_INSERT_HASH +#undef SH_DELETE_ITEM +#undef SH_DELETE +#undef SH_LOOKUP +#undef SH_LOOKUP_HASH +#undef SH_GROW +#undef SH_START_ITERATE +#undef SH_START_ITERATE_AT +#undef SH_ITERATE +#undef SH_ALLOCATE +#undef SH_FREE +#undef SH_STAT + +/* internal function names */ +#undef SH_COMPUTE_PARAMETERS +#undef SH_COMPARE_KEYS +#undef SH_INITIAL_BUCKET +#undef SH_NEXT +#undef SH_PREV +#undef SH_DISTANCE_FROM_OPTIMAL +#undef SH_ENTRY_HASH +#undef SH_INSERT_HASH_INTERNAL +#undef SH_LOOKUP_HASH_INTERNAL diff --git a/src/include/lib/sort_template.h b/src/include/lib/sort_template.h new file mode 100644 index 0000000..3122a93 --- /dev/null +++ b/src/include/lib/sort_template.h @@ -0,0 +1,432 @@ +/*------------------------------------------------------------------------- + * + * sort_template.h + * + * A template for a sort algorithm that supports varying degrees of + * specialization. + * + * Copyright (c) 2021-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1992-1994, Regents of the University of California + * + * Usage notes: + * + * To generate functions specialized for a type, the following parameter + * macros should be #define'd before this file is included. + * + * - ST_SORT - the name of a sort function to be generated + * - ST_ELEMENT_TYPE - type of the referenced elements + * - ST_DECLARE - if defined the functions and types are declared + * - ST_DEFINE - if defined the functions and types are defined + * - ST_SCOPE - scope (e.g. extern, static inline) for functions + * - ST_CHECK_FOR_INTERRUPTS - if defined the sort is interruptible + * + * Instead of ST_ELEMENT_TYPE, ST_ELEMENT_TYPE_VOID can be defined. Then + * the generated functions will automatically gain an "element_size" + * parameter. This allows us to generate a traditional qsort function. + * + * One of the following macros must be defined, to show how to compare + * elements. The first two options are arbitrary expressions depending + * on whether an extra pass-through argument is desired, and the third + * option should be defined if the sort function should receive a + * function pointer at runtime. + * + * - ST_COMPARE(a, b) - a simple comparison expression + * - ST_COMPARE(a, b, arg) - variant that takes an extra argument + * - ST_COMPARE_RUNTIME_POINTER - sort function takes a function pointer + * + * To say that the comparator and therefore also sort function should + * receive an extra pass-through argument, specify the type of the + * argument. + * + * - ST_COMPARE_ARG_TYPE - type of extra argument + * + * The prototype of the generated sort function is: + * + * void ST_SORT(ST_ELEMENT_TYPE *data, size_t n, + * [size_t element_size,] + * [ST_SORT_compare_function compare,] + * [ST_COMPARE_ARG_TYPE *arg]); + * + * ST_SORT_compare_function is a function pointer of the following type: + * + * int (*)(const ST_ELEMENT_TYPE *a, const ST_ELEMENT_TYPE *b, + * [ST_COMPARE_ARG_TYPE *arg]) + * + * HISTORY + * + * Modifications from vanilla NetBSD source: + * - Add do ... while() macro fix + * - Remove __inline, _DIAGASSERTs, __P + * - Remove ill-considered "swap_cnt" switch to insertion sort, in favor + * of a simple check for presorted input. + * - Take care to recurse on the smaller partition, to bound stack usage + * - Convert into a header that can generate specialized functions + * + * IDENTIFICATION + * src/include/lib/sort_template.h + * + *------------------------------------------------------------------------- + */ + +/* $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Qsort routine based on J. L. Bentley and M. D. McIlroy, + * "Engineering a sort function", + * Software--Practice and Experience 23 (1993) 1249-1265. + * + * We have modified their original by adding a check for already-sorted + * input, which seems to be a win per discussions on pgsql-hackers around + * 2006-03-21. + * + * Also, we recurse on the smaller partition and iterate on the larger one, + * which ensures we cannot recurse more than log(N) levels (since the + * partition recursed to is surely no more than half of the input). Bentley + * and McIlroy explicitly rejected doing this on the grounds that it's "not + * worth the effort", but we have seen crashes in the field due to stack + * overrun, so that judgment seems wrong. + */ + +#define ST_MAKE_PREFIX(a) CppConcat(a,_) +#define ST_MAKE_NAME(a,b) ST_MAKE_NAME_(ST_MAKE_PREFIX(a),b) +#define ST_MAKE_NAME_(a,b) CppConcat(a,b) + +/* + * If the element type is void, we'll also need an element_size argument + * because we don't know the size. + */ +#ifdef ST_ELEMENT_TYPE_VOID +#define ST_ELEMENT_TYPE void +#define ST_SORT_PROTO_ELEMENT_SIZE , size_t element_size +#define ST_SORT_INVOKE_ELEMENT_SIZE , element_size +#else +#define ST_SORT_PROTO_ELEMENT_SIZE +#define ST_SORT_INVOKE_ELEMENT_SIZE +#endif + +/* + * If the user wants to be able to pass in compare functions at runtime, + * we'll need to make that an argument of the sort and med3 functions. + */ +#ifdef ST_COMPARE_RUNTIME_POINTER +/* + * The type of the comparator function pointer that ST_SORT will take, unless + * you've already declared a type name manually and want to use that instead of + * having a new one defined. + */ +#ifndef ST_COMPARATOR_TYPE_NAME +#define ST_COMPARATOR_TYPE_NAME ST_MAKE_NAME(ST_SORT, compare_function) +#endif +#define ST_COMPARE compare +#ifndef ST_COMPARE_ARG_TYPE +#define ST_SORT_PROTO_COMPARE , ST_COMPARATOR_TYPE_NAME compare +#define ST_SORT_INVOKE_COMPARE , compare +#else +#define ST_SORT_PROTO_COMPARE , ST_COMPARATOR_TYPE_NAME compare +#define ST_SORT_INVOKE_COMPARE , compare +#endif +#else +#define ST_SORT_PROTO_COMPARE +#define ST_SORT_INVOKE_COMPARE +#endif + +/* + * If the user wants to use a compare function or expression that takes an + * extra argument, we'll need to make that an argument of the sort, compare and + * med3 functions. + */ +#ifdef ST_COMPARE_ARG_TYPE +#define ST_SORT_PROTO_ARG , ST_COMPARE_ARG_TYPE *arg +#define ST_SORT_INVOKE_ARG , arg +#else +#define ST_SORT_PROTO_ARG +#define ST_SORT_INVOKE_ARG +#endif + +#ifdef ST_DECLARE + +#ifdef ST_COMPARE_RUNTIME_POINTER +typedef int (*ST_COMPARATOR_TYPE_NAME) (const ST_ELEMENT_TYPE *, + const ST_ELEMENT_TYPE * ST_SORT_PROTO_ARG); +#endif + +/* Declare the sort function. Note optional arguments at end. */ +ST_SCOPE void ST_SORT(ST_ELEMENT_TYPE * first, size_t n + ST_SORT_PROTO_ELEMENT_SIZE + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG); + +#endif + +#ifdef ST_DEFINE + +/* sort private helper functions */ +#define ST_MED3 ST_MAKE_NAME(ST_SORT, med3) +#define ST_SWAP ST_MAKE_NAME(ST_SORT, swap) +#define ST_SWAPN ST_MAKE_NAME(ST_SORT, swapn) + +/* Users expecting to run very large sorts may need them to be interruptible. */ +#ifdef ST_CHECK_FOR_INTERRUPTS +#define DO_CHECK_FOR_INTERRUPTS() CHECK_FOR_INTERRUPTS() +#else +#define DO_CHECK_FOR_INTERRUPTS() +#endif + +/* + * Create wrapper macros that know how to invoke compare, med3 and sort with + * the right arguments. + */ +#ifdef ST_COMPARE_RUNTIME_POINTER +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_) ST_SORT_INVOKE_ARG) +#elif defined(ST_COMPARE_ARG_TYPE) +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_), arg) +#else +#define DO_COMPARE(a_, b_) ST_COMPARE((a_), (b_)) +#endif +#define DO_MED3(a_, b_, c_) \ + ST_MED3((a_), (b_), (c_) \ + ST_SORT_INVOKE_COMPARE \ + ST_SORT_INVOKE_ARG) +#define DO_SORT(a_, n_) \ + ST_SORT((a_), (n_) \ + ST_SORT_INVOKE_ELEMENT_SIZE \ + ST_SORT_INVOKE_COMPARE \ + ST_SORT_INVOKE_ARG) + +/* + * If we're working with void pointers, we'll use pointer arithmetic based on + * uint8, and use the runtime element_size to step through the array and swap + * elements. Otherwise we'll work with ST_ELEMENT_TYPE. + */ +#ifndef ST_ELEMENT_TYPE_VOID +#define ST_POINTER_TYPE ST_ELEMENT_TYPE +#define ST_POINTER_STEP 1 +#define DO_SWAPN(a_, b_, n_) ST_SWAPN((a_), (b_), (n_)) +#define DO_SWAP(a_, b_) ST_SWAP((a_), (b_)) +#else +#define ST_POINTER_TYPE uint8 +#define ST_POINTER_STEP element_size +#define DO_SWAPN(a_, b_, n_) ST_SWAPN((a_), (b_), (n_)) +#define DO_SWAP(a_, b_) DO_SWAPN((a_), (b_), element_size) +#endif + +/* + * Find the median of three values. Currently, performance seems to be best + * if the comparator is inlined here, but the med3 function is not inlined + * in the qsort function. + */ +static pg_noinline ST_ELEMENT_TYPE * +ST_MED3(ST_ELEMENT_TYPE * a, + ST_ELEMENT_TYPE * b, + ST_ELEMENT_TYPE * c + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG) +{ + return DO_COMPARE(a, b) < 0 ? + (DO_COMPARE(b, c) < 0 ? b : (DO_COMPARE(a, c) < 0 ? c : a)) + : (DO_COMPARE(b, c) > 0 ? b : (DO_COMPARE(a, c) < 0 ? a : c)); +} + +static inline void +ST_SWAP(ST_POINTER_TYPE * a, ST_POINTER_TYPE * b) +{ + ST_POINTER_TYPE tmp = *a; + + *a = *b; + *b = tmp; +} + +static inline void +ST_SWAPN(ST_POINTER_TYPE * a, ST_POINTER_TYPE * b, size_t n) +{ + for (size_t i = 0; i < n; ++i) + ST_SWAP(&a[i], &b[i]); +} + +/* + * Sort an array. + */ +ST_SCOPE void +ST_SORT(ST_ELEMENT_TYPE * data, size_t n + ST_SORT_PROTO_ELEMENT_SIZE + ST_SORT_PROTO_COMPARE + ST_SORT_PROTO_ARG) +{ + ST_POINTER_TYPE *a = (ST_POINTER_TYPE *) data, + *pa, + *pb, + *pc, + *pd, + *pl, + *pm, + *pn; + size_t d1, + d2; + int r, + presorted; + +loop: + DO_CHECK_FOR_INTERRUPTS(); + if (n < 7) + { + for (pm = a + ST_POINTER_STEP; pm < a + n * ST_POINTER_STEP; + pm += ST_POINTER_STEP) + for (pl = pm; pl > a && DO_COMPARE(pl - ST_POINTER_STEP, pl) > 0; + pl -= ST_POINTER_STEP) + DO_SWAP(pl, pl - ST_POINTER_STEP); + return; + } + presorted = 1; + for (pm = a + ST_POINTER_STEP; pm < a + n * ST_POINTER_STEP; + pm += ST_POINTER_STEP) + { + DO_CHECK_FOR_INTERRUPTS(); + if (DO_COMPARE(pm - ST_POINTER_STEP, pm) > 0) + { + presorted = 0; + break; + } + } + if (presorted) + return; + pm = a + (n / 2) * ST_POINTER_STEP; + if (n > 7) + { + pl = a; + pn = a + (n - 1) * ST_POINTER_STEP; + if (n > 40) + { + size_t d = (n / 8) * ST_POINTER_STEP; + + pl = DO_MED3(pl, pl + d, pl + 2 * d); + pm = DO_MED3(pm - d, pm, pm + d); + pn = DO_MED3(pn - 2 * d, pn - d, pn); + } + pm = DO_MED3(pl, pm, pn); + } + DO_SWAP(a, pm); + pa = pb = a + ST_POINTER_STEP; + pc = pd = a + (n - 1) * ST_POINTER_STEP; + for (;;) + { + while (pb <= pc && (r = DO_COMPARE(pb, a)) <= 0) + { + if (r == 0) + { + DO_SWAP(pa, pb); + pa += ST_POINTER_STEP; + } + pb += ST_POINTER_STEP; + DO_CHECK_FOR_INTERRUPTS(); + } + while (pb <= pc && (r = DO_COMPARE(pc, a)) >= 0) + { + if (r == 0) + { + DO_SWAP(pc, pd); + pd -= ST_POINTER_STEP; + } + pc -= ST_POINTER_STEP; + DO_CHECK_FOR_INTERRUPTS(); + } + if (pb > pc) + break; + DO_SWAP(pb, pc); + pb += ST_POINTER_STEP; + pc -= ST_POINTER_STEP; + } + pn = a + n * ST_POINTER_STEP; + d1 = Min(pa - a, pb - pa); + DO_SWAPN(a, pb - d1, d1); + d1 = Min(pd - pc, pn - pd - ST_POINTER_STEP); + DO_SWAPN(pb, pn - d1, d1); + d1 = pb - pa; + d2 = pd - pc; + if (d1 <= d2) + { + /* Recurse on left partition, then iterate on right partition */ + if (d1 > ST_POINTER_STEP) + DO_SORT(a, d1 / ST_POINTER_STEP); + if (d2 > ST_POINTER_STEP) + { + /* Iterate rather than recurse to save stack space */ + /* DO_SORT(pn - d2, d2 / ST_POINTER_STEP) */ + a = pn - d2; + n = d2 / ST_POINTER_STEP; + goto loop; + } + } + else + { + /* Recurse on right partition, then iterate on left partition */ + if (d2 > ST_POINTER_STEP) + DO_SORT(pn - d2, d2 / ST_POINTER_STEP); + if (d1 > ST_POINTER_STEP) + { + /* Iterate rather than recurse to save stack space */ + /* DO_SORT(a, d1 / ST_POINTER_STEP) */ + n = d1 / ST_POINTER_STEP; + goto loop; + } + } +} +#endif + +#undef DO_CHECK_FOR_INTERRUPTS +#undef DO_COMPARE +#undef DO_MED3 +#undef DO_SORT +#undef DO_SWAP +#undef DO_SWAPN +#undef ST_CHECK_FOR_INTERRUPTS +#undef ST_COMPARATOR_TYPE_NAME +#undef ST_COMPARE +#undef ST_COMPARE_ARG_TYPE +#undef ST_COMPARE_RUNTIME_POINTER +#undef ST_ELEMENT_TYPE +#undef ST_ELEMENT_TYPE_VOID +#undef ST_MAKE_NAME +#undef ST_MAKE_NAME_ +#undef ST_MAKE_PREFIX +#undef ST_MED3 +#undef ST_POINTER_STEP +#undef ST_POINTER_TYPE +#undef ST_SCOPE +#undef ST_SORT +#undef ST_SORT_INVOKE_ARG +#undef ST_SORT_INVOKE_COMPARE +#undef ST_SORT_INVOKE_ELEMENT_SIZE +#undef ST_SORT_PROTO_ARG +#undef ST_SORT_PROTO_COMPARE +#undef ST_SORT_PROTO_ELEMENT_SIZE +#undef ST_SWAP +#undef ST_SWAPN diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h new file mode 100644 index 0000000..9b755c4 --- /dev/null +++ b/src/include/lib/stringinfo.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------- + * + * stringinfo.h + * Declarations/definitions for "StringInfo" functions. + * + * StringInfo provides an extensible string data type (currently limited to a + * length of 1GB). It can be used to buffer either ordinary C strings + * (null-terminated text) or arbitrary binary data. All storage is allocated + * with palloc() (falling back to malloc in frontend code). + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/lib/stringinfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef STRINGINFO_H +#define STRINGINFO_H + +/*------------------------- + * StringInfoData holds information about an extensible string. + * data is the current buffer for the string (allocated with palloc). + * len is the current string length. There is guaranteed to be + * a terminating '\0' at data[len], although this is not very + * useful when the string holds binary data rather than text. + * maxlen is the allocated size in bytes of 'data', i.e. the maximum + * string size (including the terminating '\0' char) that we can + * currently store in 'data' without having to reallocate + * more space. We must always have maxlen > len. + * cursor is initialized to zero by makeStringInfo or initStringInfo, + * but is not otherwise touched by the stringinfo.c routines. + * Some routines use it to scan through a StringInfo. + *------------------------- + */ +typedef struct StringInfoData +{ + char *data; + int len; + int maxlen; + int cursor; +} StringInfoData; + +typedef StringInfoData *StringInfo; + + +/*------------------------ + * There are two ways to create a StringInfo object initially: + * + * StringInfo stringptr = makeStringInfo(); + * Both the StringInfoData and the data buffer are palloc'd. + * + * StringInfoData string; + * initStringInfo(&string); + * The data buffer is palloc'd but the StringInfoData is just local. + * This is the easiest approach for a StringInfo object that will + * only live as long as the current routine. + * + * To destroy a StringInfo, pfree() the data buffer, and then pfree() the + * StringInfoData if it was palloc'd. There's no special support for this. + * + * NOTE: some routines build up a string using StringInfo, and then + * release the StringInfoData but return the data string itself to their + * caller. At that point the data string looks like a plain palloc'd + * string. + *------------------------- + */ + +/*------------------------ + * makeStringInfo + * Create an empty 'StringInfoData' & return a pointer to it. + */ +extern StringInfo makeStringInfo(void); + +/*------------------------ + * initStringInfo + * Initialize a StringInfoData struct (with previously undefined contents) + * to describe an empty string. + */ +extern void initStringInfo(StringInfo str); + +/*------------------------ + * resetStringInfo + * Clears the current content of the StringInfo, if any. The + * StringInfo remains valid. + */ +extern void resetStringInfo(StringInfo str); + +/*------------------------ + * appendStringInfo + * Format text data under the control of fmt (an sprintf-style format string) + * and append it to whatever is already in str. More space is allocated + * to str if necessary. This is sort of like a combination of sprintf and + * strcat. + */ +extern void appendStringInfo(StringInfo str, const char *fmt,...) pg_attribute_printf(2, 3); + +/*------------------------ + * appendStringInfoVA + * Attempt to format text data under the control of fmt (an sprintf-style + * format string) and append it to whatever is already in str. If successful + * return zero; if not (because there's not enough space), return an estimate + * of the space needed, without modifying str. Typically the caller should + * pass the return value to enlargeStringInfo() before trying again; see + * appendStringInfo for standard usage pattern. + */ +extern int appendStringInfoVA(StringInfo str, const char *fmt, va_list args) pg_attribute_printf(2, 0); + +/*------------------------ + * appendStringInfoString + * Append a null-terminated string to str. + * Like appendStringInfo(str, "%s", s) but faster. + */ +extern void appendStringInfoString(StringInfo str, const char *s); + +/*------------------------ + * appendStringInfoChar + * Append a single byte to str. + * Like appendStringInfo(str, "%c", ch) but much faster. + */ +extern void appendStringInfoChar(StringInfo str, char ch); + +/*------------------------ + * appendStringInfoCharMacro + * As above, but a macro for even more speed where it matters. + * Caution: str argument will be evaluated multiple times. + */ +#define appendStringInfoCharMacro(str,ch) \ + (((str)->len + 1 >= (str)->maxlen) ? \ + appendStringInfoChar(str, ch) : \ + (void)((str)->data[(str)->len] = (ch), (str)->data[++(str)->len] = '\0')) + +/*------------------------ + * appendStringInfoSpaces + * Append a given number of spaces to str. + */ +extern void appendStringInfoSpaces(StringInfo str, int count); + +/*------------------------ + * appendBinaryStringInfo + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. + */ +extern void appendBinaryStringInfo(StringInfo str, + const char *data, int datalen); + +/*------------------------ + * appendBinaryStringInfoNT + * Append arbitrary binary data to a StringInfo, allocating more space + * if necessary. Does not ensure a trailing null-byte exists. + */ +extern void appendBinaryStringInfoNT(StringInfo str, + const char *data, int datalen); + +/*------------------------ + * enlargeStringInfo + * Make sure a StringInfo's buffer can hold at least 'needed' more bytes. + */ +extern void enlargeStringInfo(StringInfo str, int needed); + +#endif /* STRINGINFO_H */ diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h new file mode 100644 index 0000000..d3c189e --- /dev/null +++ b/src/include/libpq/auth.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * auth.h + * Definitions for network authentication routines + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/auth.h + * + *------------------------------------------------------------------------- + */ +#ifndef AUTH_H +#define AUTH_H + +#include "libpq/libpq-be.h" + +extern PGDLLIMPORT char *pg_krb_server_keyfile; +extern PGDLLIMPORT bool pg_krb_caseins_users; +extern PGDLLIMPORT char *pg_krb_realm; + +extern void ClientAuthentication(Port *port); +extern void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, + int extralen); + +/* Hook for plugins to get control in ClientAuthentication() */ +typedef void (*ClientAuthentication_hook_type) (Port *, int); +extern PGDLLIMPORT ClientAuthentication_hook_type ClientAuthentication_hook; + +#endif /* AUTH_H */ diff --git a/src/include/libpq/be-fsstubs.h b/src/include/libpq/be-fsstubs.h new file mode 100644 index 0000000..130bc30 --- /dev/null +++ b/src/include/libpq/be-fsstubs.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * be-fsstubs.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/be-fsstubs.h + * + *------------------------------------------------------------------------- + */ +#ifndef BE_FSSTUBS_H +#define BE_FSSTUBS_H + +/* + * These are not fmgr-callable, but are available to C code. + * Probably these should have had the underscore-free names, + * but too late now... + */ +extern int lo_read(int fd, char *buf, int len); +extern int lo_write(int fd, const char *buf, int len); + +/* + * Cleanup LOs at xact commit/abort + */ +extern void AtEOXact_LargeObject(bool isCommit); +extern void AtEOSubXact_LargeObject(bool isCommit, SubTransactionId mySubid, + SubTransactionId parentSubid); + +#endif /* BE_FSSTUBS_H */ diff --git a/src/include/libpq/be-gssapi-common.h b/src/include/libpq/be-gssapi-common.h new file mode 100644 index 0000000..ae84112 --- /dev/null +++ b/src/include/libpq/be-gssapi-common.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * be-gssapi-common.h + * Definitions for GSSAPI authentication and encryption handling + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/be-gssapi-common.h + * + *------------------------------------------------------------------------- + */ + +#ifndef BE_GSSAPI_COMMON_H +#define BE_GSSAPI_COMMON_H + +#ifdef ENABLE_GSS + +#if defined(HAVE_GSSAPI_H) +#include <gssapi.h> +#else +#include <gssapi/gssapi.h> +#endif + +extern void pg_GSS_error(const char *errmsg, + OM_uint32 maj_stat, OM_uint32 min_stat); + +#endif /* ENABLE_GSS */ + +#endif /* BE_GSSAPI_COMMON_H */ diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h new file mode 100644 index 0000000..3238cf6 --- /dev/null +++ b/src/include/libpq/crypt.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * crypt.h + * Interface to libpq/crypt.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/crypt.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CRYPT_H +#define PG_CRYPT_H + +#include "datatype/timestamp.h" + +/* + * Types of password hashes or secrets. + * + * Plaintext passwords can be passed in by the user, in a CREATE/ALTER USER + * command. They will be encrypted to MD5 or SCRAM-SHA-256 format, before + * storing on-disk, so only MD5 and SCRAM-SHA-256 passwords should appear + * in pg_authid.rolpassword. They are also the allowed values for the + * password_encryption GUC. + */ +typedef enum PasswordType +{ + PASSWORD_TYPE_PLAINTEXT = 0, + PASSWORD_TYPE_MD5, + PASSWORD_TYPE_SCRAM_SHA_256 +} PasswordType; + +extern PasswordType get_password_type(const char *shadow_pass); +extern char *encrypt_password(PasswordType target_type, const char *role, + const char *password); + +extern char *get_role_password(const char *role, const char **logdetail); + +extern int md5_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, const char *md5_salt, + int md5_salt_len, const char **logdetail); +extern int plain_crypt_verify(const char *role, const char *shadow_pass, + const char *client_pass, + const char **logdetail); + +#endif diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h new file mode 100644 index 0000000..d06da81 --- /dev/null +++ b/src/include/libpq/hba.h @@ -0,0 +1,179 @@ +/*------------------------------------------------------------------------- + * + * hba.h + * Interface to hba.c + * + * + * src/include/libpq/hba.h + * + *------------------------------------------------------------------------- + */ +#ifndef HBA_H +#define HBA_H + +#include "libpq/pqcomm.h" /* pgrminclude ignore */ /* needed for NetBSD */ +#include "nodes/pg_list.h" +#include "regex/regex.h" + + +/* + * The following enum represents the authentication methods that + * are supported by PostgreSQL. + * + * Note: keep this in sync with the UserAuthName array in hba.c. + */ +typedef enum UserAuth +{ + uaReject, + uaImplicitReject, /* Not a user-visible option */ + uaTrust, + uaIdent, + uaPassword, + uaMD5, + uaSCRAM, + uaGSS, + uaSSPI, + uaPAM, + uaBSD, + uaLDAP, + uaCert, + uaRADIUS, + uaPeer +#define USER_AUTH_LAST uaPeer /* Must be last value of this enum */ +} UserAuth; + +/* + * Data structures representing pg_hba.conf entries + */ + +typedef enum IPCompareMethod +{ + ipCmpMask, + ipCmpSameHost, + ipCmpSameNet, + ipCmpAll +} IPCompareMethod; + +typedef enum ConnType +{ + ctLocal, + ctHost, + ctHostSSL, + ctHostNoSSL, + ctHostGSS, + ctHostNoGSS, +} ConnType; + +typedef enum ClientCertMode +{ + clientCertOff, + clientCertCA, + clientCertFull +} ClientCertMode; + +typedef enum ClientCertName +{ + clientCertCN, + clientCertDN +} ClientCertName; + +typedef struct HbaLine +{ + int linenumber; + char *rawline; + ConnType conntype; + List *databases; + List *roles; + struct sockaddr_storage addr; + int addrlen; /* zero if we don't have a valid addr */ + struct sockaddr_storage mask; + int masklen; /* zero if we don't have a valid mask */ + IPCompareMethod ip_cmp_method; + char *hostname; + UserAuth auth_method; + char *usermap; + char *pamservice; + bool pam_use_hostname; + bool ldaptls; + char *ldapscheme; + char *ldapserver; + int ldapport; + char *ldapbinddn; + char *ldapbindpasswd; + char *ldapsearchattribute; + char *ldapsearchfilter; + char *ldapbasedn; + int ldapscope; + char *ldapprefix; + char *ldapsuffix; + ClientCertMode clientcert; + ClientCertName clientcertname; + char *krb_realm; + bool include_realm; + bool compat_realm; + bool upn_username; + List *radiusservers; + char *radiusservers_s; + List *radiussecrets; + char *radiussecrets_s; + List *radiusidentifiers; + char *radiusidentifiers_s; + List *radiusports; + char *radiusports_s; +} HbaLine; + +typedef struct IdentLine +{ + int linenumber; + + char *usermap; + char *ident_user; + char *pg_role; + regex_t re; +} IdentLine; + +/* + * A single string token lexed from an authentication configuration file + * (pg_ident.conf or pg_hba.conf), together with whether the token has + * been quoted. + */ +typedef struct AuthToken +{ + char *string; + bool quoted; +} AuthToken; + +/* + * TokenizedAuthLine represents one line lexed from an authentication + * configuration file. Each item in the "fields" list is a sub-list of + * AuthTokens. We don't emit a TokenizedAuthLine for empty or all-comment + * lines, so "fields" is never NIL (nor are any of its sub-lists). + * + * Exception: if an error occurs during tokenization, we might have + * fields == NIL, in which case err_msg != NULL. + */ +typedef struct TokenizedAuthLine +{ + List *fields; /* List of lists of AuthTokens */ + int line_num; /* Line number */ + char *raw_line; /* Raw line text */ + char *err_msg; /* Error message if any */ +} TokenizedAuthLine; + +/* kluge to avoid including libpq/libpq-be.h here */ +typedef struct Port hbaPort; + +extern bool load_hba(void); +extern bool load_ident(void); +extern const char *hba_authname(UserAuth auth_method); +extern void hba_getauthmethod(hbaPort *port); +extern int check_usermap(const char *usermap_name, + const char *pg_role, const char *auth_user, + bool case_insensitive); +extern HbaLine *parse_hba_line(TokenizedAuthLine *tok_line, int elevel); +extern IdentLine *parse_ident_line(TokenizedAuthLine *tok_line, int elevel); +extern bool pg_isblank(const char c); +extern MemoryContext tokenize_auth_file(const char *filename, FILE *file, + List **tok_lines, int elevel); + +#endif /* HBA_H */ diff --git a/src/include/libpq/ifaddr.h b/src/include/libpq/ifaddr.h new file mode 100644 index 0000000..b04d093 --- /dev/null +++ b/src/include/libpq/ifaddr.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * ifaddr.h + * IP netmask calculations, and enumerating network interfaces. + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/libpq/ifaddr.h + * + *------------------------------------------------------------------------- + */ +#ifndef IFADDR_H +#define IFADDR_H + +#include "libpq/pqcomm.h" /* pgrminclude ignore */ + +typedef void (*PgIfAddrCallback) (struct sockaddr *addr, + struct sockaddr *netmask, + void *cb_data); + +extern int pg_range_sockaddr(const struct sockaddr_storage *addr, + const struct sockaddr_storage *netaddr, + const struct sockaddr_storage *netmask); + +extern int pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, + char *numbits, int family); + +extern int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data); + +#endif /* IFADDR_H */ diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h new file mode 100644 index 0000000..351b4f4 --- /dev/null +++ b/src/include/libpq/libpq-be.h @@ -0,0 +1,343 @@ +/*------------------------------------------------------------------------- + * + * libpq-be.h + * This file contains definitions for structures and externs used + * by the postmaster during client authentication. + * + * Note that this is backend-internal and is NOT exported to clients. + * Structs that need to be client-visible are in pqcomm.h. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/libpq-be.h + * + *------------------------------------------------------------------------- + */ +#ifndef LIBPQ_BE_H +#define LIBPQ_BE_H + +#include <sys/time.h> +#ifdef USE_OPENSSL +#include <openssl/ssl.h> +#include <openssl/err.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + +#ifdef ENABLE_GSS +#if defined(HAVE_GSSAPI_H) +#include <gssapi.h> +#else +#include <gssapi/gssapi.h> +#endif /* HAVE_GSSAPI_H */ +/* + * GSSAPI brings in headers that set a lot of things in the global namespace on win32, + * that doesn't match the msvc build. It gives a bunch of compiler warnings that we ignore, + * but also defines a symbol that simply does not exist. Undefine it again. + */ +#ifdef _MSC_VER +#undef HAVE_GETADDRINFO +#endif +#endif /* ENABLE_GSS */ + +#ifdef ENABLE_SSPI +#define SECURITY_WIN32 +#if defined(WIN32) && !defined(_MSC_VER) +#include <ntsecapi.h> +#endif +#include <security.h> +#undef SECURITY_WIN32 + +#ifndef ENABLE_GSS +/* + * Define a fake structure compatible with GSSAPI on Unix. + */ +typedef struct +{ + void *value; + int length; +} gss_buffer_desc; +#endif +#endif /* ENABLE_SSPI */ + +#include "datatype/timestamp.h" +#include "libpq/hba.h" +#include "libpq/pqcomm.h" + + +typedef enum CAC_state +{ + CAC_OK, + CAC_STARTUP, + CAC_SHUTDOWN, + CAC_RECOVERY, + CAC_NOTCONSISTENT, + CAC_TOOMANY +} CAC_state; + + +/* + * GSSAPI specific state information + */ +#if defined(ENABLE_GSS) | defined(ENABLE_SSPI) +typedef struct +{ + gss_buffer_desc outbuf; /* GSSAPI output token buffer */ +#ifdef ENABLE_GSS + gss_cred_id_t cred; /* GSSAPI connection cred's */ + gss_ctx_id_t ctx; /* GSSAPI connection context */ + gss_name_t name; /* GSSAPI client name */ + char *princ; /* GSSAPI Principal used for auth, NULL if + * GSSAPI auth was not used */ + bool auth; /* GSSAPI Authentication used */ + bool enc; /* GSSAPI encryption in use */ +#endif +} pg_gssinfo; +#endif + +/* + * This is used by the postmaster in its communication with frontends. It + * contains all state information needed during this communication before the + * backend is run. The Port structure is kept in malloc'd memory and is + * still available when a backend is running (see MyProcPort). The data + * it points to must also be malloc'd, or else palloc'd in TopMemoryContext, + * so that it survives into PostgresMain execution! + * + * remote_hostname is set if we did a successful reverse lookup of the + * client's IP address during connection setup. + * remote_hostname_resolv tracks the state of hostname verification: + * +1 = remote_hostname is known to resolve to client's IP address + * -1 = remote_hostname is known NOT to resolve to client's IP address + * 0 = we have not done the forward DNS lookup yet + * -2 = there was an error in name resolution + * If reverse lookup of the client IP address fails, remote_hostname will be + * left NULL while remote_hostname_resolv is set to -2. If reverse lookup + * succeeds but forward lookup fails, remote_hostname_resolv is also set to -2 + * (the case is distinguishable because remote_hostname isn't NULL). In + * either of the -2 cases, remote_hostname_errcode saves the lookup return + * code for possible later use with gai_strerror. + */ + +typedef struct Port +{ + pgsocket sock; /* File descriptor */ + bool noblock; /* is the socket in non-blocking mode? */ + ProtocolVersion proto; /* FE/BE protocol version */ + SockAddr laddr; /* local addr (postmaster) */ + SockAddr raddr; /* remote addr (client) */ + char *remote_host; /* name (or ip addr) of remote host */ + char *remote_hostname; /* name (not ip addr) of remote host, if + * available */ + int remote_hostname_resolv; /* see above */ + int remote_hostname_errcode; /* see above */ + char *remote_port; /* text rep of remote port */ + CAC_state canAcceptConnections; /* postmaster connection status */ + + /* + * Information that needs to be saved from the startup packet and passed + * into backend execution. "char *" fields are NULL if not set. + * guc_options points to a List of alternating option names and values. + */ + char *database_name; + char *user_name; + char *cmdline_options; + List *guc_options; + + /* + * The startup packet application name, only used here for the "connection + * authorized" log message. We shouldn't use this post-startup, instead + * the GUC should be used as application can change it afterward. + */ + char *application_name; + + /* + * Information that needs to be held during the authentication cycle. + */ + HbaLine *hba; + + /* + * Authenticated identity. The meaning of this identifier is dependent on + * hba->auth_method; it is the identity (if any) that the user presented + * during the authentication cycle, before they were assigned a database + * role. (It is effectively the "SYSTEM-USERNAME" of a pg_ident usermap + * -- though the exact string in use may be different, depending on pg_hba + * options.) + * + * authn_id is NULL if the user has not actually been authenticated, for + * example if the "trust" auth method is in use. + */ + const char *authn_id; + + /* + * TCP keepalive and user timeout settings. + * + * default values are 0 if AF_UNIX or not yet known; current values are 0 + * if AF_UNIX or using the default. Also, -1 in a default value means we + * were unable to find out the default (getsockopt failed). + */ + int default_keepalives_idle; + int default_keepalives_interval; + int default_keepalives_count; + int default_tcp_user_timeout; + int keepalives_idle; + int keepalives_interval; + int keepalives_count; + int tcp_user_timeout; + + /* + * GSSAPI structures. + */ +#if defined(ENABLE_GSS) || defined(ENABLE_SSPI) + + /* + * If GSSAPI is supported and used on this connection, store GSSAPI + * information. Even when GSSAPI is not compiled in, store a NULL pointer + * to keep struct offsets the same (for extension ABI compatibility). + */ + pg_gssinfo *gss; +#else + void *gss; +#endif + + /* + * SSL structures. + */ + bool ssl_in_use; + char *peer_cn; + char *peer_dn; + bool peer_cert_valid; + + /* + * OpenSSL structures. (Keep these last so that the locations of other + * fields are the same whether or not you build with SSL enabled.) + */ +#ifdef USE_OPENSSL + SSL *ssl; + X509 *peer; +#endif +} Port; + +#ifdef USE_SSL +/* + * Hardcoded DH parameters, used in ephemeral DH keying. (See also + * README.SSL for more details on EDH.) + * + * This is the 2048-bit DH parameter from RFC 3526. The generation of the + * prime is specified in RFC 2412 Appendix E, which also discusses the + * design choice of the generator. Note that when loaded with OpenSSL + * this causes DH_check() to fail on DH_NOT_SUITABLE_GENERATOR, where + * leaking a bit is preferred. + */ +#define FILE_DH2048 \ +"-----BEGIN DH PARAMETERS-----\n\ +MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n\ +IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n\ +awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n\ +mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n\ +fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n\ +5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==\n\ +-----END DH PARAMETERS-----\n" + +/* + * These functions are implemented by the glue code specific to each + * SSL implementation (e.g. be-secure-openssl.c) + */ + +/* + * Initialize global SSL context. + * + * If isServerStart is true, report any errors as FATAL (so we don't return). + * Otherwise, log errors at LOG level and return -1 to indicate trouble, + * preserving the old SSL state if any. Returns 0 if OK. + */ +extern int be_tls_init(bool isServerStart); + +/* + * Destroy global SSL context, if any. + */ +extern void be_tls_destroy(void); + +/* + * Attempt to negotiate SSL connection. + */ +extern int be_tls_open_server(Port *port); + +/* + * Close SSL connection. + */ +extern void be_tls_close(Port *port); + +/* + * Read data from a secure connection. + */ +extern ssize_t be_tls_read(Port *port, void *ptr, size_t len, int *waitfor); + +/* + * Write data to a secure connection. + */ +extern ssize_t be_tls_write(Port *port, void *ptr, size_t len, int *waitfor); + +/* + * Return information about the SSL connection. + */ +extern int be_tls_get_cipher_bits(Port *port); +extern const char *be_tls_get_version(Port *port); +extern const char *be_tls_get_cipher(Port *port); +extern void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len); +extern void be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len); +extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len); + +/* + * Get the server certificate hash for SCRAM channel binding type + * tls-server-end-point. + * + * The result is a palloc'd hash of the server certificate with its + * size, and NULL if there is no certificate available. + * + * This is not supported with old versions of OpenSSL that don't have + * the X509_get_signature_nid() function. + */ +#if defined(USE_OPENSSL) && (defined(HAVE_X509_GET_SIGNATURE_NID) || defined(HAVE_X509_GET_SIGNATURE_INFO)) +#define HAVE_BE_TLS_GET_CERTIFICATE_HASH +extern char *be_tls_get_certificate_hash(Port *port, size_t *len); +#endif + +/* init hook for SSL, the default sets the password callback if appropriate */ +#ifdef USE_OPENSSL +typedef void (*openssl_tls_init_hook_typ) (SSL_CTX *context, bool isServerStart); +extern PGDLLIMPORT openssl_tls_init_hook_typ openssl_tls_init_hook; +#endif + +#endif /* USE_SSL */ + +#ifdef ENABLE_GSS +/* + * Return information about the GSSAPI authenticated connection + */ +extern bool be_gssapi_get_auth(Port *port); +extern bool be_gssapi_get_enc(Port *port); +extern const char *be_gssapi_get_princ(Port *port); + +/* Read and write to a GSSAPI-encrypted connection. */ +extern ssize_t be_gssapi_read(Port *port, void *ptr, size_t len); +extern ssize_t be_gssapi_write(Port *port, void *ptr, size_t len); +#endif /* ENABLE_GSS */ + +extern PGDLLIMPORT ProtocolVersion FrontendProtocol; + +/* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ + +extern int pq_getkeepalivesidle(Port *port); +extern int pq_getkeepalivesinterval(Port *port); +extern int pq_getkeepalivescount(Port *port); +extern int pq_gettcpusertimeout(Port *port); + +extern int pq_setkeepalivesidle(int idle, Port *port); +extern int pq_setkeepalivesinterval(int interval, Port *port); +extern int pq_setkeepalivescount(int count, Port *port); +extern int pq_settcpusertimeout(int timeout, Port *port); + +#endif /* LIBPQ_BE_H */ diff --git a/src/include/libpq/libpq-fs.h b/src/include/libpq/libpq-fs.h new file mode 100644 index 0000000..7fa02d2 --- /dev/null +++ b/src/include/libpq/libpq-fs.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * libpq-fs.h + * definitions for using Inversion file system routines (ie, large objects) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/libpq-fs.h + * + *------------------------------------------------------------------------- + */ +#ifndef LIBPQ_FS_H +#define LIBPQ_FS_H + +/* + * Read/write mode flags for inversion (large object) calls + */ + +#define INV_WRITE 0x00020000 +#define INV_READ 0x00040000 + +#endif /* LIBPQ_FS_H */ diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h new file mode 100644 index 0000000..2de7d9b --- /dev/null +++ b/src/include/libpq/libpq.h @@ -0,0 +1,144 @@ +/*------------------------------------------------------------------------- + * + * libpq.h + * POSTGRES LIBPQ buffer structure definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/libpq.h + * + *------------------------------------------------------------------------- + */ +#ifndef LIBPQ_H +#define LIBPQ_H + +#include <netinet/in.h> + +#include "lib/stringinfo.h" +#include "libpq/libpq-be.h" +#include "storage/latch.h" + + +/* + * Callers of pq_getmessage() must supply a maximum expected message size. + * By convention, if there's not any specific reason to use another value, + * use PQ_SMALL_MESSAGE_LIMIT for messages that shouldn't be too long, and + * PQ_LARGE_MESSAGE_LIMIT for messages that can be long. + */ +#define PQ_SMALL_MESSAGE_LIMIT 10000 +#define PQ_LARGE_MESSAGE_LIMIT (MaxAllocSize - 1) + +typedef struct +{ + void (*comm_reset) (void); + int (*flush) (void); + int (*flush_if_writable) (void); + bool (*is_send_pending) (void); + int (*putmessage) (char msgtype, const char *s, size_t len); + void (*putmessage_noblock) (char msgtype, const char *s, size_t len); +} PQcommMethods; + +extern const PGDLLIMPORT PQcommMethods *PqCommMethods; + +#define pq_comm_reset() (PqCommMethods->comm_reset()) +#define pq_flush() (PqCommMethods->flush()) +#define pq_flush_if_writable() (PqCommMethods->flush_if_writable()) +#define pq_is_send_pending() (PqCommMethods->is_send_pending()) +#define pq_putmessage(msgtype, s, len) \ + (PqCommMethods->putmessage(msgtype, s, len)) +#define pq_putmessage_noblock(msgtype, s, len) \ + (PqCommMethods->putmessage_noblock(msgtype, s, len)) + +/* + * External functions. + */ + +/* + * prototypes for functions in pqcomm.c + */ +extern PGDLLIMPORT WaitEventSet *FeBeWaitSet; + +#define FeBeWaitSetSocketPos 0 +#define FeBeWaitSetLatchPos 1 +#define FeBeWaitSetNEvents 3 + +extern int StreamServerPort(int family, const char *hostName, + unsigned short portNumber, const char *unixSocketDir, + pgsocket ListenSocket[], int MaxListen); +extern int StreamConnection(pgsocket server_fd, Port *port); +extern void StreamClose(pgsocket sock); +extern void TouchSocketFiles(void); +extern void RemoveSocketFiles(void); +extern void pq_init(void); +extern int pq_getbytes(char *s, size_t len); +extern void pq_startmsgread(void); +extern void pq_endmsgread(void); +extern bool pq_is_reading_msg(void); +extern int pq_getmessage(StringInfo s, int maxlen); +extern int pq_getbyte(void); +extern int pq_peekbyte(void); +extern int pq_getbyte_if_available(unsigned char *c); +extern bool pq_buffer_has_data(void); +extern int pq_putmessage_v2(char msgtype, const char *s, size_t len); +extern bool pq_check_connection(void); + +/* + * prototypes for functions in be-secure.c + */ +extern PGDLLIMPORT char *ssl_library; +extern PGDLLIMPORT char *ssl_cert_file; +extern PGDLLIMPORT char *ssl_key_file; +extern PGDLLIMPORT char *ssl_ca_file; +extern PGDLLIMPORT char *ssl_crl_file; +extern PGDLLIMPORT char *ssl_crl_dir; +extern PGDLLIMPORT char *ssl_dh_params_file; +extern PGDLLIMPORT char *ssl_passphrase_command; +extern PGDLLIMPORT bool ssl_passphrase_command_supports_reload; +#ifdef USE_SSL +extern PGDLLIMPORT bool ssl_loaded_verify_locations; +#endif + +extern int secure_initialize(bool isServerStart); +extern bool secure_loaded_verify_locations(void); +extern void secure_destroy(void); +extern int secure_open_server(Port *port); +extern void secure_close(Port *port); +extern ssize_t secure_read(Port *port, void *ptr, size_t len); +extern ssize_t secure_write(Port *port, void *ptr, size_t len); +extern ssize_t secure_raw_read(Port *port, void *ptr, size_t len); +extern ssize_t secure_raw_write(Port *port, const void *ptr, size_t len); + +/* + * prototypes for functions in be-secure-gssapi.c + */ +#ifdef ENABLE_GSS +extern ssize_t secure_open_gssapi(Port *port); +#endif + +/* GUCs */ +extern PGDLLIMPORT char *SSLCipherSuites; +extern PGDLLIMPORT char *SSLECDHCurve; +extern PGDLLIMPORT bool SSLPreferServerCiphers; +extern PGDLLIMPORT int ssl_min_protocol_version; +extern PGDLLIMPORT int ssl_max_protocol_version; + +enum ssl_protocol_versions +{ + PG_TLS_ANY = 0, + PG_TLS1_VERSION, + PG_TLS1_1_VERSION, + PG_TLS1_2_VERSION, + PG_TLS1_3_VERSION, +}; + +/* + * prototypes for functions in be-secure-common.c + */ +extern int run_ssl_passphrase_command(const char *prompt, bool is_server_start, + char *buf, int size); +extern bool check_ssl_key_file_permissions(const char *ssl_key_file, + bool isServerStart); + +#endif /* LIBPQ_H */ diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h new file mode 100644 index 0000000..b418283 --- /dev/null +++ b/src/include/libpq/pqcomm.h @@ -0,0 +1,194 @@ +/*------------------------------------------------------------------------- + * + * pqcomm.h + * Definitions common to frontends and backends. + * + * NOTE: for historical reasons, this does not correspond to pqcomm.c. + * pqcomm.c's routines are declared in libpq.h. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/pqcomm.h + * + *------------------------------------------------------------------------- + */ +#ifndef PQCOMM_H +#define PQCOMM_H + +#include <sys/socket.h> +#include <netdb.h> +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#include <netinet/in.h> + +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY +#define ss_family __ss_family +#else +#error struct sockaddr_storage does not provide an ss_family member +#endif +#endif + +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN +#define ss_len __ss_len +#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 +#endif +#else /* !HAVE_STRUCT_SOCKADDR_STORAGE */ + +/* Define a struct sockaddr_storage if we don't have one. */ + +struct sockaddr_storage +{ + union + { + struct sockaddr sa; /* get the system-dependent fields */ + int64 ss_align; /* ensures struct is properly aligned */ + char ss_pad[128]; /* ensures struct has desired size */ + } ss_stuff; +}; + +#define ss_family ss_stuff.sa.sa_family +/* It should have an ss_len field if sockaddr has sa_len. */ +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +#define ss_len ss_stuff.sa.sa_len +#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1 +#endif +#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */ + +typedef struct +{ + struct sockaddr_storage addr; + socklen_t salen; +} SockAddr; + +/* Configure the UNIX socket location for the well known port. */ + +#define UNIXSOCK_PATH(path, port, sockdir) \ + (AssertMacro(sockdir), \ + AssertMacro(*(sockdir) != '\0'), \ + snprintf(path, sizeof(path), "%s/.s.PGSQL.%d", \ + (sockdir), (port))) + +/* + * The maximum workable length of a socket path is what will fit into + * struct sockaddr_un. This is usually only 100 or so bytes :-(. + * + * For consistency, always pass a MAXPGPATH-sized buffer to UNIXSOCK_PATH(), + * then complain if the resulting string is >= UNIXSOCK_PATH_BUFLEN bytes. + * (Because the standard API for getaddrinfo doesn't allow it to complain in + * a useful way when the socket pathname is too long, we have to test for + * this explicitly, instead of just letting the subroutine return an error.) + */ +#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path) + +/* + * A host that looks either like an absolute path or starts with @ is + * interpreted as a Unix-domain socket address. + */ +static inline bool +is_unixsock_path(const char *path) +{ + return is_absolute_path(path) || path[0] == '@'; +} + +/* + * These manipulate the frontend/backend protocol version number. + * + * The major number should be incremented for incompatible changes. The minor + * number should be incremented for compatible changes (eg. additional + * functionality). + * + * If a backend supports version m.n of the protocol it must actually support + * versions m.[0..n]. Backend support for version m-1 can be dropped after a + * `reasonable' length of time. + * + * A frontend isn't required to support anything other than the current + * version. + */ + +#define PG_PROTOCOL_MAJOR(v) ((v) >> 16) +#define PG_PROTOCOL_MINOR(v) ((v) & 0x0000ffff) +#define PG_PROTOCOL(m,n) (((m) << 16) | (n)) + +/* + * The earliest and latest frontend/backend protocol version supported. + * (Only protocol version 3 is currently supported) + */ + +#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(3,0) +#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,0) + +typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ + +typedef ProtocolVersion MsgType; + + +/* + * Packet lengths are 4 bytes in network byte order. + * + * The initial length is omitted from the packet layouts appearing below. + */ + +typedef uint32 PacketLen; + +extern PGDLLIMPORT bool Db_user_namespace; + +/* + * In protocol 3.0 and later, the startup packet length is not fixed, but + * we set an arbitrary limit on it anyway. This is just to prevent simple + * denial-of-service attacks via sending enough data to run the server + * out of memory. + */ +#define MAX_STARTUP_PACKET_LENGTH 10000 + + +/* These are the authentication request codes sent by the backend. */ + +#define AUTH_REQ_OK 0 /* User is authenticated */ +#define AUTH_REQ_KRB4 1 /* Kerberos V4. Not supported any more. */ +#define AUTH_REQ_KRB5 2 /* Kerberos V5. Not supported any more. */ +#define AUTH_REQ_PASSWORD 3 /* Password */ +#define AUTH_REQ_CRYPT 4 /* crypt password. Not supported any more. */ +#define AUTH_REQ_MD5 5 /* md5 password */ +#define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */ +#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */ +#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */ +#define AUTH_REQ_SSPI 9 /* SSPI negotiate without wrap() */ +#define AUTH_REQ_SASL 10 /* Begin SASL authentication */ +#define AUTH_REQ_SASL_CONT 11 /* Continue SASL authentication */ +#define AUTH_REQ_SASL_FIN 12 /* Final SASL message */ + +typedef uint32 AuthRequest; + + +/* + * A client can also send a cancel-current-operation request to the postmaster. + * This is uglier than sending it directly to the client's backend, but it + * avoids depending on out-of-band communication facilities. + * + * The cancel request code must not match any protocol version number + * we're ever likely to use. This random choice should do. + */ +#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678) + +typedef struct CancelRequestPacket +{ + /* Note that each field is stored in network byte order! */ + MsgType cancelRequestCode; /* code to identify a cancel request */ + uint32 backendPID; /* PID of client's backend */ + uint32 cancelAuthCode; /* secret key to authorize cancel */ +} CancelRequestPacket; + + +/* + * A client can also start by sending a SSL or GSSAPI negotiation request to + * get a secure channel. + */ +#define NEGOTIATE_SSL_CODE PG_PROTOCOL(1234,5679) +#define NEGOTIATE_GSS_CODE PG_PROTOCOL(1234,5680) + +#endif /* PQCOMM_H */ diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h new file mode 100644 index 0000000..cd83482 --- /dev/null +++ b/src/include/libpq/pqformat.h @@ -0,0 +1,210 @@ +/*------------------------------------------------------------------------- + * + * pqformat.h + * Definitions for formatting and parsing frontend/backend messages + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/pqformat.h + * + *------------------------------------------------------------------------- + */ +#ifndef PQFORMAT_H +#define PQFORMAT_H + +#include "lib/stringinfo.h" +#include "mb/pg_wchar.h" +#include "port/pg_bswap.h" + +extern void pq_beginmessage(StringInfo buf, char msgtype); +extern void pq_beginmessage_reuse(StringInfo buf, char msgtype); +extern void pq_endmessage(StringInfo buf); +extern void pq_endmessage_reuse(StringInfo buf); + +extern void pq_sendbytes(StringInfo buf, const char *data, int datalen); +extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen, + bool countincludesself); +extern void pq_sendtext(StringInfo buf, const char *str, int slen); +extern void pq_sendstring(StringInfo buf, const char *str); +extern void pq_send_ascii_string(StringInfo buf, const char *str); +extern void pq_sendfloat4(StringInfo buf, float4 f); +extern void pq_sendfloat8(StringInfo buf, float8 f); + +/* + * Append a [u]int8 to a StringInfo buffer, which already has enough space + * preallocated. + * + * The use of pg_restrict allows the compiler to optimize the code based on + * the assumption that buf, buf->len, buf->data and *buf->data don't + * overlap. Without the annotation buf->len etc cannot be kept in a register + * over subsequent pq_writeintN calls. + * + * The use of StringInfoData * rather than StringInfo is due to MSVC being + * overly picky and demanding a * before a restrict. + */ +static inline void +pq_writeint8(StringInfoData *pg_restrict buf, uint8 i) +{ + uint8 ni = i; + + Assert(buf->len + (int) sizeof(uint8) <= buf->maxlen); + memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint8)); + buf->len += sizeof(uint8); +} + +/* + * Append a [u]int16 to a StringInfo buffer, which already has enough space + * preallocated. + */ +static inline void +pq_writeint16(StringInfoData *pg_restrict buf, uint16 i) +{ + uint16 ni = pg_hton16(i); + + Assert(buf->len + (int) sizeof(uint16) <= buf->maxlen); + memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint16)); + buf->len += sizeof(uint16); +} + +/* + * Append a [u]int32 to a StringInfo buffer, which already has enough space + * preallocated. + */ +static inline void +pq_writeint32(StringInfoData *pg_restrict buf, uint32 i) +{ + uint32 ni = pg_hton32(i); + + Assert(buf->len + (int) sizeof(uint32) <= buf->maxlen); + memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint32)); + buf->len += sizeof(uint32); +} + +/* + * Append a [u]int64 to a StringInfo buffer, which already has enough space + * preallocated. + */ +static inline void +pq_writeint64(StringInfoData *pg_restrict buf, uint64 i) +{ + uint64 ni = pg_hton64(i); + + Assert(buf->len + (int) sizeof(uint64) <= buf->maxlen); + memcpy((char *pg_restrict) (buf->data + buf->len), &ni, sizeof(uint64)); + buf->len += sizeof(uint64); +} + +/* + * Append a null-terminated text string (with conversion) to a buffer with + * preallocated space. + * + * NB: The pre-allocated space needs to be sufficient for the string after + * converting to client encoding. + * + * NB: passed text string must be null-terminated, and so is the data + * sent to the frontend. + */ +static inline void +pq_writestring(StringInfoData *pg_restrict buf, const char *pg_restrict str) +{ + int slen = strlen(str); + char *p; + + p = pg_server_to_client(str, slen); + if (p != str) /* actual conversion has been done? */ + slen = strlen(p); + + Assert(buf->len + slen + 1 <= buf->maxlen); + + memcpy(((char *pg_restrict) buf->data + buf->len), p, slen + 1); + buf->len += slen + 1; + + if (p != str) + pfree(p); +} + +/* append a binary [u]int8 to a StringInfo buffer */ +static inline void +pq_sendint8(StringInfo buf, uint8 i) +{ + enlargeStringInfo(buf, sizeof(uint8)); + pq_writeint8(buf, i); +} + +/* append a binary [u]int16 to a StringInfo buffer */ +static inline void +pq_sendint16(StringInfo buf, uint16 i) +{ + enlargeStringInfo(buf, sizeof(uint16)); + pq_writeint16(buf, i); +} + +/* append a binary [u]int32 to a StringInfo buffer */ +static inline void +pq_sendint32(StringInfo buf, uint32 i) +{ + enlargeStringInfo(buf, sizeof(uint32)); + pq_writeint32(buf, i); +} + +/* append a binary [u]int64 to a StringInfo buffer */ +static inline void +pq_sendint64(StringInfo buf, uint64 i) +{ + enlargeStringInfo(buf, sizeof(uint64)); + pq_writeint64(buf, i); +} + +/* append a binary byte to a StringInfo buffer */ +static inline void +pq_sendbyte(StringInfo buf, uint8 byt) +{ + pq_sendint8(buf, byt); +} + +/* + * Append a binary integer to a StringInfo buffer + * + * This function is deprecated; prefer use of the functions above. + */ +static inline void +pq_sendint(StringInfo buf, uint32 i, int b) +{ + switch (b) + { + case 1: + pq_sendint8(buf, (uint8) i); + break; + case 2: + pq_sendint16(buf, (uint16) i); + break; + case 4: + pq_sendint32(buf, (uint32) i); + break; + default: + elog(ERROR, "unsupported integer size %d", b); + break; + } +} + + +extern void pq_begintypsend(StringInfo buf); +extern bytea *pq_endtypsend(StringInfo buf); + +extern void pq_puttextmessage(char msgtype, const char *str); +extern void pq_putemptymessage(char msgtype); + +extern int pq_getmsgbyte(StringInfo msg); +extern unsigned int pq_getmsgint(StringInfo msg, int b); +extern int64 pq_getmsgint64(StringInfo msg); +extern float4 pq_getmsgfloat4(StringInfo msg); +extern float8 pq_getmsgfloat8(StringInfo msg); +extern const char *pq_getmsgbytes(StringInfo msg, int datalen); +extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen); +extern char *pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes); +extern const char *pq_getmsgstring(StringInfo msg); +extern const char *pq_getmsgrawstring(StringInfo msg); +extern void pq_getmsgend(StringInfo msg); + +#endif /* PQFORMAT_H */ diff --git a/src/include/libpq/pqmq.h b/src/include/libpq/pqmq.h new file mode 100644 index 0000000..6687c8f --- /dev/null +++ b/src/include/libpq/pqmq.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * pqmq.h + * Use the frontend/backend protocol for communication over a shm_mq + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/pqmq.h + * + *------------------------------------------------------------------------- + */ +#ifndef PQMQ_H +#define PQMQ_H + +#include "lib/stringinfo.h" +#include "storage/shm_mq.h" + +extern void pq_redirect_to_shm_mq(dsm_segment *seg, shm_mq_handle *mqh); +extern void pq_set_parallel_leader(pid_t pid, BackendId backend_id); + +extern void pq_parse_errornotice(StringInfo str, ErrorData *edata); + +#endif /* PQMQ_H */ diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h new file mode 100644 index 0000000..41227a3 --- /dev/null +++ b/src/include/libpq/pqsignal.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * pqsignal.h + * Backend signal(2) support (see also src/port/pqsignal.c) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/pqsignal.h + * + *------------------------------------------------------------------------- + */ +#ifndef PQSIGNAL_H +#define PQSIGNAL_H + +#include <signal.h> + +#ifndef WIN32 +#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL) +#else +/* Emulate POSIX sigset_t APIs on Windows */ +typedef int sigset_t; + +extern int pqsigsetmask(int mask); + +#define PG_SETMASK(mask) pqsigsetmask(*(mask)) +#define sigemptyset(set) (*(set) = 0) +#define sigfillset(set) (*(set) = ~0) +#define sigaddset(set, signum) (*(set) |= (sigmask(signum))) +#define sigdelset(set, signum) (*(set) &= ~(sigmask(signum))) +#endif /* WIN32 */ + +extern PGDLLIMPORT sigset_t UnBlockSig; +extern PGDLLIMPORT sigset_t BlockSig; +extern PGDLLIMPORT sigset_t StartupBlockSig; + +extern void pqinitmask(void); + +/* pqsigfunc is declared in src/include/port.h */ +extern pqsigfunc pqsignal_pm(int signo, pqsigfunc func); + +#endif /* PQSIGNAL_H */ diff --git a/src/include/libpq/sasl.h b/src/include/libpq/sasl.h new file mode 100644 index 0000000..39ccf8f --- /dev/null +++ b/src/include/libpq/sasl.h @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------- + * + * sasl.h + * Defines the SASL mechanism interface for the backend. + * + * Each SASL mechanism defines a frontend and a backend callback structure. + * + * See src/interfaces/libpq/fe-auth-sasl.h for the frontend counterpart. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/sasl.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_SASL_H +#define PG_SASL_H + +#include "lib/stringinfo.h" +#include "libpq/libpq-be.h" + +/* Status codes for message exchange */ +#define PG_SASL_EXCHANGE_CONTINUE 0 +#define PG_SASL_EXCHANGE_SUCCESS 1 +#define PG_SASL_EXCHANGE_FAILURE 2 + +/* + * Backend SASL mechanism callbacks. + * + * To implement a backend mechanism, declare a pg_be_sasl_mech struct with + * appropriate callback implementations. Then pass the mechanism to + * CheckSASLAuth() during ClientAuthentication(), once the server has decided + * which authentication method to use. + */ +typedef struct pg_be_sasl_mech +{ + /*--------- + * get_mechanisms() + * + * Retrieves the list of SASL mechanism names supported by this + * implementation. + * + * Input parameters: + * + * port: The client Port + * + * Output parameters: + * + * buf: A StringInfo buffer that the callback should populate with + * supported mechanism names. The names are appended into this + * StringInfo, each one ending with '\0' bytes. + *--------- + */ + void (*get_mechanisms) (Port *port, StringInfo buf); + + /*--------- + * init() + * + * Initializes mechanism-specific state for a connection. This callback + * must return a pointer to its allocated state, which will be passed + * as-is as the first argument to the other callbacks. + * + * Input parameters: + * + * port: The client Port. + * + * mech: The actual mechanism name in use by the client. + * + * shadow_pass: The stored secret for the role being authenticated, or + * NULL if one does not exist. Mechanisms that do not use + * shadow entries may ignore this parameter. If a + * mechanism uses shadow entries but shadow_pass is NULL, + * the implementation must continue the exchange as if the + * user existed and the password did not match, to avoid + * disclosing valid user names. + *--------- + */ + void *(*init) (Port *port, const char *mech, const char *shadow_pass); + + /*--------- + * exchange() + * + * Produces a server challenge to be sent to the client. The callback + * must return one of the PG_SASL_EXCHANGE_* values, depending on + * whether the exchange continues, has finished successfully, or has + * failed. + * + * Input parameters: + * + * state: The opaque mechanism state returned by init() + * + * input: The response data sent by the client, or NULL if the + * mechanism is client-first but the client did not send an + * initial response. (This can only happen during the first + * message from the client.) This is guaranteed to be + * null-terminated for safety, but SASL allows embedded + * nulls in responses, so mechanisms must be careful to + * check inputlen. + * + * inputlen: The length of the challenge data sent by the server, or + * -1 if the client did not send an initial response + * + * Output parameters, to be set by the callback function: + * + * output: A palloc'd buffer containing either the server's next + * challenge (if PG_SASL_EXCHANGE_CONTINUE is returned) or + * the server's outcome data (if PG_SASL_EXCHANGE_SUCCESS is + * returned and the mechanism requires data to be sent during + * a successful outcome). The callback should set this to + * NULL if the exchange is over and no output should be sent, + * which should correspond to either PG_SASL_EXCHANGE_FAILURE + * or a PG_SASL_EXCHANGE_SUCCESS with no outcome data. + * + * outputlen: The length of the challenge data. Ignored if *output is + * NULL. + * + * logdetail: Set to an optional DETAIL message to be printed to the + * server log, to disambiguate failure modes. (The client + * will only ever see the same generic authentication + * failure message.) Ignored if the exchange is completed + * with PG_SASL_EXCHANGE_SUCCESS. + *--------- + */ + int (*exchange) (void *state, + const char *input, int inputlen, + char **output, int *outputlen, + const char **logdetail); +} pg_be_sasl_mech; + +/* Common implementation for auth.c */ +extern int CheckSASLAuth(const pg_be_sasl_mech *mech, Port *port, + char *shadow_pass, const char **logdetail); + +#endif /* PG_SASL_H */ diff --git a/src/include/libpq/scram.h b/src/include/libpq/scram.h new file mode 100644 index 0000000..c51e848 --- /dev/null +++ b/src/include/libpq/scram.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * scram.h + * Interface to libpq/scram.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/libpq/scram.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SCRAM_H +#define PG_SCRAM_H + +#include "lib/stringinfo.h" +#include "libpq/libpq-be.h" +#include "libpq/sasl.h" + +/* SASL implementation callbacks */ +extern PGDLLIMPORT const pg_be_sasl_mech pg_be_scram_mech; + +/* Routines to handle and check SCRAM-SHA-256 secret */ +extern char *pg_be_scram_build_secret(const char *password); +extern bool parse_scram_secret(const char *secret, int *iterations, char **salt, + uint8 *stored_key, uint8 *server_key); +extern bool scram_verify_plain_password(const char *username, + const char *password, const char *secret); + +#endif /* PG_SCRAM_H */ diff --git a/src/include/mb/pg_wchar.h b/src/include/mb/pg_wchar.h new file mode 100644 index 0000000..31f5b39 --- /dev/null +++ b/src/include/mb/pg_wchar.h @@ -0,0 +1,755 @@ +/*------------------------------------------------------------------------- + * + * pg_wchar.h + * multibyte-character support + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/mb/pg_wchar.h + * + * NOTES + * This is used both by the backend and by frontends, but should not be + * included by libpq client programs. In particular, a libpq client + * should not assume that the encoding IDs used by the version of libpq + * it's linked to match up with the IDs declared here. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_WCHAR_H +#define PG_WCHAR_H + +/* + * The pg_wchar type + */ +typedef unsigned int pg_wchar; + +/* + * Maximum byte length of multibyte characters in any backend encoding + */ +#define MAX_MULTIBYTE_CHAR_LEN 4 + +/* + * various definitions for EUC + */ +#define SS2 0x8e /* single shift 2 (JIS0201) */ +#define SS3 0x8f /* single shift 3 (JIS0212) */ + +/* + * SJIS validation macros + */ +#define ISSJISHEAD(c) (((c) >= 0x81 && (c) <= 0x9f) || ((c) >= 0xe0 && (c) <= 0xfc)) +#define ISSJISTAIL(c) (((c) >= 0x40 && (c) <= 0x7e) || ((c) >= 0x80 && (c) <= 0xfc)) + +/*---------------------------------------------------- + * MULE Internal Encoding (MIC) + * + * This encoding follows the design used within XEmacs; it is meant to + * subsume many externally-defined character sets. Each character includes + * identification of the character set it belongs to, so the encoding is + * general but somewhat bulky. + * + * Currently PostgreSQL supports 5 types of MULE character sets: + * + * 1) 1-byte ASCII characters. Each byte is below 0x80. + * + * 2) "Official" single byte charsets such as ISO-8859-1 (Latin1). + * Each MULE character consists of 2 bytes: LC1 + C1, where LC1 is + * an identifier for the charset (in the range 0x81 to 0x8d) and C1 + * is the character code (in the range 0xa0 to 0xff). + * + * 3) "Private" single byte charsets such as SISHENG. Each MULE + * character consists of 3 bytes: LCPRV1 + LC12 + C1, where LCPRV1 + * is a private-charset flag, LC12 is an identifier for the charset, + * and C1 is the character code (in the range 0xa0 to 0xff). + * LCPRV1 is either 0x9a (if LC12 is in the range 0xa0 to 0xdf) + * or 0x9b (if LC12 is in the range 0xe0 to 0xef). + * + * 4) "Official" multibyte charsets such as JIS X0208. Each MULE + * character consists of 3 bytes: LC2 + C1 + C2, where LC2 is + * an identifier for the charset (in the range 0x90 to 0x99) and C1 + * and C2 form the character code (each in the range 0xa0 to 0xff). + * + * 5) "Private" multibyte charsets such as CNS 11643-1992 Plane 3. + * Each MULE character consists of 4 bytes: LCPRV2 + LC22 + C1 + C2, + * where LCPRV2 is a private-charset flag, LC22 is an identifier for + * the charset, and C1 and C2 form the character code (each in the range + * 0xa0 to 0xff). LCPRV2 is either 0x9c (if LC22 is in the range 0xf0 + * to 0xf4) or 0x9d (if LC22 is in the range 0xf5 to 0xfe). + * + * "Official" encodings are those that have been assigned code numbers by + * the XEmacs project; "private" encodings have Postgres-specific charset + * identifiers. + * + * See the "XEmacs Internals Manual", available at http://www.xemacs.org, + * for more details. Note that for historical reasons, Postgres' + * private-charset flag values do not match what XEmacs says they should be, + * so this isn't really exactly MULE (not that private charsets would be + * interoperable anyway). + * + * Note that XEmacs's implementation is different from what emacs does. + * We follow emacs's implementation, rather than XEmacs's. + *---------------------------------------------------- + */ + +/* + * Charset identifiers (also called "leading bytes" in the MULE documentation) + */ + +/* + * Charset IDs for official single byte encodings (0x81-0x8e) + */ +#define LC_ISO8859_1 0x81 /* ISO8859 Latin 1 */ +#define LC_ISO8859_2 0x82 /* ISO8859 Latin 2 */ +#define LC_ISO8859_3 0x83 /* ISO8859 Latin 3 */ +#define LC_ISO8859_4 0x84 /* ISO8859 Latin 4 */ +#define LC_TIS620 0x85 /* Thai (not supported yet) */ +#define LC_ISO8859_7 0x86 /* Greek (not supported yet) */ +#define LC_ISO8859_6 0x87 /* Arabic (not supported yet) */ +#define LC_ISO8859_8 0x88 /* Hebrew (not supported yet) */ +#define LC_JISX0201K 0x89 /* Japanese 1 byte kana */ +#define LC_JISX0201R 0x8a /* Japanese 1 byte Roman */ +/* Note that 0x8b seems to be unused as of Emacs 20.7. + * However, there might be a chance that 0x8b could be used + * in later versions of Emacs. + */ +#define LC_KOI8_R 0x8b /* Cyrillic KOI8-R */ +#define LC_ISO8859_5 0x8c /* ISO8859 Cyrillic */ +#define LC_ISO8859_9 0x8d /* ISO8859 Latin 5 (not supported yet) */ +#define LC_ISO8859_15 0x8e /* ISO8859 Latin 15 (not supported yet) */ +/* #define CONTROL_1 0x8f control characters (unused) */ + +/* Is a leading byte for "official" single byte encodings? */ +#define IS_LC1(c) ((unsigned char)(c) >= 0x81 && (unsigned char)(c) <= 0x8d) + +/* + * Charset IDs for official multibyte encodings (0x90-0x99) + * 0x9a-0x9d are free. 0x9e and 0x9f are reserved. + */ +#define LC_JISX0208_1978 0x90 /* Japanese Kanji, old JIS (not supported) */ +#define LC_GB2312_80 0x91 /* Chinese */ +#define LC_JISX0208 0x92 /* Japanese Kanji (JIS X 0208) */ +#define LC_KS5601 0x93 /* Korean */ +#define LC_JISX0212 0x94 /* Japanese Kanji (JIS X 0212) */ +#define LC_CNS11643_1 0x95 /* CNS 11643-1992 Plane 1 */ +#define LC_CNS11643_2 0x96 /* CNS 11643-1992 Plane 2 */ +#define LC_JISX0213_1 0x97 /* Japanese Kanji (JIS X 0213 Plane 1) + * (not supported) */ +#define LC_BIG5_1 0x98 /* Plane 1 Chinese traditional (not + * supported) */ +#define LC_BIG5_2 0x99 /* Plane 1 Chinese traditional (not + * supported) */ + +/* Is a leading byte for "official" multibyte encodings? */ +#define IS_LC2(c) ((unsigned char)(c) >= 0x90 && (unsigned char)(c) <= 0x99) + +/* + * Postgres-specific prefix bytes for "private" single byte encodings + * (According to the MULE docs, we should be using 0x9e for this) + */ +#define LCPRV1_A 0x9a +#define LCPRV1_B 0x9b +#define IS_LCPRV1(c) ((unsigned char)(c) == LCPRV1_A || (unsigned char)(c) == LCPRV1_B) +#define IS_LCPRV1_A_RANGE(c) \ + ((unsigned char)(c) >= 0xa0 && (unsigned char)(c) <= 0xdf) +#define IS_LCPRV1_B_RANGE(c) \ + ((unsigned char)(c) >= 0xe0 && (unsigned char)(c) <= 0xef) + +/* + * Postgres-specific prefix bytes for "private" multibyte encodings + * (According to the MULE docs, we should be using 0x9f for this) + */ +#define LCPRV2_A 0x9c +#define LCPRV2_B 0x9d +#define IS_LCPRV2(c) ((unsigned char)(c) == LCPRV2_A || (unsigned char)(c) == LCPRV2_B) +#define IS_LCPRV2_A_RANGE(c) \ + ((unsigned char)(c) >= 0xf0 && (unsigned char)(c) <= 0xf4) +#define IS_LCPRV2_B_RANGE(c) \ + ((unsigned char)(c) >= 0xf5 && (unsigned char)(c) <= 0xfe) + +/* + * Charset IDs for private single byte encodings (0xa0-0xef) + */ +#define LC_SISHENG 0xa0 /* Chinese SiSheng characters for + * PinYin/ZhuYin (not supported) */ +#define LC_IPA 0xa1 /* IPA (International Phonetic + * Association) (not supported) */ +#define LC_VISCII_LOWER 0xa2 /* Vietnamese VISCII1.1 lower-case (not + * supported) */ +#define LC_VISCII_UPPER 0xa3 /* Vietnamese VISCII1.1 upper-case (not + * supported) */ +#define LC_ARABIC_DIGIT 0xa4 /* Arabic digit (not supported) */ +#define LC_ARABIC_1_COLUMN 0xa5 /* Arabic 1-column (not supported) */ +#define LC_ASCII_RIGHT_TO_LEFT 0xa6 /* ASCII (left half of ISO8859-1) with + * right-to-left direction (not + * supported) */ +#define LC_LAO 0xa7 /* Lao characters (ISO10646 0E80..0EDF) + * (not supported) */ +#define LC_ARABIC_2_COLUMN 0xa8 /* Arabic 1-column (not supported) */ + +/* + * Charset IDs for private multibyte encodings (0xf0-0xff) + */ +#define LC_INDIAN_1_COLUMN 0xf0 /* Indian charset for 1-column width + * glyphs (not supported) */ +#define LC_TIBETAN_1_COLUMN 0xf1 /* Tibetan 1-column width glyphs (not + * supported) */ +#define LC_UNICODE_SUBSET_2 0xf2 /* Unicode characters of the range + * U+2500..U+33FF. (not supported) */ +#define LC_UNICODE_SUBSET_3 0xf3 /* Unicode characters of the range + * U+E000..U+FFFF. (not supported) */ +#define LC_UNICODE_SUBSET 0xf4 /* Unicode characters of the range + * U+0100..U+24FF. (not supported) */ +#define LC_ETHIOPIC 0xf5 /* Ethiopic characters (not supported) */ +#define LC_CNS11643_3 0xf6 /* CNS 11643-1992 Plane 3 */ +#define LC_CNS11643_4 0xf7 /* CNS 11643-1992 Plane 4 */ +#define LC_CNS11643_5 0xf8 /* CNS 11643-1992 Plane 5 */ +#define LC_CNS11643_6 0xf9 /* CNS 11643-1992 Plane 6 */ +#define LC_CNS11643_7 0xfa /* CNS 11643-1992 Plane 7 */ +#define LC_INDIAN_2_COLUMN 0xfb /* Indian charset for 2-column width + * glyphs (not supported) */ +#define LC_TIBETAN 0xfc /* Tibetan (not supported) */ +/* #define FREE 0xfd free (unused) */ +/* #define FREE 0xfe free (unused) */ +/* #define FREE 0xff free (unused) */ + +/*---------------------------------------------------- + * end of MULE stuff + *---------------------------------------------------- + */ + +/* + * PostgreSQL encoding identifiers + * + * WARNING: the order of this enum must be same as order of entries + * in the pg_enc2name_tbl[] array (in src/common/encnames.c), and + * in the pg_wchar_table[] array (in src/common/wchar.c)! + * + * If you add some encoding don't forget to check + * PG_ENCODING_BE_LAST macro. + * + * PG_SQL_ASCII is default encoding and must be = 0. + * + * XXX We must avoid renumbering any backend encoding until libpq's major + * version number is increased beyond 5; it turns out that the backend + * encoding IDs are effectively part of libpq's ABI as far as 8.2 initdb and + * psql are concerned. + */ +typedef enum pg_enc +{ + PG_SQL_ASCII = 0, /* SQL/ASCII */ + PG_EUC_JP, /* EUC for Japanese */ + PG_EUC_CN, /* EUC for Chinese */ + PG_EUC_KR, /* EUC for Korean */ + PG_EUC_TW, /* EUC for Taiwan */ + PG_EUC_JIS_2004, /* EUC-JIS-2004 */ + PG_UTF8, /* Unicode UTF8 */ + PG_MULE_INTERNAL, /* Mule internal code */ + PG_LATIN1, /* ISO-8859-1 Latin 1 */ + PG_LATIN2, /* ISO-8859-2 Latin 2 */ + PG_LATIN3, /* ISO-8859-3 Latin 3 */ + PG_LATIN4, /* ISO-8859-4 Latin 4 */ + PG_LATIN5, /* ISO-8859-9 Latin 5 */ + PG_LATIN6, /* ISO-8859-10 Latin6 */ + PG_LATIN7, /* ISO-8859-13 Latin7 */ + PG_LATIN8, /* ISO-8859-14 Latin8 */ + PG_LATIN9, /* ISO-8859-15 Latin9 */ + PG_LATIN10, /* ISO-8859-16 Latin10 */ + PG_WIN1256, /* windows-1256 */ + PG_WIN1258, /* Windows-1258 */ + PG_WIN866, /* (MS-DOS CP866) */ + PG_WIN874, /* windows-874 */ + PG_KOI8R, /* KOI8-R */ + PG_WIN1251, /* windows-1251 */ + PG_WIN1252, /* windows-1252 */ + PG_ISO_8859_5, /* ISO-8859-5 */ + PG_ISO_8859_6, /* ISO-8859-6 */ + PG_ISO_8859_7, /* ISO-8859-7 */ + PG_ISO_8859_8, /* ISO-8859-8 */ + PG_WIN1250, /* windows-1250 */ + PG_WIN1253, /* windows-1253 */ + PG_WIN1254, /* windows-1254 */ + PG_WIN1255, /* windows-1255 */ + PG_WIN1257, /* windows-1257 */ + PG_KOI8U, /* KOI8-U */ + /* PG_ENCODING_BE_LAST points to the above entry */ + + /* followings are for client encoding only */ + PG_SJIS, /* Shift JIS (Windows-932) */ + PG_BIG5, /* Big5 (Windows-950) */ + PG_GBK, /* GBK (Windows-936) */ + PG_UHC, /* UHC (Windows-949) */ + PG_GB18030, /* GB18030 */ + PG_JOHAB, /* EUC for Korean JOHAB */ + PG_SHIFT_JIS_2004, /* Shift-JIS-2004 */ + _PG_LAST_ENCODING_ /* mark only */ + +} pg_enc; + +#define PG_ENCODING_BE_LAST PG_KOI8U + +/* + * Please use these tests before access to pg_enc2name_tbl[] + * or to other places... + */ +#define PG_VALID_BE_ENCODING(_enc) \ + ((_enc) >= 0 && (_enc) <= PG_ENCODING_BE_LAST) + +#define PG_ENCODING_IS_CLIENT_ONLY(_enc) \ + ((_enc) > PG_ENCODING_BE_LAST && (_enc) < _PG_LAST_ENCODING_) + +#define PG_VALID_ENCODING(_enc) \ + ((_enc) >= 0 && (_enc) < _PG_LAST_ENCODING_) + +/* On FE are possible all encodings */ +#define PG_VALID_FE_ENCODING(_enc) PG_VALID_ENCODING(_enc) + +/* + * When converting strings between different encodings, we assume that space + * for converted result is 4-to-1 growth in the worst case. The rate for + * currently supported encoding pairs are within 3 (SJIS JIS X0201 half width + * kana -> UTF8 is the worst case). So "4" should be enough for the moment. + * + * Note that this is not the same as the maximum character width in any + * particular encoding. + */ +#define MAX_CONVERSION_GROWTH 4 + +/* + * Maximum byte length of a string that's required in any encoding to convert + * at least one character to any other encoding. In other words, if you feed + * MAX_CONVERSION_INPUT_LENGTH bytes to any encoding conversion function, it + * is guaranteed to be able to convert something without needing more input + * (assuming the input is valid). + * + * Currently, the maximum case is the conversion UTF8 -> SJIS JIS X0201 half + * width kana, where a pair of UTF-8 characters is converted into a single + * SHIFT_JIS_2004 character (the reverse of the worst case for + * MAX_CONVERSION_GROWTH). It needs 6 bytes of input. In theory, a + * user-defined conversion function might have more complicated cases, although + * for the reverse mapping you would probably also need to bump up + * MAX_CONVERSION_GROWTH. But there is no need to be stingy here, so make it + * generous. + */ +#define MAX_CONVERSION_INPUT_LENGTH 16 + +/* + * Maximum byte length of the string equivalent to any one Unicode code point, + * in any backend encoding. The current value assumes that a 4-byte UTF-8 + * character might expand by MAX_CONVERSION_GROWTH, which is a huge + * overestimate. But in current usage we don't allocate large multiples of + * this, so there's little point in being stingy. + */ +#define MAX_UNICODE_EQUIVALENT_STRING 16 + +/* + * Table for mapping an encoding number to official encoding name and + * possibly other subsidiary data. Be careful to check encoding number + * before accessing a table entry! + * + * if (PG_VALID_ENCODING(encoding)) + * pg_enc2name_tbl[ encoding ]; + */ +typedef struct pg_enc2name +{ + const char *name; + pg_enc encoding; +#ifdef WIN32 + unsigned codepage; /* codepage for WIN32 */ +#endif +} pg_enc2name; + +extern PGDLLIMPORT const pg_enc2name pg_enc2name_tbl[]; + +/* + * Encoding names for gettext + */ +typedef struct pg_enc2gettext +{ + pg_enc encoding; + const char *name; +} pg_enc2gettext; + +extern PGDLLIMPORT const pg_enc2gettext pg_enc2gettext_tbl[]; + +/* + * pg_wchar stuff + */ +typedef int (*mb2wchar_with_len_converter) (const unsigned char *from, + pg_wchar *to, + int len); + +typedef int (*wchar2mb_with_len_converter) (const pg_wchar *from, + unsigned char *to, + int len); + +typedef int (*mblen_converter) (const unsigned char *mbstr); + +typedef int (*mbdisplaylen_converter) (const unsigned char *mbstr); + +typedef bool (*mbcharacter_incrementer) (unsigned char *mbstr, int len); + +typedef int (*mbchar_verifier) (const unsigned char *mbstr, int len); + +typedef int (*mbstr_verifier) (const unsigned char *mbstr, int len); + +typedef struct +{ + mb2wchar_with_len_converter mb2wchar_with_len; /* convert a multibyte + * string to a wchar */ + wchar2mb_with_len_converter wchar2mb_with_len; /* convert a wchar string + * to a multibyte */ + mblen_converter mblen; /* get byte length of a char */ + mbdisplaylen_converter dsplen; /* get display width of a char */ + mbchar_verifier mbverifychar; /* verify multibyte character */ + mbstr_verifier mbverifystr; /* verify multibyte string */ + int maxmblen; /* max bytes for a char in this encoding */ +} pg_wchar_tbl; + +extern PGDLLIMPORT const pg_wchar_tbl pg_wchar_table[]; + +/* + * Data structures for conversions between UTF-8 and other encodings + * (UtfToLocal() and LocalToUtf()). In these data structures, characters of + * either encoding are represented by uint32 words; hence we can only support + * characters up to 4 bytes long. For example, the byte sequence 0xC2 0x89 + * would be represented by 0x0000C289, and 0xE8 0xA2 0xB4 by 0x00E8A2B4. + * + * There are three possible ways a character can be mapped: + * + * 1. Using a radix tree, from source to destination code. + * 2. Using a sorted array of source -> destination code pairs. This + * method is used for "combining" characters. There are so few of + * them that building a radix tree would be wasteful. + * 3. Using a conversion function. + */ + +/* + * Radix tree for character conversion. + * + * Logically, this is actually four different radix trees, for 1-byte, + * 2-byte, 3-byte and 4-byte inputs. The 1-byte tree is a simple lookup + * table from source to target code. The 2-byte tree consists of two levels: + * one lookup table for the first byte, where the value in the lookup table + * points to a lookup table for the second byte. And so on. + * + * Physically, all the trees are stored in one big array, in 'chars16' or + * 'chars32', depending on the maximum value that needs to be represented. For + * each level in each tree, we also store lower and upper bound of allowed + * values - values outside those bounds are considered invalid, and are left + * out of the tables. + * + * In the intermediate levels of the trees, the values stored are offsets + * into the chars[16|32] array. + * + * In the beginning of the chars[16|32] array, there is always a number of + * zeros, so that you safely follow an index from an intermediate table + * without explicitly checking for a zero. Following a zero any number of + * times will always bring you to the dummy, all-zeros table in the + * beginning. This helps to shave some cycles when looking up values. + */ +typedef struct +{ + /* + * Array containing all the values. Only one of chars16 or chars32 is + * used, depending on how wide the values we need to represent are. + */ + const uint16 *chars16; + const uint32 *chars32; + + /* Radix tree for 1-byte inputs */ + uint32 b1root; /* offset of table in the chars[16|32] array */ + uint8 b1_lower; /* min allowed value for a single byte input */ + uint8 b1_upper; /* max allowed value for a single byte input */ + + /* Radix tree for 2-byte inputs */ + uint32 b2root; /* offset of 1st byte's table */ + uint8 b2_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b2_1_upper; + uint8 b2_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b2_2_upper; + + /* Radix tree for 3-byte inputs */ + uint32 b3root; /* offset of 1st byte's table */ + uint8 b3_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b3_1_upper; + uint8 b3_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b3_2_upper; + uint8 b3_3_lower; /* min/max allowed value for 3rd input byte */ + uint8 b3_3_upper; + + /* Radix tree for 4-byte inputs */ + uint32 b4root; /* offset of 1st byte's table */ + uint8 b4_1_lower; /* min/max allowed value for 1st input byte */ + uint8 b4_1_upper; + uint8 b4_2_lower; /* min/max allowed value for 2nd input byte */ + uint8 b4_2_upper; + uint8 b4_3_lower; /* min/max allowed value for 3rd input byte */ + uint8 b4_3_upper; + uint8 b4_4_lower; /* min/max allowed value for 4th input byte */ + uint8 b4_4_upper; + +} pg_mb_radix_tree; + +/* + * UTF-8 to local code conversion map (for combined characters) + */ +typedef struct +{ + uint32 utf1; /* UTF-8 code 1 */ + uint32 utf2; /* UTF-8 code 2 */ + uint32 code; /* local code */ +} pg_utf_to_local_combined; + +/* + * local code to UTF-8 conversion map (for combined characters) + */ +typedef struct +{ + uint32 code; /* local code */ + uint32 utf1; /* UTF-8 code 1 */ + uint32 utf2; /* UTF-8 code 2 */ +} pg_local_to_utf_combined; + +/* + * callback function for algorithmic encoding conversions (in either direction) + * + * if function returns zero, it does not know how to convert the code + */ +typedef uint32 (*utf_local_conversion_func) (uint32 code); + +/* + * Support macro for encoding conversion functions to validate their + * arguments. (This could be made more compact if we included fmgr.h + * here, but we don't want to do that because this header file is also + * used by frontends.) + */ +#define CHECK_ENCODING_CONVERSION_ARGS(srcencoding,destencoding) \ + check_encoding_conversion_args(PG_GETARG_INT32(0), \ + PG_GETARG_INT32(1), \ + PG_GETARG_INT32(4), \ + (srcencoding), \ + (destencoding)) + + +/* + * Some handy functions for Unicode-specific tests. + */ +static inline bool +is_valid_unicode_codepoint(pg_wchar c) +{ + return (c > 0 && c <= 0x10FFFF); +} + +static inline bool +is_utf16_surrogate_first(pg_wchar c) +{ + return (c >= 0xD800 && c <= 0xDBFF); +} + +static inline bool +is_utf16_surrogate_second(pg_wchar c) +{ + return (c >= 0xDC00 && c <= 0xDFFF); +} + +static inline pg_wchar +surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second) +{ + return ((first & 0x3FF) << 10) + 0x10000 + (second & 0x3FF); +} + + +/* + * These functions are considered part of libpq's exported API and + * are also declared in libpq-fe.h. + */ +extern int pg_char_to_encoding(const char *name); +extern const char *pg_encoding_to_char(int encoding); +extern int pg_valid_server_encoding_id(int encoding); + +/* + * These functions are available to frontend code that links with libpgcommon + * (in addition to the ones just above). The constant tables declared + * earlier in this file are also available from libpgcommon. + */ +extern int pg_encoding_mblen(int encoding, const char *mbstr); +extern int pg_encoding_mblen_bounded(int encoding, const char *mbstr); +extern int pg_encoding_dsplen(int encoding, const char *mbstr); +extern int pg_encoding_verifymbchar(int encoding, const char *mbstr, int len); +extern int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len); +extern int pg_encoding_max_length(int encoding); +extern int pg_valid_client_encoding(const char *name); +extern int pg_valid_server_encoding(const char *name); +extern bool is_encoding_supported_by_icu(int encoding); +extern const char *get_encoding_name_for_icu(int encoding); + +extern unsigned char *unicode_to_utf8(pg_wchar c, unsigned char *utf8string); +extern pg_wchar utf8_to_unicode(const unsigned char *c); +extern bool pg_utf8_islegal(const unsigned char *source, int length); +extern int pg_utf_mblen(const unsigned char *s); +extern int pg_mule_mblen(const unsigned char *s); + +/* + * The remaining functions are backend-only. + */ +extern int pg_mb2wchar(const char *from, pg_wchar *to); +extern int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len); +extern int pg_encoding_mb2wchar_with_len(int encoding, + const char *from, pg_wchar *to, int len); +extern int pg_wchar2mb(const pg_wchar *from, char *to); +extern int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len); +extern int pg_encoding_wchar2mb_with_len(int encoding, + const pg_wchar *from, char *to, int len); +extern int pg_char_and_wchar_strcmp(const char *s1, const pg_wchar *s2); +extern int pg_wchar_strncmp(const pg_wchar *s1, const pg_wchar *s2, size_t n); +extern int pg_char_and_wchar_strncmp(const char *s1, const pg_wchar *s2, size_t n); +extern size_t pg_wchar_strlen(const pg_wchar *wstr); +extern int pg_mblen(const char *mbstr); +extern int pg_dsplen(const char *mbstr); +extern int pg_mbstrlen(const char *mbstr); +extern int pg_mbstrlen_with_len(const char *mbstr, int len); +extern int pg_mbcliplen(const char *mbstr, int len, int limit); +extern int pg_encoding_mbcliplen(int encoding, const char *mbstr, + int len, int limit); +extern int pg_mbcharcliplen(const char *mbstr, int len, int limit); +extern int pg_database_encoding_max_length(void); +extern mbcharacter_incrementer pg_database_encoding_character_incrementer(void); + +extern int PrepareClientEncoding(int encoding); +extern int SetClientEncoding(int encoding); +extern void InitializeClientEncoding(void); +extern int pg_get_client_encoding(void); +extern const char *pg_get_client_encoding_name(void); + +extern void SetDatabaseEncoding(int encoding); +extern int GetDatabaseEncoding(void); +extern const char *GetDatabaseEncodingName(void); +extern void SetMessageEncoding(int encoding); +extern int GetMessageEncoding(void); + +#ifdef ENABLE_NLS +extern int pg_bind_textdomain_codeset(const char *domainname); +#endif + +extern unsigned char *pg_do_encoding_conversion(unsigned char *src, int len, + int src_encoding, + int dest_encoding); +extern int pg_do_encoding_conversion_buf(Oid proc, + int src_encoding, + int dest_encoding, + unsigned char *src, int srclen, + unsigned char *dst, int dstlen, + bool noError); + +extern char *pg_client_to_server(const char *s, int len); +extern char *pg_server_to_client(const char *s, int len); +extern char *pg_any_to_server(const char *s, int len, int encoding); +extern char *pg_server_to_any(const char *s, int len, int encoding); + +extern void pg_unicode_to_server(pg_wchar c, unsigned char *s); + +extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc); +extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc); + +extern int UtfToLocal(const unsigned char *utf, int len, + unsigned char *iso, + const pg_mb_radix_tree *map, + const pg_utf_to_local_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding, bool noError); +extern int LocalToUtf(const unsigned char *iso, int len, + unsigned char *utf, + const pg_mb_radix_tree *map, + const pg_local_to_utf_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding, bool noError); + +extern bool pg_verifymbstr(const char *mbstr, int len, bool noError); +extern bool pg_verify_mbstr(int encoding, const char *mbstr, int len, + bool noError); +extern int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, + bool noError); + +extern void check_encoding_conversion_args(int src_encoding, + int dest_encoding, + int len, + int expected_src_encoding, + int expected_dest_encoding); + +extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn(); +extern void report_untranslatable_char(int src_encoding, int dest_encoding, + const char *mbstr, int len) pg_attribute_noreturn(); + +extern int local2local(const unsigned char *l, unsigned char *p, int len, + int src_encoding, int dest_encoding, + const unsigned char *tab, bool noError); +extern int latin2mic(const unsigned char *l, unsigned char *p, int len, + int lc, int encoding, bool noError); +extern int mic2latin(const unsigned char *mic, unsigned char *p, int len, + int lc, int encoding, bool noError); +extern int latin2mic_with_table(const unsigned char *l, unsigned char *p, + int len, int lc, int encoding, + const unsigned char *tab, bool noError); +extern int mic2latin_with_table(const unsigned char *mic, unsigned char *p, + int len, int lc, int encoding, + const unsigned char *tab, bool noError); + +#ifdef WIN32 +extern WCHAR *pgwin32_message_to_UTF16(const char *str, int len, int *utf16len); +#endif + + +/* + * Verify a chunk of bytes for valid ASCII. + * + * Returns false if the input contains any zero bytes or bytes with the + * high-bit set. Input len must be a multiple of 8. + */ +static inline bool +is_valid_ascii(const unsigned char *s, int len) +{ + uint64 chunk, + highbit_cum = UINT64CONST(0), + zero_cum = UINT64CONST(0x8080808080808080); + + Assert(len % sizeof(chunk) == 0); + + while (len > 0) + { + memcpy(&chunk, s, sizeof(chunk)); + + /* + * Capture any zero bytes in this chunk. + * + * First, add 0x7f to each byte. This sets the high bit in each byte, + * unless it was a zero. If any resulting high bits are zero, the + * corresponding high bits in the zero accumulator will be cleared. + * + * If none of the bytes in the chunk had the high bit set, the max + * value each byte can have after the addition is 0x7f + 0x7f = 0xfe, + * and we don't need to worry about carrying over to the next byte. If + * any input bytes did have the high bit set, it doesn't matter + * because we check for those separately. + */ + zero_cum &= (chunk + UINT64CONST(0x7f7f7f7f7f7f7f7f)); + + /* Capture any set bits in this chunk. */ + highbit_cum |= chunk; + + s += sizeof(chunk); + len -= sizeof(chunk); + } + + /* Check if any high bits in the high bit accumulator got set. */ + if (highbit_cum & UINT64CONST(0x8080808080808080)) + return false; + + /* Check if any high bits in the zero accumulator got cleared. */ + if (zero_cum != UINT64CONST(0x8080808080808080)) + return false; + + return true; +} + +#endif /* PG_WCHAR_H */ diff --git a/src/include/mb/stringinfo_mb.h b/src/include/mb/stringinfo_mb.h new file mode 100644 index 0000000..8781ffd --- /dev/null +++ b/src/include/mb/stringinfo_mb.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * stringinfo_mb.h + * multibyte support for StringInfo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/mb/stringinfo_mb.h + *------------------------------------------------------------------------- + */ +#ifndef STRINGINFO_MB_H +#define STRINGINFO_MB_H + + +#include "lib/stringinfo.h" + +/* + * Multibyte-aware StringInfo support function. + */ +extern void appendStringInfoStringQuoted(StringInfo str, + const char *s, int maxlen); + +#endif /* STRINGINFO_MB_H */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h new file mode 100644 index 0000000..3233278 --- /dev/null +++ b/src/include/miscadmin.h @@ -0,0 +1,495 @@ +/*------------------------------------------------------------------------- + * + * miscadmin.h + * This file contains general postgres administration and initialization + * stuff that used to be spread out between the following files: + * globals.h global variables + * pdir.h directory path crud + * pinit.h postgres initialization + * pmod.h processing modes + * Over time, this has also become the preferred place for widely known + * resource-limitation stuff, such as work_mem and check_stack_depth(). + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/miscadmin.h + * + * NOTES + * some of the information in this file should be moved to other files. + * + *------------------------------------------------------------------------- + */ +#ifndef MISCADMIN_H +#define MISCADMIN_H + +#include <signal.h> + +#include "datatype/timestamp.h" /* for TimestampTz */ +#include "pgtime.h" /* for pg_time_t */ + + +#define InvalidPid (-1) + + +/***************************************************************************** + * System interrupt and critical section handling + * + * There are two types of interrupts that a running backend needs to accept + * without messing up its state: QueryCancel (SIGINT) and ProcDie (SIGTERM). + * In both cases, we need to be able to clean up the current transaction + * gracefully, so we can't respond to the interrupt instantaneously --- + * there's no guarantee that internal data structures would be self-consistent + * if the code is interrupted at an arbitrary instant. Instead, the signal + * handlers set flags that are checked periodically during execution. + * + * The CHECK_FOR_INTERRUPTS() macro is called at strategically located spots + * where it is normally safe to accept a cancel or die interrupt. In some + * cases, we invoke CHECK_FOR_INTERRUPTS() inside low-level subroutines that + * might sometimes be called in contexts that do *not* want to allow a cancel + * or die interrupt. The HOLD_INTERRUPTS() and RESUME_INTERRUPTS() macros + * allow code to ensure that no cancel or die interrupt will be accepted, + * even if CHECK_FOR_INTERRUPTS() gets called in a subroutine. The interrupt + * will be held off until CHECK_FOR_INTERRUPTS() is done outside any + * HOLD_INTERRUPTS() ... RESUME_INTERRUPTS() section. + * + * There is also a mechanism to prevent query cancel interrupts, while still + * allowing die interrupts: HOLD_CANCEL_INTERRUPTS() and + * RESUME_CANCEL_INTERRUPTS(). + * + * Note that ProcessInterrupts() has also acquired a number of tasks that + * do not necessarily cause a query-cancel-or-die response. Hence, it's + * possible that it will just clear InterruptPending and return. + * + * INTERRUPTS_PENDING_CONDITION() can be checked to see whether an + * interrupt needs to be serviced, without trying to do so immediately. + * Some callers are also interested in INTERRUPTS_CAN_BE_PROCESSED(), + * which tells whether ProcessInterrupts is sure to clear the interrupt. + * + * Special mechanisms are used to let an interrupt be accepted when we are + * waiting for a lock or when we are waiting for command input (but, of + * course, only if the interrupt holdoff counter is zero). See the + * related code for details. + * + * A lost connection is handled similarly, although the loss of connection + * does not raise a signal, but is detected when we fail to write to the + * socket. If there was a signal for a broken connection, we could make use of + * it by setting ClientConnectionLost in the signal handler. + * + * A related, but conceptually distinct, mechanism is the "critical section" + * mechanism. A critical section not only holds off cancel/die interrupts, + * but causes any ereport(ERROR) or ereport(FATAL) to become ereport(PANIC) + * --- that is, a system-wide reset is forced. Needless to say, only really + * *critical* code should be marked as a critical section! Currently, this + * mechanism is only used for XLOG-related code. + * + *****************************************************************************/ + +/* in globals.c */ +/* these are marked volatile because they are set by signal handlers: */ +extern PGDLLIMPORT volatile sig_atomic_t InterruptPending; +extern PGDLLIMPORT volatile sig_atomic_t QueryCancelPending; +extern PGDLLIMPORT volatile sig_atomic_t ProcDiePending; +extern PGDLLIMPORT volatile sig_atomic_t IdleInTransactionSessionTimeoutPending; +extern PGDLLIMPORT volatile sig_atomic_t IdleSessionTimeoutPending; +extern PGDLLIMPORT volatile sig_atomic_t ProcSignalBarrierPending; +extern PGDLLIMPORT volatile sig_atomic_t LogMemoryContextPending; +extern PGDLLIMPORT volatile sig_atomic_t IdleStatsUpdateTimeoutPending; + +extern PGDLLIMPORT volatile sig_atomic_t CheckClientConnectionPending; +extern PGDLLIMPORT volatile sig_atomic_t ClientConnectionLost; + +/* these are marked volatile because they are examined by signal handlers: */ +extern PGDLLIMPORT volatile uint32 InterruptHoldoffCount; +extern PGDLLIMPORT volatile uint32 QueryCancelHoldoffCount; +extern PGDLLIMPORT volatile uint32 CritSectionCount; + +/* in tcop/postgres.c */ +extern void ProcessInterrupts(void); + +/* Test whether an interrupt is pending */ +#ifndef WIN32 +#define INTERRUPTS_PENDING_CONDITION() \ + (unlikely(InterruptPending)) +#else +#define INTERRUPTS_PENDING_CONDITION() \ + (unlikely(UNBLOCKED_SIGNAL_QUEUE()) ? pgwin32_dispatch_queued_signals() : 0, \ + unlikely(InterruptPending)) +#endif + +/* Service interrupt, if one is pending and it's safe to service it now */ +#define CHECK_FOR_INTERRUPTS() \ +do { \ + if (INTERRUPTS_PENDING_CONDITION()) \ + ProcessInterrupts(); \ +} while(0) + +/* Is ProcessInterrupts() guaranteed to clear InterruptPending? */ +#define INTERRUPTS_CAN_BE_PROCESSED() \ + (InterruptHoldoffCount == 0 && CritSectionCount == 0 && \ + QueryCancelHoldoffCount == 0) + +#define HOLD_INTERRUPTS() (InterruptHoldoffCount++) + +#define RESUME_INTERRUPTS() \ +do { \ + Assert(InterruptHoldoffCount > 0); \ + InterruptHoldoffCount--; \ +} while(0) + +#define HOLD_CANCEL_INTERRUPTS() (QueryCancelHoldoffCount++) + +#define RESUME_CANCEL_INTERRUPTS() \ +do { \ + Assert(QueryCancelHoldoffCount > 0); \ + QueryCancelHoldoffCount--; \ +} while(0) + +#define START_CRIT_SECTION() (CritSectionCount++) + +#define END_CRIT_SECTION() \ +do { \ + Assert(CritSectionCount > 0); \ + CritSectionCount--; \ +} while(0) + + +/***************************************************************************** + * globals.h -- * + *****************************************************************************/ + +/* + * from utils/init/globals.c + */ +extern PGDLLIMPORT pid_t PostmasterPid; +extern PGDLLIMPORT bool IsPostmasterEnvironment; +extern PGDLLIMPORT bool IsUnderPostmaster; +extern PGDLLIMPORT bool IsBackgroundWorker; +extern PGDLLIMPORT bool IsBinaryUpgrade; + +extern PGDLLIMPORT bool ExitOnAnyError; + +extern PGDLLIMPORT char *DataDir; +extern PGDLLIMPORT int data_directory_mode; + +extern PGDLLIMPORT int NBuffers; +extern PGDLLIMPORT int MaxBackends; +extern PGDLLIMPORT int MaxConnections; +extern PGDLLIMPORT int max_worker_processes; +extern PGDLLIMPORT int max_parallel_workers; + +extern PGDLLIMPORT int MyProcPid; +extern PGDLLIMPORT pg_time_t MyStartTime; +extern PGDLLIMPORT TimestampTz MyStartTimestamp; +extern PGDLLIMPORT struct Port *MyProcPort; +extern PGDLLIMPORT struct Latch *MyLatch; +extern PGDLLIMPORT int32 MyCancelKey; +extern PGDLLIMPORT int MyPMChildSlot; + +extern PGDLLIMPORT char OutputFileName[]; +extern PGDLLIMPORT char my_exec_path[]; +extern PGDLLIMPORT char pkglib_path[]; + +#ifdef EXEC_BACKEND +extern PGDLLIMPORT char postgres_exec_path[]; +#endif + +/* + * done in storage/backendid.h for now. + * + * extern BackendId MyBackendId; + */ +extern PGDLLIMPORT Oid MyDatabaseId; + +extern PGDLLIMPORT Oid MyDatabaseTableSpace; + +/* + * Date/Time Configuration + * + * DateStyle defines the output formatting choice for date/time types: + * USE_POSTGRES_DATES specifies traditional Postgres format + * USE_ISO_DATES specifies ISO-compliant format + * USE_SQL_DATES specifies Oracle/Ingres-compliant format + * USE_GERMAN_DATES specifies German-style dd.mm/yyyy + * + * DateOrder defines the field order to be assumed when reading an + * ambiguous date (anything not in YYYY-MM-DD format, with a four-digit + * year field first, is taken to be ambiguous): + * DATEORDER_YMD specifies field order yy-mm-dd + * DATEORDER_DMY specifies field order dd-mm-yy ("European" convention) + * DATEORDER_MDY specifies field order mm-dd-yy ("US" convention) + * + * In the Postgres and SQL DateStyles, DateOrder also selects output field + * order: day comes before month in DMY style, else month comes before day. + * + * The user-visible "DateStyle" run-time parameter subsumes both of these. + */ + +/* valid DateStyle values */ +#define USE_POSTGRES_DATES 0 +#define USE_ISO_DATES 1 +#define USE_SQL_DATES 2 +#define USE_GERMAN_DATES 3 +#define USE_XSD_DATES 4 + +/* valid DateOrder values */ +#define DATEORDER_YMD 0 +#define DATEORDER_DMY 1 +#define DATEORDER_MDY 2 + +extern PGDLLIMPORT int DateStyle; +extern PGDLLIMPORT int DateOrder; + +/* + * IntervalStyles + * INTSTYLE_POSTGRES Like Postgres < 8.4 when DateStyle = 'iso' + * INTSTYLE_POSTGRES_VERBOSE Like Postgres < 8.4 when DateStyle != 'iso' + * INTSTYLE_SQL_STANDARD SQL standard interval literals + * INTSTYLE_ISO_8601 ISO-8601-basic formatted intervals + */ +#define INTSTYLE_POSTGRES 0 +#define INTSTYLE_POSTGRES_VERBOSE 1 +#define INTSTYLE_SQL_STANDARD 2 +#define INTSTYLE_ISO_8601 3 + +extern PGDLLIMPORT int IntervalStyle; + +#define MAXTZLEN 10 /* max TZ name len, not counting tr. null */ + +extern PGDLLIMPORT bool enableFsync; +extern PGDLLIMPORT bool allowSystemTableMods; +extern PGDLLIMPORT int work_mem; +extern PGDLLIMPORT double hash_mem_multiplier; +extern PGDLLIMPORT int maintenance_work_mem; +extern PGDLLIMPORT int max_parallel_maintenance_workers; + +extern PGDLLIMPORT int VacuumCostPageHit; +extern PGDLLIMPORT int VacuumCostPageMiss; +extern PGDLLIMPORT int VacuumCostPageDirty; +extern PGDLLIMPORT int VacuumCostLimit; +extern PGDLLIMPORT double VacuumCostDelay; + +extern PGDLLIMPORT int64 VacuumPageHit; +extern PGDLLIMPORT int64 VacuumPageMiss; +extern PGDLLIMPORT int64 VacuumPageDirty; + +extern PGDLLIMPORT int VacuumCostBalance; +extern PGDLLIMPORT bool VacuumCostActive; + + +/* in tcop/postgres.c */ + +#if defined(__ia64__) || defined(__ia64) +typedef struct +{ + char *stack_base_ptr; + char *register_stack_base_ptr; +} pg_stack_base_t; +#else +typedef char *pg_stack_base_t; +#endif + +extern pg_stack_base_t set_stack_base(void); +extern void restore_stack_base(pg_stack_base_t base); +extern void check_stack_depth(void); +extern bool stack_is_too_deep(void); + +/* in tcop/utility.c */ +extern void PreventCommandIfReadOnly(const char *cmdname); +extern void PreventCommandIfParallelMode(const char *cmdname); +extern void PreventCommandDuringRecovery(const char *cmdname); + +/* in utils/misc/guc.c */ +extern PGDLLIMPORT int trace_recovery_messages; +extern int trace_recovery(int trace_level); + +/***************************************************************************** + * pdir.h -- * + * POSTGRES directory path definitions. * + *****************************************************************************/ + +/* flags to be OR'd to form sec_context */ +#define SECURITY_LOCAL_USERID_CHANGE 0x0001 +#define SECURITY_RESTRICTED_OPERATION 0x0002 +#define SECURITY_NOFORCE_RLS 0x0004 + +extern PGDLLIMPORT char *DatabasePath; + +/* now in utils/init/miscinit.c */ +extern void InitPostmasterChild(void); +extern void InitStandaloneProcess(const char *argv0); +extern void SwitchToSharedLatch(void); +extern void SwitchBackToLocalLatch(void); + +typedef enum BackendType +{ + B_INVALID = 0, + B_AUTOVAC_LAUNCHER, + B_AUTOVAC_WORKER, + B_BACKEND, + B_BG_WORKER, + B_BG_WRITER, + B_CHECKPOINTER, + B_STARTUP, + B_WAL_RECEIVER, + B_WAL_SENDER, + B_WAL_WRITER, + B_ARCHIVER, + B_LOGGER, +} BackendType; + +extern PGDLLIMPORT BackendType MyBackendType; + +extern const char *GetBackendTypeDesc(BackendType backendType); + +extern void SetDatabasePath(const char *path); +extern void checkDataDir(void); +extern void SetDataDir(const char *dir); +extern void ChangeToDataDir(void); + +extern char *GetUserNameFromId(Oid roleid, bool noerr); +extern Oid GetUserId(void); +extern Oid GetOuterUserId(void); +extern Oid GetSessionUserId(void); +extern Oid GetAuthenticatedUserId(void); +extern void GetUserIdAndSecContext(Oid *userid, int *sec_context); +extern void SetUserIdAndSecContext(Oid userid, int sec_context); +extern bool InLocalUserIdChange(void); +extern bool InSecurityRestrictedOperation(void); +extern bool InNoForceRLSOperation(void); +extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context); +extern void SetUserIdAndContext(Oid userid, bool sec_def_context); +extern void InitializeSessionUserId(const char *rolename, Oid useroid); +extern void InitializeSessionUserIdStandalone(void); +extern void SetSessionAuthorization(Oid userid, bool is_superuser); +extern Oid GetCurrentRoleId(void); +extern void SetCurrentRoleId(Oid roleid, bool is_superuser); + +/* in utils/misc/superuser.c */ +extern bool superuser(void); /* current user is superuser */ +extern bool superuser_arg(Oid roleid); /* given user is superuser */ + + +/***************************************************************************** + * pmod.h -- * + * POSTGRES processing mode definitions. * + *****************************************************************************/ + +/* + * Description: + * There are three processing modes in POSTGRES. They are + * BootstrapProcessing or "bootstrap," InitProcessing or + * "initialization," and NormalProcessing or "normal." + * + * The first two processing modes are used during special times. When the + * system state indicates bootstrap processing, transactions are all given + * transaction id "one" and are consequently guaranteed to commit. This mode + * is used during the initial generation of template databases. + * + * Initialization mode: used while starting a backend, until all normal + * initialization is complete. Some code behaves differently when executed + * in this mode to enable system bootstrapping. + * + * If a POSTGRES backend process is in normal mode, then all code may be + * executed normally. + */ + +typedef enum ProcessingMode +{ + BootstrapProcessing, /* bootstrap creation of template database */ + InitProcessing, /* initializing system */ + NormalProcessing /* normal processing */ +} ProcessingMode; + +extern PGDLLIMPORT ProcessingMode Mode; + +#define IsBootstrapProcessingMode() (Mode == BootstrapProcessing) +#define IsInitProcessingMode() (Mode == InitProcessing) +#define IsNormalProcessingMode() (Mode == NormalProcessing) + +#define GetProcessingMode() Mode + +#define SetProcessingMode(mode) \ + do { \ + AssertArg((mode) == BootstrapProcessing || \ + (mode) == InitProcessing || \ + (mode) == NormalProcessing); \ + Mode = (mode); \ + } while(0) + + +/* + * Auxiliary-process type identifiers. These used to be in bootstrap.h + * but it seems saner to have them here, with the ProcessingMode stuff. + * The MyAuxProcType global is defined and set in auxprocess.c. + * + * Make sure to list in the glossary any items you add here. + */ + +typedef enum +{ + NotAnAuxProcess = -1, + StartupProcess = 0, + BgWriterProcess, + ArchiverProcess, + CheckpointerProcess, + WalWriterProcess, + WalReceiverProcess, + + NUM_AUXPROCTYPES /* Must be last! */ +} AuxProcType; + +extern PGDLLIMPORT AuxProcType MyAuxProcType; + +#define AmStartupProcess() (MyAuxProcType == StartupProcess) +#define AmBackgroundWriterProcess() (MyAuxProcType == BgWriterProcess) +#define AmArchiverProcess() (MyAuxProcType == ArchiverProcess) +#define AmCheckpointerProcess() (MyAuxProcType == CheckpointerProcess) +#define AmWalWriterProcess() (MyAuxProcType == WalWriterProcess) +#define AmWalReceiverProcess() (MyAuxProcType == WalReceiverProcess) + + +/***************************************************************************** + * pinit.h -- * + * POSTGRES initialization and cleanup definitions. * + *****************************************************************************/ + +/* in utils/init/postinit.c */ +extern void pg_split_opts(char **argv, int *argcp, const char *optstr); +extern void InitializeMaxBackends(void); +extern void InitPostgres(const char *in_dbname, Oid dboid, + const char *username, Oid useroid, + bool load_session_libraries, + bool override_allow_connections, + char *out_dbname); +extern void BaseInit(void); + +/* in utils/init/miscinit.c */ +extern PGDLLIMPORT bool IgnoreSystemIndexes; +extern PGDLLIMPORT bool process_shared_preload_libraries_in_progress; +extern PGDLLIMPORT bool process_shared_preload_libraries_done; +extern PGDLLIMPORT bool process_shmem_requests_in_progress; +extern PGDLLIMPORT char *session_preload_libraries_string; +extern PGDLLIMPORT char *shared_preload_libraries_string; +extern PGDLLIMPORT char *local_preload_libraries_string; + +extern void CreateDataDirLockFile(bool amPostmaster); +extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster, + const char *socketDir); +extern void TouchSocketLockFiles(void); +extern void AddToDataDirLockFile(int target_line, const char *str); +extern bool RecheckDataDirLockFile(void); +extern void ValidatePgVersion(const char *path); +extern void process_shared_preload_libraries(void); +extern void process_session_preload_libraries(void); +extern void process_shmem_requests(void); +extern void pg_bindtextdomain(const char *domain); +extern bool has_rolreplication(Oid roleid); + +typedef void (*shmem_request_hook_type) (void); +extern PGDLLIMPORT shmem_request_hook_type shmem_request_hook; + +/* in executor/nodeHash.c */ +extern size_t get_hash_memory_limit(void); + +#endif /* MISCADMIN_H */ diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h new file mode 100644 index 0000000..75b5ce1 --- /dev/null +++ b/src/include/nodes/bitmapset.h @@ -0,0 +1,122 @@ +/*------------------------------------------------------------------------- + * + * bitmapset.h + * PostgreSQL generic bitmap set package + * + * A bitmap set can represent any set of nonnegative integers, although + * it is mainly intended for sets where the maximum value is not large, + * say at most a few hundred. By convention, a NULL pointer is always + * accepted by all operations to represent the empty set. (But beware + * that this is not the only representation of the empty set. Use + * bms_is_empty() in preference to testing for NULL.) + * + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/nodes/bitmapset.h + * + *------------------------------------------------------------------------- + */ +#ifndef BITMAPSET_H +#define BITMAPSET_H + +/* + * Forward decl to save including pg_list.h + */ +struct List; + +/* + * Data representation + * + * Larger bitmap word sizes generally give better performance, so long as + * they're not wider than the processor can handle efficiently. We use + * 64-bit words if pointers are that large, else 32-bit words. + */ +#if SIZEOF_VOID_P >= 8 + +#define BITS_PER_BITMAPWORD 64 +typedef uint64 bitmapword; /* must be an unsigned type */ +typedef int64 signedbitmapword; /* must be the matching signed type */ + +#else + +#define BITS_PER_BITMAPWORD 32 +typedef uint32 bitmapword; /* must be an unsigned type */ +typedef int32 signedbitmapword; /* must be the matching signed type */ + +#endif + +typedef struct Bitmapset +{ + int nwords; /* number of words in array */ + bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */ +} Bitmapset; + + +/* result of bms_subset_compare */ +typedef enum +{ + BMS_EQUAL, /* sets are equal */ + BMS_SUBSET1, /* first set is a subset of the second */ + BMS_SUBSET2, /* second set is a subset of the first */ + BMS_DIFFERENT /* neither set is a subset of the other */ +} BMS_Comparison; + +/* result of bms_membership */ +typedef enum +{ + BMS_EMPTY_SET, /* 0 members */ + BMS_SINGLETON, /* 1 member */ + BMS_MULTIPLE /* >1 member */ +} BMS_Membership; + + +/* + * function prototypes in nodes/bitmapset.c + */ + +extern Bitmapset *bms_copy(const Bitmapset *a); +extern bool bms_equal(const Bitmapset *a, const Bitmapset *b); +extern int bms_compare(const Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_make_singleton(int x); +extern void bms_free(Bitmapset *a); + +extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b); +extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b); +extern BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b); +extern bool bms_is_member(int x, const Bitmapset *a); +extern int bms_member_index(Bitmapset *a, int x); +extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b); +extern bool bms_overlap_list(const Bitmapset *a, const struct List *b); +extern bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b); +extern int bms_singleton_member(const Bitmapset *a); +extern bool bms_get_singleton_member(const Bitmapset *a, int *member); +extern int bms_num_members(const Bitmapset *a); + +/* optimized tests when we don't need to know exact membership count: */ +extern BMS_Membership bms_membership(const Bitmapset *a); +extern bool bms_is_empty(const Bitmapset *a); + +/* these routines recycle (modify or free) their non-const inputs: */ + +extern Bitmapset *bms_add_member(Bitmapset *a, int x); +extern Bitmapset *bms_del_member(Bitmapset *a, int x); +extern Bitmapset *bms_add_members(Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_add_range(Bitmapset *a, int lower, int upper); +extern Bitmapset *bms_int_members(Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_del_members(Bitmapset *a, const Bitmapset *b); +extern Bitmapset *bms_join(Bitmapset *a, Bitmapset *b); + +/* support for iterating through the integer elements of a set: */ +extern int bms_first_member(Bitmapset *a); +extern int bms_next_member(const Bitmapset *a, int prevbit); +extern int bms_prev_member(const Bitmapset *a, int prevbit); + +/* support for hashtables using Bitmapsets as keys: */ +extern uint32 bms_hash_value(const Bitmapset *a); +extern uint32 bitmap_hash(const void *key, Size keysize); +extern int bitmap_match(const void *key1, const void *key2, Size keysize); + +#endif /* BITMAPSET_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h new file mode 100644 index 0000000..9f176b0 --- /dev/null +++ b/src/include/nodes/execnodes.h @@ -0,0 +1,2758 @@ +/*------------------------------------------------------------------------- + * + * execnodes.h + * definitions for executor state nodes + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/execnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXECNODES_H +#define EXECNODES_H + +#include "access/tupconvert.h" +#include "executor/instrument.h" +#include "fmgr.h" +#include "lib/ilist.h" +#include "lib/pairingheap.h" +#include "nodes/params.h" +#include "nodes/plannodes.h" +#include "nodes/tidbitmap.h" +#include "partitioning/partdefs.h" +#include "storage/condition_variable.h" +#include "utils/hsearch.h" +#include "utils/queryenvironment.h" +#include "utils/reltrigger.h" +#include "utils/sharedtuplestore.h" +#include "utils/snapshot.h" +#include "utils/sortsupport.h" +#include "utils/tuplesort.h" +#include "utils/tuplestore.h" + +struct PlanState; /* forward references in this file */ +struct ParallelHashJoinState; +struct ExecRowMark; +struct ExprState; +struct ExprContext; +struct RangeTblEntry; /* avoid including parsenodes.h here */ +struct ExprEvalStep; /* avoid including execExpr.h everywhere */ +struct CopyMultiInsertBuffer; +struct LogicalTapeSet; + + +/* ---------------- + * ExprState node + * + * ExprState is the top-level node for expression evaluation. + * It contains instructions (in ->steps) to evaluate the expression. + * ---------------- + */ +typedef Datum (*ExprStateEvalFunc) (struct ExprState *expression, + struct ExprContext *econtext, + bool *isNull); + +/* Bits in ExprState->flags (see also execExpr.h for private flag bits): */ +/* expression is for use with ExecQual() */ +#define EEO_FLAG_IS_QUAL (1 << 0) + +typedef struct ExprState +{ + NodeTag type; + + uint8 flags; /* bitmask of EEO_FLAG_* bits, see above */ + + /* + * Storage for result value of a scalar expression, or for individual + * column results within expressions built by ExecBuildProjectionInfo(). + */ +#define FIELDNO_EXPRSTATE_RESNULL 2 + bool resnull; +#define FIELDNO_EXPRSTATE_RESVALUE 3 + Datum resvalue; + + /* + * If projecting a tuple result, this slot holds the result; else NULL. + */ +#define FIELDNO_EXPRSTATE_RESULTSLOT 4 + TupleTableSlot *resultslot; + + /* + * Instructions to compute expression's return value. + */ + struct ExprEvalStep *steps; + + /* + * Function that actually evaluates the expression. This can be set to + * different values depending on the complexity of the expression. + */ + ExprStateEvalFunc evalfunc; + + /* original expression tree, for debugging only */ + Expr *expr; + + /* private state for an evalfunc */ + void *evalfunc_private; + + /* + * XXX: following fields only needed during "compilation" (ExecInitExpr); + * could be thrown away afterwards. + */ + + int steps_len; /* number of steps currently */ + int steps_alloc; /* allocated length of steps array */ + +#define FIELDNO_EXPRSTATE_PARENT 11 + struct PlanState *parent; /* parent PlanState node, if any */ + ParamListInfo ext_params; /* for compiling PARAM_EXTERN nodes */ + + Datum *innermost_caseval; + bool *innermost_casenull; + + Datum *innermost_domainval; + bool *innermost_domainnull; +} ExprState; + + +/* ---------------- + * IndexInfo information + * + * this struct holds the information needed to construct new index + * entries for a particular index. Used for both index_build and + * retail creation of index entries. + * + * NumIndexAttrs total number of columns in this index + * NumIndexKeyAttrs number of key columns in index + * IndexAttrNumbers underlying-rel attribute numbers used as keys + * (zeroes indicate expressions). It also contains + * info about included columns. + * Expressions expr trees for expression entries, or NIL if none + * ExpressionsState exec state for expressions, or NIL if none + * Predicate partial-index predicate, or NIL if none + * PredicateState exec state for predicate, or NIL if none + * ExclusionOps Per-column exclusion operators, or NULL if none + * ExclusionProcs Underlying function OIDs for ExclusionOps + * ExclusionStrats Opclass strategy numbers for ExclusionOps + * UniqueOps These are like Exclusion*, but for unique indexes + * UniqueProcs + * UniqueStrats + * Unique is it a unique index? + * OpclassOptions opclass-specific options, or NULL if none + * ReadyForInserts is it valid for inserts? + * CheckedUnchanged IndexUnchanged status determined yet? + * IndexUnchanged aminsert hint, cached for retail inserts + * Concurrent are we doing a concurrent index build? + * BrokenHotChain did we detect any broken HOT chains? + * ParallelWorkers # of workers requested (excludes leader) + * Am Oid of index AM + * AmCache private cache area for index AM + * Context memory context holding this IndexInfo + * + * ii_Concurrent, ii_BrokenHotChain, and ii_ParallelWorkers are used only + * during index build; they're conventionally zeroed otherwise. + * ---------------- + */ +typedef struct IndexInfo +{ + NodeTag type; + int ii_NumIndexAttrs; /* total number of columns in index */ + int ii_NumIndexKeyAttrs; /* number of key columns in index */ + AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]; + List *ii_Expressions; /* list of Expr */ + List *ii_ExpressionsState; /* list of ExprState */ + List *ii_Predicate; /* list of Expr */ + ExprState *ii_PredicateState; + Oid *ii_ExclusionOps; /* array with one entry per column */ + Oid *ii_ExclusionProcs; /* array with one entry per column */ + uint16 *ii_ExclusionStrats; /* array with one entry per column */ + Oid *ii_UniqueOps; /* array with one entry per column */ + Oid *ii_UniqueProcs; /* array with one entry per column */ + uint16 *ii_UniqueStrats; /* array with one entry per column */ + Datum *ii_OpclassOptions; /* array with one entry per column */ + bool ii_Unique; + bool ii_NullsNotDistinct; + bool ii_ReadyForInserts; + bool ii_CheckedUnchanged; + bool ii_IndexUnchanged; + bool ii_Concurrent; + bool ii_BrokenHotChain; + int ii_ParallelWorkers; + Oid ii_Am; + void *ii_AmCache; + MemoryContext ii_Context; +} IndexInfo; + +/* ---------------- + * ExprContext_CB + * + * List of callbacks to be called at ExprContext shutdown. + * ---------------- + */ +typedef void (*ExprContextCallbackFunction) (Datum arg); + +typedef struct ExprContext_CB +{ + struct ExprContext_CB *next; + ExprContextCallbackFunction function; + Datum arg; +} ExprContext_CB; + +/* ---------------- + * ExprContext + * + * This class holds the "current context" information + * needed to evaluate expressions for doing tuple qualifications + * and tuple projections. For example, if an expression refers + * to an attribute in the current inner tuple then we need to know + * what the current inner tuple is and so we look at the expression + * context. + * + * There are two memory contexts associated with an ExprContext: + * * ecxt_per_query_memory is a query-lifespan context, typically the same + * context the ExprContext node itself is allocated in. This context + * can be used for purposes such as storing function call cache info. + * * ecxt_per_tuple_memory is a short-term context for expression results. + * As the name suggests, it will typically be reset once per tuple, + * before we begin to evaluate expressions for that tuple. Each + * ExprContext normally has its very own per-tuple memory context. + * + * CurrentMemoryContext should be set to ecxt_per_tuple_memory before + * calling ExecEvalExpr() --- see ExecEvalExprSwitchContext(). + * ---------------- + */ +typedef struct ExprContext +{ + NodeTag type; + + /* Tuples that Var nodes in expression may refer to */ +#define FIELDNO_EXPRCONTEXT_SCANTUPLE 1 + TupleTableSlot *ecxt_scantuple; +#define FIELDNO_EXPRCONTEXT_INNERTUPLE 2 + TupleTableSlot *ecxt_innertuple; +#define FIELDNO_EXPRCONTEXT_OUTERTUPLE 3 + TupleTableSlot *ecxt_outertuple; + + /* Memory contexts for expression evaluation --- see notes above */ + MemoryContext ecxt_per_query_memory; + MemoryContext ecxt_per_tuple_memory; + + /* Values to substitute for Param nodes in expression */ + ParamExecData *ecxt_param_exec_vals; /* for PARAM_EXEC params */ + ParamListInfo ecxt_param_list_info; /* for other param types */ + + /* + * Values to substitute for Aggref nodes in the expressions of an Agg + * node, or for WindowFunc nodes within a WindowAgg node. + */ +#define FIELDNO_EXPRCONTEXT_AGGVALUES 8 + Datum *ecxt_aggvalues; /* precomputed values for aggs/windowfuncs */ +#define FIELDNO_EXPRCONTEXT_AGGNULLS 9 + bool *ecxt_aggnulls; /* null flags for aggs/windowfuncs */ + + /* Value to substitute for CaseTestExpr nodes in expression */ +#define FIELDNO_EXPRCONTEXT_CASEDATUM 10 + Datum caseValue_datum; +#define FIELDNO_EXPRCONTEXT_CASENULL 11 + bool caseValue_isNull; + + /* Value to substitute for CoerceToDomainValue nodes in expression */ +#define FIELDNO_EXPRCONTEXT_DOMAINDATUM 12 + Datum domainValue_datum; +#define FIELDNO_EXPRCONTEXT_DOMAINNULL 13 + bool domainValue_isNull; + + /* Link to containing EState (NULL if a standalone ExprContext) */ + struct EState *ecxt_estate; + + /* Functions to call back when ExprContext is shut down or rescanned */ + ExprContext_CB *ecxt_callbacks; +} ExprContext; + +/* + * Set-result status used when evaluating functions potentially returning a + * set. + */ +typedef enum +{ + ExprSingleResult, /* expression does not return a set */ + ExprMultipleResult, /* this result is an element of a set */ + ExprEndResult /* there are no more elements in the set */ +} ExprDoneCond; + +/* + * Return modes for functions returning sets. Note values must be chosen + * as separate bits so that a bitmask can be formed to indicate supported + * modes. SFRM_Materialize_Random and SFRM_Materialize_Preferred are + * auxiliary flags about SFRM_Materialize mode, rather than separate modes. + */ +typedef enum +{ + SFRM_ValuePerCall = 0x01, /* one value returned per call */ + SFRM_Materialize = 0x02, /* result set instantiated in Tuplestore */ + SFRM_Materialize_Random = 0x04, /* Tuplestore needs randomAccess */ + SFRM_Materialize_Preferred = 0x08 /* caller prefers Tuplestore */ +} SetFunctionReturnMode; + +/* + * When calling a function that might return a set (multiple rows), + * a node of this type is passed as fcinfo->resultinfo to allow + * return status to be passed back. A function returning set should + * raise an error if no such resultinfo is provided. + */ +typedef struct ReturnSetInfo +{ + NodeTag type; + /* values set by caller: */ + ExprContext *econtext; /* context function is being called in */ + TupleDesc expectedDesc; /* tuple descriptor expected by caller */ + int allowedModes; /* bitmask: return modes caller can handle */ + /* result status from function (but pre-initialized by caller): */ + SetFunctionReturnMode returnMode; /* actual return mode */ + ExprDoneCond isDone; /* status for ValuePerCall mode */ + /* fields filled by function in Materialize return mode: */ + Tuplestorestate *setResult; /* holds the complete returned tuple set */ + TupleDesc setDesc; /* actual descriptor for returned tuples */ +} ReturnSetInfo; + +/* ---------------- + * ProjectionInfo node information + * + * This is all the information needed to perform projections --- + * that is, form new tuples by evaluation of targetlist expressions. + * Nodes which need to do projections create one of these. + * + * The target tuple slot is kept in ProjectionInfo->pi_state.resultslot. + * ExecProject() evaluates the tlist, forms a tuple, and stores it + * in the given slot. Note that the result will be a "virtual" tuple + * unless ExecMaterializeSlot() is then called to force it to be + * converted to a physical tuple. The slot must have a tupledesc + * that matches the output of the tlist! + * ---------------- + */ +typedef struct ProjectionInfo +{ + NodeTag type; + /* instructions to evaluate projection */ + ExprState pi_state; + /* expression context in which to evaluate expression */ + ExprContext *pi_exprContext; +} ProjectionInfo; + +/* ---------------- + * JunkFilter + * + * This class is used to store information regarding junk attributes. + * A junk attribute is an attribute in a tuple that is needed only for + * storing intermediate information in the executor, and does not belong + * in emitted tuples. For example, when we do an UPDATE query, + * the planner adds a "junk" entry to the targetlist so that the tuples + * returned to ExecutePlan() contain an extra attribute: the ctid of + * the tuple to be updated. This is needed to do the update, but we + * don't want the ctid to be part of the stored new tuple! So, we + * apply a "junk filter" to remove the junk attributes and form the + * real output tuple. The junkfilter code also provides routines to + * extract the values of the junk attribute(s) from the input tuple. + * + * targetList: the original target list (including junk attributes). + * cleanTupType: the tuple descriptor for the "clean" tuple (with + * junk attributes removed). + * cleanMap: A map with the correspondence between the non-junk + * attribute numbers of the "original" tuple and the + * attribute numbers of the "clean" tuple. + * resultSlot: tuple slot used to hold cleaned tuple. + * ---------------- + */ +typedef struct JunkFilter +{ + NodeTag type; + List *jf_targetList; + TupleDesc jf_cleanTupType; + AttrNumber *jf_cleanMap; + TupleTableSlot *jf_resultSlot; +} JunkFilter; + +/* + * OnConflictSetState + * + * Executor state of an ON CONFLICT DO UPDATE operation. + */ +typedef struct OnConflictSetState +{ + NodeTag type; + + TupleTableSlot *oc_Existing; /* slot to store existing target tuple in */ + TupleTableSlot *oc_ProjSlot; /* CONFLICT ... SET ... projection target */ + ProjectionInfo *oc_ProjInfo; /* for ON CONFLICT DO UPDATE SET */ + ExprState *oc_WhereClause; /* state for the WHERE clause */ +} OnConflictSetState; + +/* ---------------- + * MergeActionState information + * + * Executor state for a MERGE action. + * ---------------- + */ +typedef struct MergeActionState +{ + NodeTag type; + + MergeAction *mas_action; /* associated MergeAction node */ + ProjectionInfo *mas_proj; /* projection of the action's targetlist for + * this rel */ + ExprState *mas_whenqual; /* WHEN [NOT] MATCHED AND conditions */ +} MergeActionState; + +/* + * ResultRelInfo + * + * Whenever we update an existing relation, we have to update indexes on the + * relation, and perhaps also fire triggers. ResultRelInfo holds all the + * information needed about a result relation, including indexes. + * + * Normally, a ResultRelInfo refers to a table that is in the query's range + * table; then ri_RangeTableIndex is the RT index and ri_RelationDesc is + * just a copy of the relevant es_relations[] entry. However, in some + * situations we create ResultRelInfos for relations that are not in the + * range table, namely for targets of tuple routing in a partitioned table, + * and when firing triggers in tables other than the target tables (See + * ExecGetTriggerResultRel). In these situations, ri_RangeTableIndex is 0 + * and ri_RelationDesc is a separately-opened relcache pointer that needs to + * be separately closed. + */ +typedef struct ResultRelInfo +{ + NodeTag type; + + /* result relation's range table index, or 0 if not in range table */ + Index ri_RangeTableIndex; + + /* relation descriptor for result relation */ + Relation ri_RelationDesc; + + /* # of indices existing on result relation */ + int ri_NumIndices; + + /* array of relation descriptors for indices */ + RelationPtr ri_IndexRelationDescs; + + /* array of key/attr info for indices */ + IndexInfo **ri_IndexRelationInfo; + + /* + * For UPDATE/DELETE result relations, the attribute number of the row + * identity junk attribute in the source plan's output tuples + */ + AttrNumber ri_RowIdAttNo; + + /* Projection to generate new tuple in an INSERT/UPDATE */ + ProjectionInfo *ri_projectNew; + /* Slot to hold that tuple */ + TupleTableSlot *ri_newTupleSlot; + /* Slot to hold the old tuple being updated */ + TupleTableSlot *ri_oldTupleSlot; + /* Have the projection and the slots above been initialized? */ + bool ri_projectNewInfoValid; + + /* triggers to be fired, if any */ + TriggerDesc *ri_TrigDesc; + + /* cached lookup info for trigger functions */ + FmgrInfo *ri_TrigFunctions; + + /* array of trigger WHEN expr states */ + ExprState **ri_TrigWhenExprs; + + /* optional runtime measurements for triggers */ + Instrumentation *ri_TrigInstrument; + + /* On-demand created slots for triggers / returning processing */ + TupleTableSlot *ri_ReturningSlot; /* for trigger output tuples */ + TupleTableSlot *ri_TrigOldSlot; /* for a trigger's old tuple */ + TupleTableSlot *ri_TrigNewSlot; /* for a trigger's new tuple */ + + /* FDW callback functions, if foreign table */ + struct FdwRoutine *ri_FdwRoutine; + + /* available to save private state of FDW */ + void *ri_FdwState; + + /* true when modifying foreign table directly */ + bool ri_usesFdwDirectModify; + + /* batch insert stuff */ + int ri_NumSlots; /* number of slots in the array */ + int ri_NumSlotsInitialized; /* number of initialized slots */ + int ri_BatchSize; /* max slots inserted in a single batch */ + TupleTableSlot **ri_Slots; /* input tuples for batch insert */ + TupleTableSlot **ri_PlanSlots; + + /* list of WithCheckOption's to be checked */ + List *ri_WithCheckOptions; + + /* list of WithCheckOption expr states */ + List *ri_WithCheckOptionExprs; + + /* array of constraint-checking expr states */ + ExprState **ri_ConstraintExprs; + + /* array of stored generated columns expr states */ + ExprState **ri_GeneratedExprs; + + /* number of stored generated columns we need to compute */ + int ri_NumGeneratedNeeded; + + /* list of RETURNING expressions */ + List *ri_returningList; + + /* for computing a RETURNING list */ + ProjectionInfo *ri_projectReturning; + + /* list of arbiter indexes to use to check conflicts */ + List *ri_onConflictArbiterIndexes; + + /* ON CONFLICT evaluation state */ + OnConflictSetState *ri_onConflict; + + /* for MERGE, lists of MergeActionState */ + List *ri_matchedMergeAction; + List *ri_notMatchedMergeAction; + + /* partition check expression state (NULL if not set up yet) */ + ExprState *ri_PartitionCheckExpr; + + /* + * Information needed by tuple routing target relations + * + * RootResultRelInfo gives the target relation mentioned in the query, if + * it's a partitioned table. It is not set if the target relation + * mentioned in the query is an inherited table, nor when tuple routing is + * not needed. + * + * RootToPartitionMap and PartitionTupleSlot, initialized by + * ExecInitRoutingInfo, are non-NULL if partition has a different tuple + * format than the root table. + */ + struct ResultRelInfo *ri_RootResultRelInfo; + TupleConversionMap *ri_RootToPartitionMap; + TupleTableSlot *ri_PartitionTupleSlot; + + /* + * Map to convert child result relation tuples to the format of the table + * actually mentioned in the query (called "root"). Computed only if + * needed. A NULL map value indicates that no conversion is needed, so we + * must have a separate flag to show if the map has been computed. + */ + TupleConversionMap *ri_ChildToRootMap; + bool ri_ChildToRootMapValid; + + /* for use by copyfrom.c when performing multi-inserts */ + struct CopyMultiInsertBuffer *ri_CopyMultiInsertBuffer; + + /* + * Used when a leaf partition is involved in a cross-partition update of + * one of its ancestors; see ExecCrossPartitionUpdateForeignKey(). + */ + List *ri_ancestorResultRels; +} ResultRelInfo; + +/* + * To avoid an ABI-breaking change in the size of ResultRelInfo in back + * branches, we create one of these for each result relation for which we've + * computed extraUpdatedCols, and store it in EState.es_resultrelinfo_extra. + */ +typedef struct ResultRelInfoExtra +{ + ResultRelInfo *rinfo; /* owning ResultRelInfo */ + + /* For INSERT/UPDATE, attnums of generated columns to be computed */ + Bitmapset *ri_extraUpdatedCols; +} ResultRelInfoExtra; + +/* ---------------- + * AsyncRequest + * + * State for an asynchronous tuple request. + * ---------------- + */ +typedef struct AsyncRequest +{ + struct PlanState *requestor; /* Node that wants a tuple */ + struct PlanState *requestee; /* Node from which a tuple is wanted */ + int request_index; /* Scratch space for requestor */ + bool callback_pending; /* Callback is needed */ + bool request_complete; /* Request complete, result valid */ + TupleTableSlot *result; /* Result (NULL or an empty slot if no more + * tuples) */ +} AsyncRequest; + +/* ---------------- + * EState information + * + * Working state for an Executor invocation + * ---------------- + */ +typedef struct EState +{ + NodeTag type; + + /* Basic state for all query types: */ + ScanDirection es_direction; /* current scan direction */ + Snapshot es_snapshot; /* time qual to use */ + Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */ + List *es_range_table; /* List of RangeTblEntry */ + Index es_range_table_size; /* size of the range table arrays */ + Relation *es_relations; /* Array of per-range-table-entry Relation + * pointers, or NULL if not yet opened */ + struct ExecRowMark **es_rowmarks; /* Array of per-range-table-entry + * ExecRowMarks, or NULL if none */ + PlannedStmt *es_plannedstmt; /* link to top of plan tree */ + const char *es_sourceText; /* Source text from QueryDesc */ + + JunkFilter *es_junkFilter; /* top-level junk filter, if any */ + + /* If query can insert/delete tuples, the command ID to mark them with */ + CommandId es_output_cid; + + /* Info about target table(s) for insert/update/delete queries: */ + ResultRelInfo **es_result_relations; /* Array of per-range-table-entry + * ResultRelInfo pointers, or NULL + * if not a target table */ + List *es_opened_result_relations; /* List of non-NULL entries in + * es_result_relations in no + * specific order */ + + PartitionDirectory es_partition_directory; /* for PartitionDesc lookup */ + + /* + * The following list contains ResultRelInfos created by the tuple routing + * code for partitions that aren't found in the es_result_relations array. + */ + List *es_tuple_routing_result_relations; + + /* Stuff used for firing triggers: */ + List *es_trig_target_relations; /* trigger-only ResultRelInfos */ + + /* Parameter info: */ + ParamListInfo es_param_list_info; /* values of external params */ + ParamExecData *es_param_exec_vals; /* values of internal params */ + + QueryEnvironment *es_queryEnv; /* query environment */ + + /* Other working state: */ + MemoryContext es_query_cxt; /* per-query context in which EState lives */ + + List *es_tupleTable; /* List of TupleTableSlots */ + + uint64 es_processed; /* # of tuples processed */ + + int es_top_eflags; /* eflags passed to ExecutorStart */ + int es_instrument; /* OR of InstrumentOption flags */ + bool es_finished; /* true when ExecutorFinish is done */ + + List *es_exprcontexts; /* List of ExprContexts within EState */ + + List *es_subplanstates; /* List of PlanState for SubPlans */ + + List *es_auxmodifytables; /* List of secondary ModifyTableStates */ + + /* + * this ExprContext is for per-output-tuple operations, such as constraint + * checks and index-value computations. It will be reset for each output + * tuple. Note that it will be created only if needed. + */ + ExprContext *es_per_tuple_exprcontext; + + /* + * If not NULL, this is an EPQState's EState. This is a field in EState + * both to allow EvalPlanQual aware executor nodes to detect that they + * need to perform EPQ related work, and to provide necessary information + * to do so. + */ + struct EPQState *es_epq_active; + + bool es_use_parallel_mode; /* can we use parallel workers? */ + + /* The per-query shared memory area to use for parallel execution. */ + struct dsa_area *es_query_dsa; + + /* + * JIT information. es_jit_flags indicates whether JIT should be performed + * and with which options. es_jit is created on-demand when JITing is + * performed. + * + * es_jit_worker_instr is the combined, on demand allocated, + * instrumentation from all workers. The leader's instrumentation is kept + * separate, and is combined on demand by ExplainPrintJITSummary(). + */ + int es_jit_flags; + struct JitContext *es_jit; + struct JitInstrumentation *es_jit_worker_instr; + + /* + * Lists of ResultRelInfos for foreign tables on which batch-inserts are + * to be executed and owning ModifyTableStates, stored in the same order. + */ + List *es_insert_pending_result_relations; + List *es_insert_pending_modifytables; + + /* List of ResultRelInfoExtra structs (see above) */ + List *es_resultrelinfo_extra; +} EState; + + +/* + * ExecRowMark - + * runtime representation of FOR [KEY] UPDATE/SHARE clauses + * + * When doing UPDATE/DELETE/MERGE/SELECT FOR [KEY] UPDATE/SHARE, we will have + * an ExecRowMark for each non-target relation in the query (except inheritance + * parent RTEs, which can be ignored at runtime). Virtual relations such as + * subqueries-in-FROM will have an ExecRowMark with relation == NULL. See + * PlanRowMark for details about most of the fields. In addition to fields + * directly derived from PlanRowMark, we store an activity flag (to denote + * inactive children of inheritance trees), curCtid, which is used by the + * WHERE CURRENT OF code, and ermExtra, which is available for use by the plan + * node that sources the relation (e.g., for a foreign table the FDW can use + * ermExtra to hold information). + * + * EState->es_rowmarks is an array of these structs, indexed by RT index, + * with NULLs for irrelevant RT indexes. es_rowmarks itself is NULL if + * there are no rowmarks. + */ +typedef struct ExecRowMark +{ + Relation relation; /* opened and suitably locked relation */ + Oid relid; /* its OID (or InvalidOid, if subquery) */ + Index rti; /* its range table index */ + Index prti; /* parent range table index, if child */ + Index rowmarkId; /* unique identifier for resjunk columns */ + RowMarkType markType; /* see enum in nodes/plannodes.h */ + LockClauseStrength strength; /* LockingClause's strength, or LCS_NONE */ + LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */ + bool ermActive; /* is this mark relevant for current tuple? */ + ItemPointerData curCtid; /* ctid of currently locked tuple, if any */ + void *ermExtra; /* available for use by relation source node */ +} ExecRowMark; + +/* + * ExecAuxRowMark - + * additional runtime representation of FOR [KEY] UPDATE/SHARE clauses + * + * Each LockRows and ModifyTable node keeps a list of the rowmarks it needs to + * deal with. In addition to a pointer to the related entry in es_rowmarks, + * this struct carries the column number(s) of the resjunk columns associated + * with the rowmark (see comments for PlanRowMark for more detail). + */ +typedef struct ExecAuxRowMark +{ + ExecRowMark *rowmark; /* related entry in es_rowmarks */ + AttrNumber ctidAttNo; /* resno of ctid junk attribute, if any */ + AttrNumber toidAttNo; /* resno of tableoid junk attribute, if any */ + AttrNumber wholeAttNo; /* resno of whole-row junk attribute, if any */ +} ExecAuxRowMark; + + +/* ---------------------------------------------------------------- + * Tuple Hash Tables + * + * All-in-memory tuple hash tables are used for a number of purposes. + * + * Note: tab_hash_funcs are for the key datatype(s) stored in the table, + * and tab_eq_funcs are non-cross-type equality operators for those types. + * Normally these are the only functions used, but FindTupleHashEntry() + * supports searching a hashtable using cross-data-type hashing. For that, + * the caller must supply hash functions for the LHS datatype as well as + * the cross-type equality operators to use. in_hash_funcs and cur_eq_func + * are set to point to the caller's function arrays while doing such a search. + * During LookupTupleHashEntry(), they point to tab_hash_funcs and + * tab_eq_func respectively. + * ---------------------------------------------------------------- + */ +typedef struct TupleHashEntryData *TupleHashEntry; +typedef struct TupleHashTableData *TupleHashTable; + +typedef struct TupleHashEntryData +{ + MinimalTuple firstTuple; /* copy of first tuple in this group */ + void *additional; /* user data */ + uint32 status; /* hash status */ + uint32 hash; /* hash value (cached) */ +} TupleHashEntryData; + +/* define parameters necessary to generate the tuple hash table interface */ +#define SH_PREFIX tuplehash +#define SH_ELEMENT_TYPE TupleHashEntryData +#define SH_KEY_TYPE MinimalTuple +#define SH_SCOPE extern +#define SH_DECLARE +#include "lib/simplehash.h" + +typedef struct TupleHashTableData +{ + tuplehash_hash *hashtab; /* underlying hash table */ + int numCols; /* number of columns in lookup key */ + AttrNumber *keyColIdx; /* attr numbers of key columns */ + FmgrInfo *tab_hash_funcs; /* hash functions for table datatype(s) */ + ExprState *tab_eq_func; /* comparator for table datatype(s) */ + Oid *tab_collations; /* collations for hash and comparison */ + MemoryContext tablecxt; /* memory context containing table */ + MemoryContext tempcxt; /* context for function evaluations */ + Size entrysize; /* actual size to make each hash entry */ + TupleTableSlot *tableslot; /* slot for referencing table entries */ + /* The following fields are set transiently for each table search: */ + TupleTableSlot *inputslot; /* current input tuple's slot */ + FmgrInfo *in_hash_funcs; /* hash functions for input datatype(s) */ + ExprState *cur_eq_func; /* comparator for input vs. table */ + uint32 hash_iv; /* hash-function IV */ + ExprContext *exprcontext; /* expression context */ +} TupleHashTableData; + +typedef tuplehash_iterator TupleHashIterator; + +/* + * Use InitTupleHashIterator/TermTupleHashIterator for a read/write scan. + * Use ResetTupleHashIterator if the table can be frozen (in this case no + * explicit scan termination is needed). + */ +#define InitTupleHashIterator(htable, iter) \ + tuplehash_start_iterate(htable->hashtab, iter) +#define TermTupleHashIterator(iter) \ + ((void) 0) +#define ResetTupleHashIterator(htable, iter) \ + InitTupleHashIterator(htable, iter) +#define ScanTupleHashTable(htable, iter) \ + tuplehash_iterate(htable->hashtab, iter) + + +/* ---------------------------------------------------------------- + * Expression State Nodes + * + * Formerly, there was a separate executor expression state node corresponding + * to each node in a planned expression tree. That's no longer the case; for + * common expression node types, all the execution info is embedded into + * step(s) in a single ExprState node. But we still have a few executor state + * node types for selected expression node types, mostly those in which info + * has to be shared with other parts of the execution state tree. + * ---------------------------------------------------------------- + */ + +/* ---------------- + * WindowFuncExprState node + * ---------------- + */ +typedef struct WindowFuncExprState +{ + NodeTag type; + WindowFunc *wfunc; /* expression plan node */ + List *args; /* ExprStates for argument expressions */ + ExprState *aggfilter; /* FILTER expression */ + int wfuncno; /* ID number for wfunc within its plan node */ +} WindowFuncExprState; + + +/* ---------------- + * SetExprState node + * + * State for evaluating a potentially set-returning expression (like FuncExpr + * or OpExpr). In some cases, like some of the expressions in ROWS FROM(...) + * the expression might not be a SRF, but nonetheless it uses the same + * machinery as SRFs; it will be treated as a SRF returning a single row. + * ---------------- + */ +typedef struct SetExprState +{ + NodeTag type; + Expr *expr; /* expression plan node */ + List *args; /* ExprStates for argument expressions */ + + /* + * In ROWS FROM, functions can be inlined, removing the FuncExpr normally + * inside. In such a case this is the compiled expression (which cannot + * return a set), which'll be evaluated using regular ExecEvalExpr(). + */ + ExprState *elidedFuncState; + + /* + * Function manager's lookup info for the target function. If func.fn_oid + * is InvalidOid, we haven't initialized it yet (nor any of the following + * fields, except funcReturnsSet). + */ + FmgrInfo func; + + /* + * For a set-returning function (SRF) that returns a tuplestore, we keep + * the tuplestore here and dole out the result rows one at a time. The + * slot holds the row currently being returned. + */ + Tuplestorestate *funcResultStore; + TupleTableSlot *funcResultSlot; + + /* + * In some cases we need to compute a tuple descriptor for the function's + * output. If so, it's stored here. + */ + TupleDesc funcResultDesc; + bool funcReturnsTuple; /* valid when funcResultDesc isn't NULL */ + + /* + * Remember whether the function is declared to return a set. This is set + * by ExecInitExpr, and is valid even before the FmgrInfo is set up. + */ + bool funcReturnsSet; + + /* + * setArgsValid is true when we are evaluating a set-returning function + * that uses value-per-call mode and we are in the middle of a call + * series; we want to pass the same argument values to the function again + * (and again, until it returns ExprEndResult). This indicates that + * fcinfo_data already contains valid argument data. + */ + bool setArgsValid; + + /* + * Flag to remember whether we have registered a shutdown callback for + * this SetExprState. We do so only if funcResultStore or setArgsValid + * has been set at least once (since all the callback is for is to release + * the tuplestore or clear setArgsValid). + */ + bool shutdown_reg; /* a shutdown callback is registered */ + + /* + * Call parameter structure for the function. This has been initialized + * (by InitFunctionCallInfoData) if func.fn_oid is valid. It also saves + * argument values between calls, when setArgsValid is true. + */ + FunctionCallInfo fcinfo; +} SetExprState; + +/* ---------------- + * SubPlanState node + * ---------------- + */ +typedef struct SubPlanState +{ + NodeTag type; + SubPlan *subplan; /* expression plan node */ + struct PlanState *planstate; /* subselect plan's state tree */ + struct PlanState *parent; /* parent plan node's state tree */ + ExprState *testexpr; /* state of combining expression */ + List *args; /* states of argument expression(s) */ + HeapTuple curTuple; /* copy of most recent tuple from subplan */ + Datum curArray; /* most recent array from ARRAY() subplan */ + /* these are used when hashing the subselect's output: */ + TupleDesc descRight; /* subselect desc after projection */ + ProjectionInfo *projLeft; /* for projecting lefthand exprs */ + ProjectionInfo *projRight; /* for projecting subselect output */ + TupleHashTable hashtable; /* hash table for no-nulls subselect rows */ + TupleHashTable hashnulls; /* hash table for rows with null(s) */ + bool havehashrows; /* true if hashtable is not empty */ + bool havenullrows; /* true if hashnulls is not empty */ + MemoryContext hashtablecxt; /* memory context containing hash tables */ + MemoryContext hashtempcxt; /* temp memory context for hash tables */ + ExprContext *innerecontext; /* econtext for computing inner tuples */ + int numCols; /* number of columns being hashed */ + /* each of the remaining fields is an array of length numCols: */ + AttrNumber *keyColIdx; /* control data for hash tables */ + Oid *tab_eq_funcoids; /* equality func oids for table + * datatype(s) */ + Oid *tab_collations; /* collations for hash and comparison */ + FmgrInfo *tab_hash_funcs; /* hash functions for table datatype(s) */ + FmgrInfo *tab_eq_funcs; /* equality functions for table datatype(s) */ + FmgrInfo *lhs_hash_funcs; /* hash functions for lefthand datatype(s) */ + FmgrInfo *cur_eq_funcs; /* equality functions for LHS vs. table */ + ExprState *cur_eq_comp; /* equality comparator for LHS vs. table */ +} SubPlanState; + +/* + * DomainConstraintState - one item to check during CoerceToDomain + * + * Note: we consider this to be part of an ExprState tree, so we give it + * a name following the xxxState convention. But there's no directly + * associated plan-tree node. + */ +typedef enum DomainConstraintType +{ + DOM_CONSTRAINT_NOTNULL, + DOM_CONSTRAINT_CHECK +} DomainConstraintType; + +typedef struct DomainConstraintState +{ + NodeTag type; + DomainConstraintType constrainttype; /* constraint type */ + char *name; /* name of constraint (for error msgs) */ + Expr *check_expr; /* for CHECK, a boolean expression */ + ExprState *check_exprstate; /* check_expr's eval state, or NULL */ +} DomainConstraintState; + + +/* ---------------------------------------------------------------- + * Executor State Trees + * + * An executing query has a PlanState tree paralleling the Plan tree + * that describes the plan. + * ---------------------------------------------------------------- + */ + +/* ---------------- + * ExecProcNodeMtd + * + * This is the method called by ExecProcNode to return the next tuple + * from an executor node. It returns NULL, or an empty TupleTableSlot, + * if no more tuples are available. + * ---------------- + */ +typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate); + +/* ---------------- + * PlanState node + * + * We never actually instantiate any PlanState nodes; this is just the common + * abstract superclass for all PlanState-type nodes. + * ---------------- + */ +typedef struct PlanState +{ + NodeTag type; + + Plan *plan; /* associated Plan node */ + + EState *state; /* at execution time, states of individual + * nodes point to one EState for the whole + * top-level plan */ + + ExecProcNodeMtd ExecProcNode; /* function to return next tuple */ + ExecProcNodeMtd ExecProcNodeReal; /* actual function, if above is a + * wrapper */ + + Instrumentation *instrument; /* Optional runtime stats for this node */ + WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */ + + /* Per-worker JIT instrumentation */ + struct SharedJitInstrumentation *worker_jit_instrument; + + /* + * Common structural data for all Plan types. These links to subsidiary + * state trees parallel links in the associated plan tree (except for the + * subPlan list, which does not exist in the plan tree). + */ + ExprState *qual; /* boolean qual condition */ + struct PlanState *lefttree; /* input plan tree(s) */ + struct PlanState *righttree; + + List *initPlan; /* Init SubPlanState nodes (un-correlated expr + * subselects) */ + List *subPlan; /* SubPlanState nodes in my expressions */ + + /* + * State for management of parameter-change-driven rescanning + */ + Bitmapset *chgParam; /* set of IDs of changed Params */ + + /* + * Other run-time state needed by most if not all node types. + */ + TupleDesc ps_ResultTupleDesc; /* node's return type */ + TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */ + ExprContext *ps_ExprContext; /* node's expression-evaluation context */ + ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */ + + bool async_capable; /* true if node is async-capable */ + + /* + * Scanslot's descriptor if known. This is a bit of a hack, but otherwise + * it's hard for expression compilation to optimize based on the + * descriptor, without encoding knowledge about all executor nodes. + */ + TupleDesc scandesc; + + /* + * Define the slot types for inner, outer and scanslots for expression + * contexts with this state as a parent. If *opsset is set, then + * *opsfixed indicates whether *ops is guaranteed to be the type of slot + * used. That means that every slot in the corresponding + * ExprContext.ecxt_*tuple will point to a slot of that type, while + * evaluating the expression. If *opsfixed is false, but *ops is set, + * that indicates the most likely type of slot. + * + * The scan* fields are set by ExecInitScanTupleSlot(). If that's not + * called, nodes can initialize the fields themselves. + * + * If outer/inneropsset is false, the information is inferred on-demand + * using ExecGetResultSlotOps() on ->righttree/lefttree, using the + * corresponding node's resultops* fields. + * + * The result* fields are automatically set when ExecInitResultSlot is + * used (be it directly or when the slot is created by + * ExecAssignScanProjectionInfo() / + * ExecConditionalAssignProjectionInfo()). If no projection is necessary + * ExecConditionalAssignProjectionInfo() defaults those fields to the scan + * operations. + */ + const TupleTableSlotOps *scanops; + const TupleTableSlotOps *outerops; + const TupleTableSlotOps *innerops; + const TupleTableSlotOps *resultops; + bool scanopsfixed; + bool outeropsfixed; + bool inneropsfixed; + bool resultopsfixed; + bool scanopsset; + bool outeropsset; + bool inneropsset; + bool resultopsset; +} PlanState; + +/* ---------------- + * these are defined to avoid confusion problems with "left" + * and "right" and "inner" and "outer". The convention is that + * the "left" plan is the "outer" plan and the "right" plan is + * the inner plan, but these make the code more readable. + * ---------------- + */ +#define innerPlanState(node) (((PlanState *)(node))->righttree) +#define outerPlanState(node) (((PlanState *)(node))->lefttree) + +/* Macros for inline access to certain instrumentation counters */ +#define InstrCountTuples2(node, delta) \ + do { \ + if (((PlanState *)(node))->instrument) \ + ((PlanState *)(node))->instrument->ntuples2 += (delta); \ + } while (0) +#define InstrCountFiltered1(node, delta) \ + do { \ + if (((PlanState *)(node))->instrument) \ + ((PlanState *)(node))->instrument->nfiltered1 += (delta); \ + } while(0) +#define InstrCountFiltered2(node, delta) \ + do { \ + if (((PlanState *)(node))->instrument) \ + ((PlanState *)(node))->instrument->nfiltered2 += (delta); \ + } while(0) + +/* + * EPQState is state for executing an EvalPlanQual recheck on a candidate + * tuples e.g. in ModifyTable or LockRows. + * + * To execute EPQ a separate EState is created (stored in ->recheckestate), + * which shares some resources, like the rangetable, with the main query's + * EState (stored in ->parentestate). The (sub-)tree of the plan that needs to + * be rechecked (in ->plan), is separately initialized (into + * ->recheckplanstate), but shares plan nodes with the corresponding nodes in + * the main query. The scan nodes in that separate executor tree are changed + * to return only the current tuple of interest for the respective + * table. Those tuples are either provided by the caller (using + * EvalPlanQualSlot), and/or found using the rowmark mechanism (non-locking + * rowmarks by the EPQ machinery itself, locking ones by the caller). + * + * While the plan to be checked may be changed using EvalPlanQualSetPlan(), + * all such plans need to share the same EState. + */ +typedef struct EPQState +{ + /* These are initialized by EvalPlanQualInit() and do not change later: */ + EState *parentestate; /* main query's EState */ + int epqParam; /* ID of Param to force scan node re-eval */ + struct EPQStateExtra *epqExtra; /* extension pointer to avoid ABI break */ + + /* + * relsubs_slot[scanrelid - 1] holds the EPQ test tuple to be returned by + * the scan node for the scanrelid'th RT index, in place of performing an + * actual table scan. Callers should use EvalPlanQualSlot() to fetch + * these slots. + */ + TupleTableSlot **relsubs_slot; + + /* + * Initialized by EvalPlanQualInit(), may be changed later with + * EvalPlanQualSetPlan(): + */ + + Plan *plan; /* plan tree to be executed */ + List *arowMarks; /* ExecAuxRowMarks (non-locking only) */ + + + /* + * The original output tuple to be rechecked. Set by + * EvalPlanQualSetSlot(), before EvalPlanQualNext() or EvalPlanQual() may + * be called. + */ + TupleTableSlot *origslot; + + + /* Initialized or reset by EvalPlanQualBegin(): */ + + EState *recheckestate; /* EState for EPQ execution, see above */ + + /* + * Rowmarks that can be fetched on-demand using + * EvalPlanQualFetchRowMark(), indexed by scanrelid - 1. Only non-locking + * rowmarks. + */ + ExecAuxRowMark **relsubs_rowmark; + + /* + * relsubs_done[scanrelid - 1] is true if there is no EPQ tuple for this + * target relation or it has already been fetched in the current scan of + * this target relation within the current EvalPlanQual test. + */ + bool *relsubs_done; + + PlanState *recheckplanstate; /* EPQ specific exec nodes, for ->plan */ +} EPQState; + + +/* + * To avoid an ABI-breaking change in the size of EPQState in back branches, + * we create one of these during EvalPlanQualInit. + */ +typedef struct EPQStateExtra +{ + List *resultRelations; /* integer list of RT indexes, or NIL */ + List *tuple_table; /* tuple table for relsubs_slot */ + + /* + * relsubs_blocked[scanrelid - 1] is true if there is no EPQ tuple for + * this target relation during the current EvalPlanQual test. We keep + * these flags set for all relids listed in resultRelations, but + * transiently clear the one for the relation whose tuple is actually + * passed to EvalPlanQual(). + */ + bool *relsubs_blocked; +} EPQStateExtra; + +/* ---------------- + * ResultState information + * ---------------- + */ +typedef struct ResultState +{ + PlanState ps; /* its first field is NodeTag */ + ExprState *resconstantqual; + bool rs_done; /* are we done? */ + bool rs_checkqual; /* do we need to check the qual? */ +} ResultState; + +/* ---------------- + * ProjectSetState information + * + * Note: at least one of the "elems" will be a SetExprState; the rest are + * regular ExprStates. + * ---------------- + */ +typedef struct ProjectSetState +{ + PlanState ps; /* its first field is NodeTag */ + Node **elems; /* array of expression states */ + ExprDoneCond *elemdone; /* array of per-SRF is-done states */ + int nelems; /* length of elemdone[] array */ + bool pending_srf_tuples; /* still evaluating srfs in tlist? */ + MemoryContext argcontext; /* context for SRF arguments */ +} ProjectSetState; + + +/* flags for mt_merge_subcommands */ +#define MERGE_INSERT 0x01 +#define MERGE_UPDATE 0x02 +#define MERGE_DELETE 0x04 + +/* ---------------- + * ModifyTableState information + * ---------------- + */ +typedef struct ModifyTableState +{ + PlanState ps; /* its first field is NodeTag */ + CmdType operation; /* INSERT, UPDATE, DELETE, or MERGE */ + bool canSetTag; /* do we set the command tag/es_processed? */ + bool mt_done; /* are we done? */ + int mt_nrels; /* number of entries in resultRelInfo[] */ + ResultRelInfo *resultRelInfo; /* info about target relation(s) */ + + /* + * Target relation mentioned in the original statement, used to fire + * statement-level triggers and as the root for tuple routing. (This + * might point to one of the resultRelInfo[] entries, but it can also be a + * distinct struct.) + */ + ResultRelInfo *rootResultRelInfo; + + EPQState mt_epqstate; /* for evaluating EvalPlanQual rechecks */ + bool fireBSTriggers; /* do we need to fire stmt triggers? */ + + /* + * These fields are used for inherited UPDATE and DELETE, to track which + * target relation a given tuple is from. If there are a lot of target + * relations, we use a hash table to translate table OIDs to + * resultRelInfo[] indexes; otherwise mt_resultOidHash is NULL. + */ + int mt_resultOidAttno; /* resno of "tableoid" junk attr */ + Oid mt_lastResultOid; /* last-seen value of tableoid */ + int mt_lastResultIndex; /* corresponding index in resultRelInfo[] */ + HTAB *mt_resultOidHash; /* optional hash table to speed lookups */ + + /* + * Slot for storing tuples in the root partitioned table's rowtype during + * an UPDATE of a partitioned table. + */ + TupleTableSlot *mt_root_tuple_slot; + + /* Tuple-routing support info */ + struct PartitionTupleRouting *mt_partition_tuple_routing; + + /* controls transition table population for specified operation */ + struct TransitionCaptureState *mt_transition_capture; + + /* controls transition table population for INSERT...ON CONFLICT UPDATE */ + struct TransitionCaptureState *mt_oc_transition_capture; + + /* Flags showing which subcommands are present INS/UPD/DEL/DO NOTHING */ + int mt_merge_subcommands; + + /* tuple counters for MERGE */ + double mt_merge_inserted; + double mt_merge_updated; + double mt_merge_deleted; +} ModifyTableState; + +/* ---------------- + * AppendState information + * + * nplans how many plans are in the array + * whichplan which synchronous plan is being executed (0 .. n-1) + * or a special negative value. See nodeAppend.c. + * prune_state details required to allow partitions to be + * eliminated from the scan, or NULL if not possible. + * valid_subplans for runtime pruning, valid synchronous appendplans + * indexes to scan. + * ---------------- + */ + +struct AppendState; +typedef struct AppendState AppendState; +struct ParallelAppendState; +typedef struct ParallelAppendState ParallelAppendState; +struct PartitionPruneState; + +struct AppendState +{ + PlanState ps; /* its first field is NodeTag */ + PlanState **appendplans; /* array of PlanStates for my inputs */ + int as_nplans; + int as_whichplan; + bool as_begun; /* false means need to initialize */ + Bitmapset *as_asyncplans; /* asynchronous plans indexes */ + int as_nasyncplans; /* # of asynchronous plans */ + AsyncRequest **as_asyncrequests; /* array of AsyncRequests */ + TupleTableSlot **as_asyncresults; /* unreturned results of async plans */ + int as_nasyncresults; /* # of valid entries in as_asyncresults */ + bool as_syncdone; /* true if all synchronous plans done in + * asynchronous mode, else false */ + int as_nasyncremain; /* # of remaining asynchronous plans */ + Bitmapset *as_needrequest; /* asynchronous plans needing a new request */ + struct WaitEventSet *as_eventset; /* WaitEventSet used to configure file + * descriptor wait events */ + int as_first_partial_plan; /* Index of 'appendplans' containing + * the first partial plan */ + ParallelAppendState *as_pstate; /* parallel coordination info */ + Size pstate_len; /* size of parallel coordination info */ + struct PartitionPruneState *as_prune_state; + Bitmapset *as_valid_subplans; + Bitmapset *as_valid_asyncplans; /* valid asynchronous plans indexes */ + bool (*choose_next_subplan) (AppendState *); +}; + +/* ---------------- + * MergeAppendState information + * + * nplans how many plans are in the array + * nkeys number of sort key columns + * sortkeys sort keys in SortSupport representation + * slots current output tuple of each subplan + * heap heap of active tuples + * initialized true if we have fetched first tuple from each subplan + * prune_state details required to allow partitions to be + * eliminated from the scan, or NULL if not possible. + * valid_subplans for runtime pruning, valid mergeplans indexes to + * scan. + * ---------------- + */ +typedef struct MergeAppendState +{ + PlanState ps; /* its first field is NodeTag */ + PlanState **mergeplans; /* array of PlanStates for my inputs */ + int ms_nplans; + int ms_nkeys; + SortSupport ms_sortkeys; /* array of length ms_nkeys */ + TupleTableSlot **ms_slots; /* array of length ms_nplans */ + struct binaryheap *ms_heap; /* binary heap of slot indices */ + bool ms_initialized; /* are subplans started? */ + struct PartitionPruneState *ms_prune_state; + Bitmapset *ms_valid_subplans; +} MergeAppendState; + +/* ---------------- + * RecursiveUnionState information + * + * RecursiveUnionState is used for performing a recursive union. + * + * recursing T when we're done scanning the non-recursive term + * intermediate_empty T if intermediate_table is currently empty + * working_table working table (to be scanned by recursive term) + * intermediate_table current recursive output (next generation of WT) + * ---------------- + */ +typedef struct RecursiveUnionState +{ + PlanState ps; /* its first field is NodeTag */ + bool recursing; + bool intermediate_empty; + Tuplestorestate *working_table; + Tuplestorestate *intermediate_table; + /* Remaining fields are unused in UNION ALL case */ + Oid *eqfuncoids; /* per-grouping-field equality fns */ + FmgrInfo *hashfunctions; /* per-grouping-field hash fns */ + MemoryContext tempContext; /* short-term context for comparisons */ + TupleHashTable hashtable; /* hash table for tuples already seen */ + MemoryContext tableContext; /* memory context containing hash table */ +} RecursiveUnionState; + +/* ---------------- + * BitmapAndState information + * ---------------- + */ +typedef struct BitmapAndState +{ + PlanState ps; /* its first field is NodeTag */ + PlanState **bitmapplans; /* array of PlanStates for my inputs */ + int nplans; /* number of input plans */ +} BitmapAndState; + +/* ---------------- + * BitmapOrState information + * ---------------- + */ +typedef struct BitmapOrState +{ + PlanState ps; /* its first field is NodeTag */ + PlanState **bitmapplans; /* array of PlanStates for my inputs */ + int nplans; /* number of input plans */ +} BitmapOrState; + +/* ---------------------------------------------------------------- + * Scan State Information + * ---------------------------------------------------------------- + */ + +/* ---------------- + * ScanState information + * + * ScanState extends PlanState for node types that represent + * scans of an underlying relation. It can also be used for nodes + * that scan the output of an underlying plan node --- in that case, + * only ScanTupleSlot is actually useful, and it refers to the tuple + * retrieved from the subplan. + * + * currentRelation relation being scanned (NULL if none) + * currentScanDesc current scan descriptor for scan (NULL if none) + * ScanTupleSlot pointer to slot in tuple table holding scan tuple + * ---------------- + */ +typedef struct ScanState +{ + PlanState ps; /* its first field is NodeTag */ + Relation ss_currentRelation; + struct TableScanDescData *ss_currentScanDesc; + TupleTableSlot *ss_ScanTupleSlot; +} ScanState; + +/* ---------------- + * SeqScanState information + * ---------------- + */ +typedef struct SeqScanState +{ + ScanState ss; /* its first field is NodeTag */ + Size pscan_len; /* size of parallel heap scan descriptor */ +} SeqScanState; + +/* ---------------- + * SampleScanState information + * ---------------- + */ +typedef struct SampleScanState +{ + ScanState ss; + List *args; /* expr states for TABLESAMPLE params */ + ExprState *repeatable; /* expr state for REPEATABLE expr */ + /* use struct pointer to avoid including tsmapi.h here */ + struct TsmRoutine *tsmroutine; /* descriptor for tablesample method */ + void *tsm_state; /* tablesample method can keep state here */ + bool use_bulkread; /* use bulkread buffer access strategy? */ + bool use_pagemode; /* use page-at-a-time visibility checking? */ + bool begun; /* false means need to call BeginSampleScan */ + uint32 seed; /* random seed */ + int64 donetuples; /* number of tuples already returned */ + bool haveblock; /* has a block for sampling been determined */ + bool done; /* exhausted all tuples? */ +} SampleScanState; + +/* + * These structs store information about index quals that don't have simple + * constant right-hand sides. See comments for ExecIndexBuildScanKeys() + * for discussion. + */ +typedef struct +{ + struct ScanKeyData *scan_key; /* scankey to put value into */ + ExprState *key_expr; /* expr to evaluate to get value */ + bool key_toastable; /* is expr's result a toastable datatype? */ +} IndexRuntimeKeyInfo; + +typedef struct +{ + struct ScanKeyData *scan_key; /* scankey to put value into */ + ExprState *array_expr; /* expr to evaluate to get array value */ + int next_elem; /* next array element to use */ + int num_elems; /* number of elems in current array value */ + Datum *elem_values; /* array of num_elems Datums */ + bool *elem_nulls; /* array of num_elems is-null flags */ +} IndexArrayKeyInfo; + +/* ---------------- + * IndexScanState information + * + * indexqualorig execution state for indexqualorig expressions + * indexorderbyorig execution state for indexorderbyorig expressions + * ScanKeys Skey structures for index quals + * NumScanKeys number of ScanKeys + * OrderByKeys Skey structures for index ordering operators + * NumOrderByKeys number of OrderByKeys + * RuntimeKeys info about Skeys that must be evaluated at runtime + * NumRuntimeKeys number of RuntimeKeys + * RuntimeKeysReady true if runtime Skeys have been computed + * RuntimeContext expr context for evaling runtime Skeys + * RelationDesc index relation descriptor + * ScanDesc index scan descriptor + * + * ReorderQueue tuples that need reordering due to re-check + * ReachedEnd have we fetched all tuples from index already? + * OrderByValues values of ORDER BY exprs of last fetched tuple + * OrderByNulls null flags for OrderByValues + * SortSupport for reordering ORDER BY exprs + * OrderByTypByVals is the datatype of order by expression pass-by-value? + * OrderByTypLens typlens of the datatypes of order by expressions + * PscanLen size of parallel index scan descriptor + * ---------------- + */ +typedef struct IndexScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *indexqualorig; + List *indexorderbyorig; + struct ScanKeyData *iss_ScanKeys; + int iss_NumScanKeys; + struct ScanKeyData *iss_OrderByKeys; + int iss_NumOrderByKeys; + IndexRuntimeKeyInfo *iss_RuntimeKeys; + int iss_NumRuntimeKeys; + bool iss_RuntimeKeysReady; + ExprContext *iss_RuntimeContext; + Relation iss_RelationDesc; + struct IndexScanDescData *iss_ScanDesc; + + /* These are needed for re-checking ORDER BY expr ordering */ + pairingheap *iss_ReorderQueue; + bool iss_ReachedEnd; + Datum *iss_OrderByValues; + bool *iss_OrderByNulls; + SortSupport iss_SortSupport; + bool *iss_OrderByTypByVals; + int16 *iss_OrderByTypLens; + Size iss_PscanLen; +} IndexScanState; + +/* ---------------- + * IndexOnlyScanState information + * + * recheckqual execution state for recheckqual expressions + * ScanKeys Skey structures for index quals + * NumScanKeys number of ScanKeys + * OrderByKeys Skey structures for index ordering operators + * NumOrderByKeys number of OrderByKeys + * RuntimeKeys info about Skeys that must be evaluated at runtime + * NumRuntimeKeys number of RuntimeKeys + * RuntimeKeysReady true if runtime Skeys have been computed + * RuntimeContext expr context for evaling runtime Skeys + * RelationDesc index relation descriptor + * ScanDesc index scan descriptor + * TableSlot slot for holding tuples fetched from the table + * VMBuffer buffer in use for visibility map testing, if any + * PscanLen size of parallel index-only scan descriptor + * ---------------- + */ +typedef struct IndexOnlyScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *recheckqual; + struct ScanKeyData *ioss_ScanKeys; + int ioss_NumScanKeys; + struct ScanKeyData *ioss_OrderByKeys; + int ioss_NumOrderByKeys; + IndexRuntimeKeyInfo *ioss_RuntimeKeys; + int ioss_NumRuntimeKeys; + bool ioss_RuntimeKeysReady; + ExprContext *ioss_RuntimeContext; + Relation ioss_RelationDesc; + struct IndexScanDescData *ioss_ScanDesc; + TupleTableSlot *ioss_TableSlot; + Buffer ioss_VMBuffer; + Size ioss_PscanLen; +} IndexOnlyScanState; + +/* ---------------- + * BitmapIndexScanState information + * + * result bitmap to return output into, or NULL + * ScanKeys Skey structures for index quals + * NumScanKeys number of ScanKeys + * RuntimeKeys info about Skeys that must be evaluated at runtime + * NumRuntimeKeys number of RuntimeKeys + * ArrayKeys info about Skeys that come from ScalarArrayOpExprs + * NumArrayKeys number of ArrayKeys + * RuntimeKeysReady true if runtime Skeys have been computed + * RuntimeContext expr context for evaling runtime Skeys + * RelationDesc index relation descriptor + * ScanDesc index scan descriptor + * ---------------- + */ +typedef struct BitmapIndexScanState +{ + ScanState ss; /* its first field is NodeTag */ + TIDBitmap *biss_result; + struct ScanKeyData *biss_ScanKeys; + int biss_NumScanKeys; + IndexRuntimeKeyInfo *biss_RuntimeKeys; + int biss_NumRuntimeKeys; + IndexArrayKeyInfo *biss_ArrayKeys; + int biss_NumArrayKeys; + bool biss_RuntimeKeysReady; + ExprContext *biss_RuntimeContext; + Relation biss_RelationDesc; + struct IndexScanDescData *biss_ScanDesc; +} BitmapIndexScanState; + +/* ---------------- + * SharedBitmapState information + * + * BM_INITIAL TIDBitmap creation is not yet started, so first worker + * to see this state will set the state to BM_INPROGRESS + * and that process will be responsible for creating + * TIDBitmap. + * BM_INPROGRESS TIDBitmap creation is in progress; workers need to + * sleep until it's finished. + * BM_FINISHED TIDBitmap creation is done, so now all workers can + * proceed to iterate over TIDBitmap. + * ---------------- + */ +typedef enum +{ + BM_INITIAL, + BM_INPROGRESS, + BM_FINISHED +} SharedBitmapState; + +/* ---------------- + * ParallelBitmapHeapState information + * tbmiterator iterator for scanning current pages + * prefetch_iterator iterator for prefetching ahead of current page + * mutex mutual exclusion for the prefetching variable + * and state + * prefetch_pages # pages prefetch iterator is ahead of current + * prefetch_target current target prefetch distance + * state current state of the TIDBitmap + * cv conditional wait variable + * phs_snapshot_data snapshot data shared to workers + * ---------------- + */ +typedef struct ParallelBitmapHeapState +{ + dsa_pointer tbmiterator; + dsa_pointer prefetch_iterator; + slock_t mutex; + int prefetch_pages; + int prefetch_target; + SharedBitmapState state; + ConditionVariable cv; + char phs_snapshot_data[FLEXIBLE_ARRAY_MEMBER]; +} ParallelBitmapHeapState; + +/* ---------------- + * BitmapHeapScanState information + * + * bitmapqualorig execution state for bitmapqualorig expressions + * tbm bitmap obtained from child index scan(s) + * tbmiterator iterator for scanning current pages + * tbmres current-page data + * can_skip_fetch can we potentially skip tuple fetches in this scan? + * return_empty_tuples number of empty tuples to return + * vmbuffer buffer for visibility-map lookups + * pvmbuffer ditto, for prefetched pages + * exact_pages total number of exact pages retrieved + * lossy_pages total number of lossy pages retrieved + * prefetch_iterator iterator for prefetching ahead of current page + * prefetch_pages # pages prefetch iterator is ahead of current + * prefetch_target current target prefetch distance + * prefetch_maximum maximum value for prefetch_target + * pscan_len size of the shared memory for parallel bitmap + * initialized is node is ready to iterate + * shared_tbmiterator shared iterator + * shared_prefetch_iterator shared iterator for prefetching + * pstate shared state for parallel bitmap scan + * ---------------- + */ +typedef struct BitmapHeapScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *bitmapqualorig; + TIDBitmap *tbm; + TBMIterator *tbmiterator; + TBMIterateResult *tbmres; + bool can_skip_fetch; + int return_empty_tuples; + Buffer vmbuffer; + Buffer pvmbuffer; + long exact_pages; + long lossy_pages; + TBMIterator *prefetch_iterator; + int prefetch_pages; + int prefetch_target; + int prefetch_maximum; + Size pscan_len; + bool initialized; + TBMSharedIterator *shared_tbmiterator; + TBMSharedIterator *shared_prefetch_iterator; + ParallelBitmapHeapState *pstate; +} BitmapHeapScanState; + +/* ---------------- + * TidScanState information + * + * tidexprs list of TidExpr structs (see nodeTidscan.c) + * isCurrentOf scan has a CurrentOfExpr qual + * NumTids number of tids in this scan + * TidPtr index of currently fetched tid + * TidList evaluated item pointers (array of size NumTids) + * htup currently-fetched tuple, if any + * ---------------- + */ +typedef struct TidScanState +{ + ScanState ss; /* its first field is NodeTag */ + List *tss_tidexprs; + bool tss_isCurrentOf; + int tss_NumTids; + int tss_TidPtr; + ItemPointerData *tss_TidList; + HeapTupleData tss_htup; +} TidScanState; + +/* ---------------- + * TidRangeScanState information + * + * trss_tidexprs list of TidOpExpr structs (see nodeTidrangescan.c) + * trss_mintid the lowest TID in the scan range + * trss_maxtid the highest TID in the scan range + * trss_inScan is a scan currently in progress? + * ---------------- + */ +typedef struct TidRangeScanState +{ + ScanState ss; /* its first field is NodeTag */ + List *trss_tidexprs; + ItemPointerData trss_mintid; + ItemPointerData trss_maxtid; + bool trss_inScan; +} TidRangeScanState; + +/* ---------------- + * SubqueryScanState information + * + * SubqueryScanState is used for scanning a sub-query in the range table. + * ScanTupleSlot references the current output tuple of the sub-query. + * ---------------- + */ +typedef struct SubqueryScanState +{ + ScanState ss; /* its first field is NodeTag */ + PlanState *subplan; +} SubqueryScanState; + +/* ---------------- + * FunctionScanState information + * + * Function nodes are used to scan the results of a + * function appearing in FROM (typically a function returning set). + * + * eflags node's capability flags + * ordinality is this scan WITH ORDINALITY? + * simple true if we have 1 function and no ordinality + * ordinal current ordinal column value + * nfuncs number of functions being executed + * funcstates per-function execution states (private in + * nodeFunctionscan.c) + * argcontext memory context to evaluate function arguments in + * ---------------- + */ +struct FunctionScanPerFuncState; + +typedef struct FunctionScanState +{ + ScanState ss; /* its first field is NodeTag */ + int eflags; + bool ordinality; + bool simple; + int64 ordinal; + int nfuncs; + struct FunctionScanPerFuncState *funcstates; /* array of length nfuncs */ + MemoryContext argcontext; +} FunctionScanState; + +/* ---------------- + * ValuesScanState information + * + * ValuesScan nodes are used to scan the results of a VALUES list + * + * rowcontext per-expression-list context + * exprlists array of expression lists being evaluated + * exprstatelists array of expression state lists, for SubPlans only + * array_len size of above arrays + * curr_idx current array index (0-based) + * + * Note: ss.ps.ps_ExprContext is used to evaluate any qual or projection + * expressions attached to the node. We create a second ExprContext, + * rowcontext, in which to build the executor expression state for each + * Values sublist. Resetting this context lets us get rid of expression + * state for each row, avoiding major memory leakage over a long values list. + * However, that doesn't work for sublists containing SubPlans, because a + * SubPlan has to be connected up to the outer plan tree to work properly. + * Therefore, for only those sublists containing SubPlans, we do expression + * state construction at executor start, and store those pointers in + * exprstatelists[]. NULL entries in that array correspond to simple + * subexpressions that are handled as described above. + * ---------------- + */ +typedef struct ValuesScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprContext *rowcontext; + List **exprlists; + List **exprstatelists; + int array_len; + int curr_idx; +} ValuesScanState; + +/* ---------------- + * TableFuncScanState node + * + * Used in table-expression functions like XMLTABLE. + * ---------------- + */ +typedef struct TableFuncScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *docexpr; /* state for document expression */ + ExprState *rowexpr; /* state for row-generating expression */ + List *colexprs; /* state for column-generating expression */ + List *coldefexprs; /* state for column default expressions */ + List *ns_names; /* same as TableFunc.ns_names */ + List *ns_uris; /* list of states of namespace URI exprs */ + Bitmapset *notnulls; /* nullability flag for each output column */ + void *opaque; /* table builder private space */ + const struct TableFuncRoutine *routine; /* table builder methods */ + FmgrInfo *in_functions; /* input function for each column */ + Oid *typioparams; /* typioparam for each column */ + int64 ordinal; /* row number to be output next */ + MemoryContext perTableCxt; /* per-table context */ + Tuplestorestate *tupstore; /* output tuple store */ +} TableFuncScanState; + +/* ---------------- + * CteScanState information + * + * CteScan nodes are used to scan a CommonTableExpr query. + * + * Multiple CteScan nodes can read out from the same CTE query. We use + * a tuplestore to hold rows that have been read from the CTE query but + * not yet consumed by all readers. + * ---------------- + */ +typedef struct CteScanState +{ + ScanState ss; /* its first field is NodeTag */ + int eflags; /* capability flags to pass to tuplestore */ + int readptr; /* index of my tuplestore read pointer */ + PlanState *cteplanstate; /* PlanState for the CTE query itself */ + /* Link to the "leader" CteScanState (possibly this same node) */ + struct CteScanState *leader; + /* The remaining fields are only valid in the "leader" CteScanState */ + Tuplestorestate *cte_table; /* rows already read from the CTE query */ + bool eof_cte; /* reached end of CTE query? */ +} CteScanState; + +/* ---------------- + * NamedTuplestoreScanState information + * + * NamedTuplestoreScan nodes are used to scan a Tuplestore created and + * named prior to execution of the query. An example is a transition + * table for an AFTER trigger. + * + * Multiple NamedTuplestoreScan nodes can read out from the same Tuplestore. + * ---------------- + */ +typedef struct NamedTuplestoreScanState +{ + ScanState ss; /* its first field is NodeTag */ + int readptr; /* index of my tuplestore read pointer */ + TupleDesc tupdesc; /* format of the tuples in the tuplestore */ + Tuplestorestate *relation; /* the rows */ +} NamedTuplestoreScanState; + +/* ---------------- + * WorkTableScanState information + * + * WorkTableScan nodes are used to scan the work table created by + * a RecursiveUnion node. We locate the RecursiveUnion node + * during executor startup. + * ---------------- + */ +typedef struct WorkTableScanState +{ + ScanState ss; /* its first field is NodeTag */ + RecursiveUnionState *rustate; +} WorkTableScanState; + +/* ---------------- + * ForeignScanState information + * + * ForeignScan nodes are used to scan foreign-data tables. + * ---------------- + */ +typedef struct ForeignScanState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *fdw_recheck_quals; /* original quals not in ss.ps.qual */ + Size pscan_len; /* size of parallel coordination information */ + ResultRelInfo *resultRelInfo; /* result rel info, if UPDATE or DELETE */ + /* use struct pointer to avoid including fdwapi.h here */ + struct FdwRoutine *fdwroutine; + void *fdw_state; /* foreign-data wrapper can keep state here */ +} ForeignScanState; + +/* ---------------- + * CustomScanState information + * + * CustomScan nodes are used to execute custom code within executor. + * + * Core code must avoid assuming that the CustomScanState is only as large as + * the structure declared here; providers are allowed to make it the first + * element in a larger structure, and typically would need to do so. The + * struct is actually allocated by the CreateCustomScanState method associated + * with the plan node. Any additional fields can be initialized there, or in + * the BeginCustomScan method. + * ---------------- + */ +struct CustomExecMethods; + +typedef struct CustomScanState +{ + ScanState ss; + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ + List *custom_ps; /* list of child PlanState nodes, if any */ + Size pscan_len; /* size of parallel coordination information */ + const struct CustomExecMethods *methods; +} CustomScanState; + +/* ---------------------------------------------------------------- + * Join State Information + * ---------------------------------------------------------------- + */ + +/* ---------------- + * JoinState information + * + * Superclass for state nodes of join plans. + * ---------------- + */ +typedef struct JoinState +{ + PlanState ps; + JoinType jointype; + bool single_match; /* True if we should skip to next outer tuple + * after finding one inner match */ + ExprState *joinqual; /* JOIN quals (in addition to ps.qual) */ +} JoinState; + +/* ---------------- + * NestLoopState information + * + * NeedNewOuter true if need new outer tuple on next call + * MatchedOuter true if found a join match for current outer tuple + * NullInnerTupleSlot prepared null tuple for left outer joins + * ---------------- + */ +typedef struct NestLoopState +{ + JoinState js; /* its first field is NodeTag */ + bool nl_NeedNewOuter; + bool nl_MatchedOuter; + TupleTableSlot *nl_NullInnerTupleSlot; +} NestLoopState; + +/* ---------------- + * MergeJoinState information + * + * NumClauses number of mergejoinable join clauses + * Clauses info for each mergejoinable clause + * JoinState current state of ExecMergeJoin state machine + * SkipMarkRestore true if we may skip Mark and Restore operations + * ExtraMarks true to issue extra Mark operations on inner scan + * ConstFalseJoin true if we have a constant-false joinqual + * FillOuter true if should emit unjoined outer tuples anyway + * FillInner true if should emit unjoined inner tuples anyway + * MatchedOuter true if found a join match for current outer tuple + * MatchedInner true if found a join match for current inner tuple + * OuterTupleSlot slot in tuple table for cur outer tuple + * InnerTupleSlot slot in tuple table for cur inner tuple + * MarkedTupleSlot slot in tuple table for marked tuple + * NullOuterTupleSlot prepared null tuple for right outer joins + * NullInnerTupleSlot prepared null tuple for left outer joins + * OuterEContext workspace for computing outer tuple's join values + * InnerEContext workspace for computing inner tuple's join values + * ---------------- + */ +/* private in nodeMergejoin.c: */ +typedef struct MergeJoinClauseData *MergeJoinClause; + +typedef struct MergeJoinState +{ + JoinState js; /* its first field is NodeTag */ + int mj_NumClauses; + MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */ + int mj_JoinState; + bool mj_SkipMarkRestore; + bool mj_ExtraMarks; + bool mj_ConstFalseJoin; + bool mj_FillOuter; + bool mj_FillInner; + bool mj_MatchedOuter; + bool mj_MatchedInner; + TupleTableSlot *mj_OuterTupleSlot; + TupleTableSlot *mj_InnerTupleSlot; + TupleTableSlot *mj_MarkedTupleSlot; + TupleTableSlot *mj_NullOuterTupleSlot; + TupleTableSlot *mj_NullInnerTupleSlot; + ExprContext *mj_OuterEContext; + ExprContext *mj_InnerEContext; +} MergeJoinState; + +/* ---------------- + * HashJoinState information + * + * hashclauses original form of the hashjoin condition + * hj_OuterHashKeys the outer hash keys in the hashjoin condition + * hj_HashOperators the join operators in the hashjoin condition + * hj_HashTable hash table for the hashjoin + * (NULL if table not built yet) + * hj_CurHashValue hash value for current outer tuple + * hj_CurBucketNo regular bucket# for current outer tuple + * hj_CurSkewBucketNo skew bucket# for current outer tuple + * hj_CurTuple last inner tuple matched to current outer + * tuple, or NULL if starting search + * (hj_CurXXX variables are undefined if + * OuterTupleSlot is empty!) + * hj_OuterTupleSlot tuple slot for outer tuples + * hj_HashTupleSlot tuple slot for inner (hashed) tuples + * hj_NullOuterTupleSlot prepared null tuple for right/full outer joins + * hj_NullInnerTupleSlot prepared null tuple for left/full outer joins + * hj_FirstOuterTupleSlot first tuple retrieved from outer plan + * hj_JoinState current state of ExecHashJoin state machine + * hj_MatchedOuter true if found a join match for current outer + * hj_OuterNotEmpty true if outer relation known not empty + * ---------------- + */ + +/* these structs are defined in executor/hashjoin.h: */ +typedef struct HashJoinTupleData *HashJoinTuple; +typedef struct HashJoinTableData *HashJoinTable; + +typedef struct HashJoinState +{ + JoinState js; /* its first field is NodeTag */ + ExprState *hashclauses; + List *hj_OuterHashKeys; /* list of ExprState nodes */ + List *hj_HashOperators; /* list of operator OIDs */ + List *hj_Collations; + HashJoinTable hj_HashTable; + uint32 hj_CurHashValue; + int hj_CurBucketNo; + int hj_CurSkewBucketNo; + HashJoinTuple hj_CurTuple; + TupleTableSlot *hj_OuterTupleSlot; + TupleTableSlot *hj_HashTupleSlot; + TupleTableSlot *hj_NullOuterTupleSlot; + TupleTableSlot *hj_NullInnerTupleSlot; + TupleTableSlot *hj_FirstOuterTupleSlot; + int hj_JoinState; + bool hj_MatchedOuter; + bool hj_OuterNotEmpty; +} HashJoinState; + + +/* ---------------------------------------------------------------- + * Materialization State Information + * ---------------------------------------------------------------- + */ + +/* ---------------- + * MaterialState information + * + * materialize nodes are used to materialize the results + * of a subplan into a temporary file. + * + * ss.ss_ScanTupleSlot refers to output of underlying plan. + * ---------------- + */ +typedef struct MaterialState +{ + ScanState ss; /* its first field is NodeTag */ + int eflags; /* capability flags to pass to tuplestore */ + bool eof_underlying; /* reached end of underlying plan? */ + Tuplestorestate *tuplestorestate; +} MaterialState; + +struct MemoizeEntry; +struct MemoizeTuple; +struct MemoizeKey; + +typedef struct MemoizeInstrumentation +{ + uint64 cache_hits; /* number of rescans where we've found the + * scan parameter values to be cached */ + uint64 cache_misses; /* number of rescans where we've not found the + * scan parameter values to be cached. */ + uint64 cache_evictions; /* number of cache entries removed due to + * the need to free memory */ + uint64 cache_overflows; /* number of times we've had to bypass the + * cache when filling it due to not being + * able to free enough space to store the + * current scan's tuples. */ + uint64 mem_peak; /* peak memory usage in bytes */ +} MemoizeInstrumentation; + +/* ---------------- + * Shared memory container for per-worker memoize information + * ---------------- + */ +typedef struct SharedMemoizeInfo +{ + int num_workers; + MemoizeInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]; +} SharedMemoizeInfo; + +/* ---------------- + * MemoizeState information + * + * memoize nodes are used to cache recent and commonly seen results from + * a parameterized scan. + * ---------------- + */ +typedef struct MemoizeState +{ + ScanState ss; /* its first field is NodeTag */ + int mstatus; /* value of ExecMemoize state machine */ + int nkeys; /* number of cache keys */ + struct memoize_hash *hashtable; /* hash table for cache entries */ + TupleDesc hashkeydesc; /* tuple descriptor for cache keys */ + TupleTableSlot *tableslot; /* min tuple slot for existing cache entries */ + TupleTableSlot *probeslot; /* virtual slot used for hash lookups */ + ExprState *cache_eq_expr; /* Compare exec params to hash key */ + ExprState **param_exprs; /* exprs containing the parameters to this + * node */ + FmgrInfo *hashfunctions; /* lookup data for hash funcs nkeys in size */ + Oid *collations; /* collation for comparisons nkeys in size */ + uint64 mem_used; /* bytes of memory used by cache */ + uint64 mem_limit; /* memory limit in bytes for the cache */ + MemoryContext tableContext; /* memory context to store cache data */ + dlist_head lru_list; /* least recently used entry list */ + struct MemoizeTuple *last_tuple; /* Used to point to the last tuple + * returned during a cache hit and the + * tuple we last stored when + * populating the cache. */ + struct MemoizeEntry *entry; /* the entry that 'last_tuple' belongs to or + * NULL if 'last_tuple' is NULL. */ + bool singlerow; /* true if the cache entry is to be marked as + * complete after caching the first tuple. */ + bool binary_mode; /* true when cache key should be compared bit + * by bit, false when using hash equality ops */ + MemoizeInstrumentation stats; /* execution statistics */ + SharedMemoizeInfo *shared_info; /* statistics for parallel workers */ + Bitmapset *keyparamids; /* Param->paramids of expressions belonging to + * param_exprs */ +} MemoizeState; + +/* ---------------- + * When performing sorting by multiple keys, it's possible that the input + * dataset is already sorted on a prefix of those keys. We call these + * "presorted keys". + * PresortedKeyData represents information about one such key. + * ---------------- + */ +typedef struct PresortedKeyData +{ + FmgrInfo flinfo; /* comparison function info */ + FunctionCallInfo fcinfo; /* comparison function call info */ + OffsetNumber attno; /* attribute number in tuple */ +} PresortedKeyData; + +/* ---------------- + * Shared memory container for per-worker sort information + * ---------------- + */ +typedef struct SharedSortInfo +{ + int num_workers; + TuplesortInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]; +} SharedSortInfo; + +/* ---------------- + * SortState information + * ---------------- + */ +typedef struct SortState +{ + ScanState ss; /* its first field is NodeTag */ + bool randomAccess; /* need random access to sort output? */ + bool bounded; /* is the result set bounded? */ + int64 bound; /* if bounded, how many tuples are needed */ + bool sort_Done; /* sort completed yet? */ + bool bounded_Done; /* value of bounded we did the sort with */ + int64 bound_Done; /* value of bound we did the sort with */ + void *tuplesortstate; /* private state of tuplesort.c */ + bool am_worker; /* are we a worker? */ + bool datumSort; /* Datum sort instead of tuple sort? */ + SharedSortInfo *shared_info; /* one entry per worker */ +} SortState; + +/* ---------------- + * Instrumentation information for IncrementalSort + * ---------------- + */ +typedef struct IncrementalSortGroupInfo +{ + int64 groupCount; + int64 maxDiskSpaceUsed; + int64 totalDiskSpaceUsed; + int64 maxMemorySpaceUsed; + int64 totalMemorySpaceUsed; + bits32 sortMethods; /* bitmask of TuplesortMethod */ +} IncrementalSortGroupInfo; + +typedef struct IncrementalSortInfo +{ + IncrementalSortGroupInfo fullsortGroupInfo; + IncrementalSortGroupInfo prefixsortGroupInfo; +} IncrementalSortInfo; + +/* ---------------- + * Shared memory container for per-worker incremental sort information + * ---------------- + */ +typedef struct SharedIncrementalSortInfo +{ + int num_workers; + IncrementalSortInfo sinfo[FLEXIBLE_ARRAY_MEMBER]; +} SharedIncrementalSortInfo; + +/* ---------------- + * IncrementalSortState information + * ---------------- + */ +typedef enum +{ + INCSORT_LOADFULLSORT, + INCSORT_LOADPREFIXSORT, + INCSORT_READFULLSORT, + INCSORT_READPREFIXSORT, +} IncrementalSortExecutionStatus; + +typedef struct IncrementalSortState +{ + ScanState ss; /* its first field is NodeTag */ + bool bounded; /* is the result set bounded? */ + int64 bound; /* if bounded, how many tuples are needed */ + bool outerNodeDone; /* finished fetching tuples from outer node */ + int64 bound_Done; /* value of bound we did the sort with */ + IncrementalSortExecutionStatus execution_status; + int64 n_fullsort_remaining; + Tuplesortstate *fullsort_state; /* private state of tuplesort.c */ + Tuplesortstate *prefixsort_state; /* private state of tuplesort.c */ + /* the keys by which the input path is already sorted */ + PresortedKeyData *presorted_keys; + + IncrementalSortInfo incsort_info; + + /* slot for pivot tuple defining values of presorted keys within group */ + TupleTableSlot *group_pivot; + TupleTableSlot *transfer_tuple; + bool am_worker; /* are we a worker? */ + SharedIncrementalSortInfo *shared_info; /* one entry per worker */ +} IncrementalSortState; + +/* --------------------- + * GroupState information + * --------------------- + */ +typedef struct GroupState +{ + ScanState ss; /* its first field is NodeTag */ + ExprState *eqfunction; /* equality function */ + bool grp_done; /* indicates completion of Group scan */ +} GroupState; + +/* --------------------- + * per-worker aggregate information + * --------------------- + */ +typedef struct AggregateInstrumentation +{ + Size hash_mem_peak; /* peak hash table memory usage */ + uint64 hash_disk_used; /* kB of disk space used */ + int hash_batches_used; /* batches used during entire execution */ +} AggregateInstrumentation; + +/* ---------------- + * Shared memory container for per-worker aggregate information + * ---------------- + */ +typedef struct SharedAggInfo +{ + int num_workers; + AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]; +} SharedAggInfo; + +/* --------------------- + * AggState information + * + * ss.ss_ScanTupleSlot refers to output of underlying plan. + * + * Note: ss.ps.ps_ExprContext contains ecxt_aggvalues and + * ecxt_aggnulls arrays, which hold the computed agg values for the current + * input group during evaluation of an Agg node's output tuple(s). We + * create a second ExprContext, tmpcontext, in which to evaluate input + * expressions and run the aggregate transition functions. + * --------------------- + */ +/* these structs are private in nodeAgg.c: */ +typedef struct AggStatePerAggData *AggStatePerAgg; +typedef struct AggStatePerTransData *AggStatePerTrans; +typedef struct AggStatePerGroupData *AggStatePerGroup; +typedef struct AggStatePerPhaseData *AggStatePerPhase; +typedef struct AggStatePerHashData *AggStatePerHash; + +typedef struct AggState +{ + ScanState ss; /* its first field is NodeTag */ + List *aggs; /* all Aggref nodes in targetlist & quals */ + int numaggs; /* length of list (could be zero!) */ + int numtrans; /* number of pertrans items */ + AggStrategy aggstrategy; /* strategy mode */ + AggSplit aggsplit; /* agg-splitting mode, see nodes.h */ + AggStatePerPhase phase; /* pointer to current phase data */ + int numphases; /* number of phases (including phase 0) */ + int current_phase; /* current phase number */ + AggStatePerAgg peragg; /* per-Aggref information */ + AggStatePerTrans pertrans; /* per-Trans state information */ + ExprContext *hashcontext; /* econtexts for long-lived data (hashtable) */ + ExprContext **aggcontexts; /* econtexts for long-lived data (per GS) */ + ExprContext *tmpcontext; /* econtext for input expressions */ +#define FIELDNO_AGGSTATE_CURAGGCONTEXT 14 + ExprContext *curaggcontext; /* currently active aggcontext */ + AggStatePerAgg curperagg; /* currently active aggregate, if any */ +#define FIELDNO_AGGSTATE_CURPERTRANS 16 + AggStatePerTrans curpertrans; /* currently active trans state, if any */ + bool input_done; /* indicates end of input */ + bool agg_done; /* indicates completion of Agg scan */ + int projected_set; /* The last projected grouping set */ +#define FIELDNO_AGGSTATE_CURRENT_SET 20 + int current_set; /* The current grouping set being evaluated */ + Bitmapset *grouped_cols; /* grouped cols in current projection */ + List *all_grouped_cols; /* list of all grouped cols in DESC order */ + Bitmapset *colnos_needed; /* all columns needed from the outer plan */ + int max_colno_needed; /* highest colno needed from outer plan */ + bool all_cols_needed; /* are all cols from outer plan needed? */ + /* These fields are for grouping set phase data */ + int maxsets; /* The max number of sets in any phase */ + AggStatePerPhase phases; /* array of all phases */ + Tuplesortstate *sort_in; /* sorted input to phases > 1 */ + Tuplesortstate *sort_out; /* input is copied here for next phase */ + TupleTableSlot *sort_slot; /* slot for sort results */ + /* these fields are used in AGG_PLAIN and AGG_SORTED modes: */ + AggStatePerGroup *pergroups; /* grouping set indexed array of per-group + * pointers */ + HeapTuple grp_firstTuple; /* copy of first tuple of current group */ + /* these fields are used in AGG_HASHED and AGG_MIXED modes: */ + bool table_filled; /* hash table filled yet? */ + int num_hashes; + MemoryContext hash_metacxt; /* memory for hash table itself */ + struct LogicalTapeSet *hash_tapeset; /* tape set for hash spill tapes */ + struct HashAggSpill *hash_spills; /* HashAggSpill for each grouping set, + * exists only during first pass */ + TupleTableSlot *hash_spill_rslot; /* for reading spill files */ + TupleTableSlot *hash_spill_wslot; /* for writing spill files */ + List *hash_batches; /* hash batches remaining to be processed */ + bool hash_ever_spilled; /* ever spilled during this execution? */ + bool hash_spill_mode; /* we hit a limit during the current batch + * and we must not create new groups */ + Size hash_mem_limit; /* limit before spilling hash table */ + uint64 hash_ngroups_limit; /* limit before spilling hash table */ + int hash_planned_partitions; /* number of partitions planned + * for first pass */ + double hashentrysize; /* estimate revised during execution */ + Size hash_mem_peak; /* peak hash table memory usage */ + uint64 hash_ngroups_current; /* number of groups currently in + * memory in all hash tables */ + uint64 hash_disk_used; /* kB of disk space used */ + int hash_batches_used; /* batches used during entire execution */ + + AggStatePerHash perhash; /* array of per-hashtable data */ + AggStatePerGroup *hash_pergroup; /* grouping set indexed array of + * per-group pointers */ + + /* support for evaluation of agg input expressions: */ +#define FIELDNO_AGGSTATE_ALL_PERGROUPS 53 + AggStatePerGroup *all_pergroups; /* array of first ->pergroups, than + * ->hash_pergroup */ + ProjectionInfo *combinedproj; /* projection machinery */ + SharedAggInfo *shared_info; /* one entry per worker */ +} AggState; + +/* ---------------- + * WindowAggState information + * ---------------- + */ +/* these structs are private in nodeWindowAgg.c: */ +typedef struct WindowStatePerFuncData *WindowStatePerFunc; +typedef struct WindowStatePerAggData *WindowStatePerAgg; + +/* + * WindowAggStatus -- Used to track the status of WindowAggState + */ +typedef enum WindowAggStatus +{ + WINDOWAGG_DONE, /* No more processing to do */ + WINDOWAGG_RUN, /* Normal processing of window funcs */ + WINDOWAGG_PASSTHROUGH, /* Don't eval window funcs */ + WINDOWAGG_PASSTHROUGH_STRICT /* Pass-through plus don't store new + * tuples during spool */ +} WindowAggStatus; + +typedef struct WindowAggState +{ + ScanState ss; /* its first field is NodeTag */ + + /* these fields are filled in by ExecInitExpr: */ + List *funcs; /* all WindowFunc nodes in targetlist */ + int numfuncs; /* total number of window functions */ + int numaggs; /* number that are plain aggregates */ + + WindowStatePerFunc perfunc; /* per-window-function information */ + WindowStatePerAgg peragg; /* per-plain-aggregate information */ + ExprState *partEqfunction; /* equality funcs for partition columns */ + ExprState *ordEqfunction; /* equality funcs for ordering columns */ + Tuplestorestate *buffer; /* stores rows of current partition */ + int current_ptr; /* read pointer # for current row */ + int framehead_ptr; /* read pointer # for frame head, if used */ + int frametail_ptr; /* read pointer # for frame tail, if used */ + int grouptail_ptr; /* read pointer # for group tail, if used */ + int64 spooled_rows; /* total # of rows in buffer */ + int64 currentpos; /* position of current row in partition */ + int64 frameheadpos; /* current frame head position */ + int64 frametailpos; /* current frame tail position (frame end+1) */ + /* use struct pointer to avoid including windowapi.h here */ + struct WindowObjectData *agg_winobj; /* winobj for aggregate fetches */ + int64 aggregatedbase; /* start row for current aggregates */ + int64 aggregatedupto; /* rows before this one are aggregated */ + WindowAggStatus status; /* run status of WindowAggState */ + + int frameOptions; /* frame_clause options, see WindowDef */ + ExprState *startOffset; /* expression for starting bound offset */ + ExprState *endOffset; /* expression for ending bound offset */ + Datum startOffsetValue; /* result of startOffset evaluation */ + Datum endOffsetValue; /* result of endOffset evaluation */ + + /* these fields are used with RANGE offset PRECEDING/FOLLOWING: */ + FmgrInfo startInRangeFunc; /* in_range function for startOffset */ + FmgrInfo endInRangeFunc; /* in_range function for endOffset */ + Oid inRangeColl; /* collation for in_range tests */ + bool inRangeAsc; /* use ASC sort order for in_range tests? */ + bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ + + /* these fields are used in GROUPS mode: */ + int64 currentgroup; /* peer group # of current row in partition */ + int64 frameheadgroup; /* peer group # of frame head row */ + int64 frametailgroup; /* peer group # of frame tail row */ + int64 groupheadpos; /* current row's peer group head position */ + int64 grouptailpos; /* " " " " tail position (group end+1) */ + + MemoryContext partcontext; /* context for partition-lifespan data */ + MemoryContext aggcontext; /* shared context for aggregate working data */ + MemoryContext curaggcontext; /* current aggregate's working data */ + ExprContext *tmpcontext; /* short-term evaluation context */ + + ExprState *runcondition; /* Condition which must remain true otherwise + * execution of the WindowAgg will finish or + * go into pass-through mode. NULL when there + * is no such condition. */ + + bool use_pass_through; /* When false, stop execution when + * runcondition is no longer true. Else + * just stop evaluating window funcs. */ + bool top_window; /* true if this is the top-most WindowAgg or + * the only WindowAgg in this query level */ + bool all_first; /* true if the scan is starting */ + bool partition_spooled; /* true if all tuples in current partition + * have been spooled into tuplestore */ + bool more_partitions; /* true if there's more partitions after + * this one */ + bool framehead_valid; /* true if frameheadpos is known up to + * date for current row */ + bool frametail_valid; /* true if frametailpos is known up to + * date for current row */ + bool grouptail_valid; /* true if grouptailpos is known up to + * date for current row */ + + TupleTableSlot *first_part_slot; /* first tuple of current or next + * partition */ + TupleTableSlot *framehead_slot; /* first tuple of current frame */ + TupleTableSlot *frametail_slot; /* first tuple after current frame */ + + /* temporary slots for tuples fetched back from tuplestore */ + TupleTableSlot *agg_row_slot; + TupleTableSlot *temp_slot_1; + TupleTableSlot *temp_slot_2; +} WindowAggState; + +/* ---------------- + * UniqueState information + * + * Unique nodes are used "on top of" sort nodes to discard + * duplicate tuples returned from the sort phase. Basically + * all it does is compare the current tuple from the subplan + * with the previously fetched tuple (stored in its result slot). + * If the two are identical in all interesting fields, then + * we just fetch another tuple from the sort and try again. + * ---------------- + */ +typedef struct UniqueState +{ + PlanState ps; /* its first field is NodeTag */ + ExprState *eqfunction; /* tuple equality qual */ +} UniqueState; + +/* ---------------- + * GatherState information + * + * Gather nodes launch 1 or more parallel workers, run a subplan + * in those workers, and collect the results. + * ---------------- + */ +typedef struct GatherState +{ + PlanState ps; /* its first field is NodeTag */ + bool initialized; /* workers launched? */ + bool need_to_scan_locally; /* need to read from local plan? */ + int64 tuples_needed; /* tuple bound, see ExecSetTupleBound */ + /* these fields are set up once: */ + TupleTableSlot *funnel_slot; + struct ParallelExecutorInfo *pei; + /* all remaining fields are reinitialized during a rescan: */ + int nworkers_launched; /* original number of workers */ + int nreaders; /* number of still-active workers */ + int nextreader; /* next one to try to read from */ + struct TupleQueueReader **reader; /* array with nreaders active entries */ +} GatherState; + +/* ---------------- + * GatherMergeState information + * + * Gather merge nodes launch 1 or more parallel workers, run a + * subplan which produces sorted output in each worker, and then + * merge the results into a single sorted stream. + * ---------------- + */ +struct GMReaderTupleBuffer; /* private in nodeGatherMerge.c */ + +typedef struct GatherMergeState +{ + PlanState ps; /* its first field is NodeTag */ + bool initialized; /* workers launched? */ + bool gm_initialized; /* gather_merge_init() done? */ + bool need_to_scan_locally; /* need to read from local plan? */ + int64 tuples_needed; /* tuple bound, see ExecSetTupleBound */ + /* these fields are set up once: */ + TupleDesc tupDesc; /* descriptor for subplan result tuples */ + int gm_nkeys; /* number of sort columns */ + SortSupport gm_sortkeys; /* array of length gm_nkeys */ + struct ParallelExecutorInfo *pei; + /* all remaining fields are reinitialized during a rescan */ + /* (but the arrays are not reallocated, just cleared) */ + int nworkers_launched; /* original number of workers */ + int nreaders; /* number of active workers */ + TupleTableSlot **gm_slots; /* array with nreaders+1 entries */ + struct TupleQueueReader **reader; /* array with nreaders active entries */ + struct GMReaderTupleBuffer *gm_tuple_buffers; /* nreaders tuple buffers */ + struct binaryheap *gm_heap; /* binary heap of slot indices */ +} GatherMergeState; + +/* ---------------- + * Values displayed by EXPLAIN ANALYZE + * ---------------- + */ +typedef struct HashInstrumentation +{ + int nbuckets; /* number of buckets at end of execution */ + int nbuckets_original; /* planned number of buckets */ + int nbatch; /* number of batches at end of execution */ + int nbatch_original; /* planned number of batches */ + Size space_peak; /* peak memory usage in bytes */ +} HashInstrumentation; + +/* ---------------- + * Shared memory container for per-worker hash information + * ---------------- + */ +typedef struct SharedHashInfo +{ + int num_workers; + HashInstrumentation hinstrument[FLEXIBLE_ARRAY_MEMBER]; +} SharedHashInfo; + +/* ---------------- + * HashState information + * ---------------- + */ +typedef struct HashState +{ + PlanState ps; /* its first field is NodeTag */ + HashJoinTable hashtable; /* hash table for the hashjoin */ + List *hashkeys; /* list of ExprState nodes */ + + /* + * In a parallelized hash join, the leader retains a pointer to the + * shared-memory stats area in its shared_info field, and then copies the + * shared-memory info back to local storage before DSM shutdown. The + * shared_info field remains NULL in workers, or in non-parallel joins. + */ + SharedHashInfo *shared_info; + + /* + * If we are collecting hash stats, this points to an initially-zeroed + * collection area, which could be either local storage or in shared + * memory; either way it's for just one process. + */ + HashInstrumentation *hinstrument; + + /* Parallel hash state. */ + struct ParallelHashJoinState *parallel_state; +} HashState; + +/* ---------------- + * SetOpState information + * + * Even in "sorted" mode, SetOp nodes are more complex than a simple + * Unique, since we have to count how many duplicates to return. But + * we also support hashing, so this is really more like a cut-down + * form of Agg. + * ---------------- + */ +/* this struct is private in nodeSetOp.c: */ +typedef struct SetOpStatePerGroupData *SetOpStatePerGroup; + +typedef struct SetOpState +{ + PlanState ps; /* its first field is NodeTag */ + ExprState *eqfunction; /* equality comparator */ + Oid *eqfuncoids; /* per-grouping-field equality fns */ + FmgrInfo *hashfunctions; /* per-grouping-field hash fns */ + bool setop_done; /* indicates completion of output scan */ + long numOutput; /* number of dups left to output */ + /* these fields are used in SETOP_SORTED mode: */ + SetOpStatePerGroup pergroup; /* per-group working state */ + HeapTuple grp_firstTuple; /* copy of first tuple of current group */ + /* these fields are used in SETOP_HASHED mode: */ + TupleHashTable hashtable; /* hash table with one entry per group */ + MemoryContext tableContext; /* memory context containing hash table */ + bool table_filled; /* hash table filled yet? */ + TupleHashIterator hashiter; /* for iterating through hash table */ +} SetOpState; + +/* ---------------- + * LockRowsState information + * + * LockRows nodes are used to enforce FOR [KEY] UPDATE/SHARE locking. + * ---------------- + */ +typedef struct LockRowsState +{ + PlanState ps; /* its first field is NodeTag */ + List *lr_arowMarks; /* List of ExecAuxRowMarks */ + EPQState lr_epqstate; /* for evaluating EvalPlanQual rechecks */ +} LockRowsState; + +/* ---------------- + * LimitState information + * + * Limit nodes are used to enforce LIMIT/OFFSET clauses. + * They just select the desired subrange of their subplan's output. + * + * offset is the number of initial tuples to skip (0 does nothing). + * count is the number of tuples to return after skipping the offset tuples. + * If no limit count was specified, count is undefined and noCount is true. + * When lstate == LIMIT_INITIAL, offset/count/noCount haven't been set yet. + * ---------------- + */ +typedef enum +{ + LIMIT_INITIAL, /* initial state for LIMIT node */ + LIMIT_RESCAN, /* rescan after recomputing parameters */ + LIMIT_EMPTY, /* there are no returnable rows */ + LIMIT_INWINDOW, /* have returned a row in the window */ + LIMIT_WINDOWEND_TIES, /* have returned a tied row */ + LIMIT_SUBPLANEOF, /* at EOF of subplan (within window) */ + LIMIT_WINDOWEND, /* stepped off end of window */ + LIMIT_WINDOWSTART /* stepped off beginning of window */ +} LimitStateCond; + +typedef struct LimitState +{ + PlanState ps; /* its first field is NodeTag */ + ExprState *limitOffset; /* OFFSET parameter, or NULL if none */ + ExprState *limitCount; /* COUNT parameter, or NULL if none */ + LimitOption limitOption; /* limit specification type */ + int64 offset; /* current OFFSET value */ + int64 count; /* current COUNT, if any */ + bool noCount; /* if true, ignore count */ + LimitStateCond lstate; /* state machine status, as above */ + int64 position; /* 1-based index of last tuple returned */ + TupleTableSlot *subSlot; /* tuple last obtained from subplan */ + ExprState *eqfunction; /* tuple equality qual in case of WITH TIES + * option */ + TupleTableSlot *last_slot; /* slot for evaluation of ties */ +} LimitState; + +#endif /* EXECNODES_H */ diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h new file mode 100644 index 0000000..6244c8d --- /dev/null +++ b/src/include/nodes/extensible.h @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------- + * + * extensible.h + * Definitions for extensible nodes and custom scans + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/extensible.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXTENSIBLE_H +#define EXTENSIBLE_H + +#include "access/parallel.h" +#include "commands/explain.h" +#include "nodes/execnodes.h" +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + +/* maximum length of an extensible node identifier */ +#define EXTNODENAME_MAX_LEN 64 + +/* + * An extensible node is a new type of node defined by an extension. The + * type is always T_ExtensibleNode, while the extnodename identifies the + * specific type of node. extnodename can be looked up to find the + * ExtensibleNodeMethods for this node type. + */ +typedef struct ExtensibleNode +{ + NodeTag type; + const char *extnodename; /* identifier of ExtensibleNodeMethods */ +} ExtensibleNode; + +/* + * node_size is the size of an extensible node of this type in bytes. + * + * nodeCopy is a function which performs a deep copy from oldnode to newnode. + * It does not need to copy type or extnodename, which are copied by the + * core system. + * + * nodeEqual is a function which performs a deep equality comparison between + * a and b and returns true or false accordingly. It does not need to compare + * type or extnodename, which are compared by the core system. + * + * nodeOut is a serialization function for the node type. It should use the + * output conventions typical for outfuncs.c. It does not need to output + * type or extnodename; the core system handles those. + * + * nodeRead is a deserialization function for the node type. It does not need + * to read type or extnodename; the core system handles those. It should fetch + * the next token using pg_strtok() from the current input stream, and then + * reconstruct the private fields according to the manner in readfuncs.c. + * + * All callbacks are mandatory. + */ +typedef struct ExtensibleNodeMethods +{ + const char *extnodename; + Size node_size; + void (*nodeCopy) (struct ExtensibleNode *newnode, + const struct ExtensibleNode *oldnode); + bool (*nodeEqual) (const struct ExtensibleNode *a, + const struct ExtensibleNode *b); + void (*nodeOut) (struct StringInfoData *str, + const struct ExtensibleNode *node); + void (*nodeRead) (struct ExtensibleNode *node); +} ExtensibleNodeMethods; + +extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method); +extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name, + bool missing_ok); + +/* + * Flags for custom paths, indicating what capabilities the resulting scan + * will have. The flags fields of CustomPath and CustomScan nodes are + * bitmasks of these flags. + */ +#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001 +#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002 +#define CUSTOMPATH_SUPPORT_PROJECTION 0x0004 + +/* + * Custom path methods. Mostly, we just need to know how to convert a + * CustomPath to a plan. + */ +typedef struct CustomPathMethods +{ + const char *CustomName; + + /* Convert Path to a Plan */ + struct Plan *(*PlanCustomPath) (PlannerInfo *root, + RelOptInfo *rel, + struct CustomPath *best_path, + List *tlist, + List *clauses, + List *custom_plans); + struct List *(*ReparameterizeCustomPathByChild) (PlannerInfo *root, + List *custom_private, + RelOptInfo *child_rel); +} CustomPathMethods; + +/* + * Custom scan. Here again, there's not much to do: we need to be able to + * generate a ScanState corresponding to the scan. + */ +typedef struct CustomScanMethods +{ + const char *CustomName; + + /* Create execution state (CustomScanState) from a CustomScan plan node */ + Node *(*CreateCustomScanState) (CustomScan *cscan); +} CustomScanMethods; + +/* + * Execution-time methods for a CustomScanState. This is more complex than + * what we need for a custom path or scan. + */ +typedef struct CustomExecMethods +{ + const char *CustomName; + + /* Required executor methods */ + void (*BeginCustomScan) (CustomScanState *node, + EState *estate, + int eflags); + TupleTableSlot *(*ExecCustomScan) (CustomScanState *node); + void (*EndCustomScan) (CustomScanState *node); + void (*ReScanCustomScan) (CustomScanState *node); + + /* Optional methods: needed if mark/restore is supported */ + void (*MarkPosCustomScan) (CustomScanState *node); + void (*RestrPosCustomScan) (CustomScanState *node); + + /* Optional methods: needed if parallel execution is supported */ + Size (*EstimateDSMCustomScan) (CustomScanState *node, + ParallelContext *pcxt); + void (*InitializeDSMCustomScan) (CustomScanState *node, + ParallelContext *pcxt, + void *coordinate); + void (*ReInitializeDSMCustomScan) (CustomScanState *node, + ParallelContext *pcxt, + void *coordinate); + void (*InitializeWorkerCustomScan) (CustomScanState *node, + shm_toc *toc, + void *coordinate); + void (*ShutdownCustomScan) (CustomScanState *node); + + /* Optional: print additional information in EXPLAIN */ + void (*ExplainCustomScan) (CustomScanState *node, + List *ancestors, + ExplainState *es); +} CustomExecMethods; + +extern void RegisterCustomScanMethods(const CustomScanMethods *methods); +extern const CustomScanMethods *GetCustomScanMethods(const char *CustomName, + bool missing_ok); + +#endif /* EXTENSIBLE_H */ diff --git a/src/include/nodes/lockoptions.h b/src/include/nodes/lockoptions.h new file mode 100644 index 0000000..399f729 --- /dev/null +++ b/src/include/nodes/lockoptions.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * lockoptions.h + * Common header for some locking-related declarations. + * + * + * Copyright (c) 2014-2022, PostgreSQL Global Development Group + * + * src/include/nodes/lockoptions.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOCKOPTIONS_H +#define LOCKOPTIONS_H + +/* + * This enum represents the different strengths of FOR UPDATE/SHARE clauses. + * The ordering here is important, because the highest numerical value takes + * precedence when a RTE is specified multiple ways. See applyLockingClause. + */ +typedef enum LockClauseStrength +{ + LCS_NONE, /* no such clause - only used in PlanRowMark */ + LCS_FORKEYSHARE, /* FOR KEY SHARE */ + LCS_FORSHARE, /* FOR SHARE */ + LCS_FORNOKEYUPDATE, /* FOR NO KEY UPDATE */ + LCS_FORUPDATE /* FOR UPDATE */ +} LockClauseStrength; + +/* + * This enum controls how to deal with rows being locked by FOR UPDATE/SHARE + * clauses (i.e., it represents the NOWAIT and SKIP LOCKED options). + * The ordering here is important, because the highest numerical value takes + * precedence when a RTE is specified multiple ways. See applyLockingClause. + */ +typedef enum LockWaitPolicy +{ + /* Wait for the lock to become available (default behavior) */ + LockWaitBlock, + /* Skip rows that can't be locked (SKIP LOCKED) */ + LockWaitSkip, + /* Raise an error if a row cannot be locked (NOWAIT) */ + LockWaitError +} LockWaitPolicy; + +/* + * Possible lock modes for a tuple. + */ +typedef enum LockTupleMode +{ + /* SELECT FOR KEY SHARE */ + LockTupleKeyShare, + /* SELECT FOR SHARE */ + LockTupleShare, + /* SELECT FOR NO KEY UPDATE, and UPDATEs that don't modify key columns */ + LockTupleNoKeyExclusive, + /* SELECT FOR UPDATE, UPDATEs that modify key columns, and DELETE */ + LockTupleExclusive +} LockTupleMode; + +#endif /* LOCKOPTIONS_H */ diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h new file mode 100644 index 0000000..50de4c6 --- /dev/null +++ b/src/include/nodes/makefuncs.h @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------- + * + * makefuncs.h + * prototypes for the creator functions of various nodes + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/makefuncs.h + * + *------------------------------------------------------------------------- + */ +#ifndef MAKEFUNC_H +#define MAKEFUNC_H + +#include "nodes/execnodes.h" +#include "nodes/parsenodes.h" + + +extern A_Expr *makeA_Expr(A_Expr_Kind kind, List *name, + Node *lexpr, Node *rexpr, int location); + +extern A_Expr *makeSimpleA_Expr(A_Expr_Kind kind, char *name, + Node *lexpr, Node *rexpr, int location); + +extern Var *makeVar(int varno, + AttrNumber varattno, + Oid vartype, + int32 vartypmod, + Oid varcollid, + Index varlevelsup); + +extern Var *makeVarFromTargetEntry(int varno, + TargetEntry *tle); + +extern Var *makeWholeRowVar(RangeTblEntry *rte, + int varno, + Index varlevelsup, + bool allowScalar); + +extern TargetEntry *makeTargetEntry(Expr *expr, + AttrNumber resno, + char *resname, + bool resjunk); + +extern TargetEntry *flatCopyTargetEntry(TargetEntry *src_tle); + +extern FromExpr *makeFromExpr(List *fromlist, Node *quals); + +extern Const *makeConst(Oid consttype, + int32 consttypmod, + Oid constcollid, + int constlen, + Datum constvalue, + bool constisnull, + bool constbyval); + +extern Const *makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid); + +extern Node *makeBoolConst(bool value, bool isnull); + +extern Expr *makeBoolExpr(BoolExprType boolop, List *args, int location); + +extern Alias *makeAlias(const char *aliasname, List *colnames); + +extern RelabelType *makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, + Oid rcollid, CoercionForm rformat); + +extern RangeVar *makeRangeVar(char *schemaname, char *relname, int location); + +extern TypeName *makeTypeName(char *typnam); +extern TypeName *makeTypeNameFromNameList(List *names); +extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod); + +extern ColumnDef *makeColumnDef(const char *colname, + Oid typeOid, int32 typmod, Oid collOid); + +extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args, + Oid funccollid, Oid inputcollid, CoercionForm fformat); + +extern FuncCall *makeFuncCall(List *name, List *args, + CoercionForm funcformat, int location); + +extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset, + Expr *leftop, Expr *rightop, + Oid opcollid, Oid inputcollid); + +extern Expr *make_andclause(List *andclauses); +extern Expr *make_orclause(List *orclauses); +extern Expr *make_notclause(Expr *notclause); + +extern Node *make_and_qual(Node *qual1, Node *qual2); +extern Expr *make_ands_explicit(List *andclauses); +extern List *make_ands_implicit(Expr *clause); + +extern IndexInfo *makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, + List *expressions, List *predicates, + bool unique, bool nulls_not_distinct, bool isready, bool concurrent); + +extern DefElem *makeDefElem(char *name, Node *arg, int location); +extern DefElem *makeDefElemExtended(char *nameSpace, char *name, Node *arg, + DefElemAction defaction, int location); + +extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int location); + +extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols); + +#endif /* MAKEFUNC_H */ diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h new file mode 100644 index 0000000..bbbe151 --- /dev/null +++ b/src/include/nodes/memnodes.h @@ -0,0 +1,110 @@ +/*------------------------------------------------------------------------- + * + * memnodes.h + * POSTGRES memory context node definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/memnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef MEMNODES_H +#define MEMNODES_H + +#include "nodes/nodes.h" + +/* + * MemoryContextCounters + * Summarization state for MemoryContextStats collection. + * + * The set of counters in this struct is biased towards AllocSet; if we ever + * add any context types that are based on fundamentally different approaches, + * we might need more or different counters here. A possible API spec then + * would be to print only nonzero counters, but for now we just summarize in + * the format historically used by AllocSet. + */ +typedef struct MemoryContextCounters +{ + Size nblocks; /* Total number of malloc blocks */ + Size freechunks; /* Total number of free chunks */ + Size totalspace; /* Total bytes requested from malloc */ + Size freespace; /* The unused portion of totalspace */ +} MemoryContextCounters; + +/* + * MemoryContext + * A logical context in which memory allocations occur. + * + * MemoryContext itself is an abstract type that can have multiple + * implementations. + * The function pointers in MemoryContextMethods define one specific + * implementation of MemoryContext --- they are a virtual function table + * in C++ terms. + * + * Node types that are actual implementations of memory contexts must + * begin with the same fields as MemoryContextData. + * + * Note: for largely historical reasons, typedef MemoryContext is a pointer + * to the context struct rather than the struct type itself. + */ + +typedef void (*MemoryStatsPrintFunc) (MemoryContext context, void *passthru, + const char *stats_string, + bool print_to_stderr); + +typedef struct MemoryContextMethods +{ + void *(*alloc) (MemoryContext context, Size size); + /* call this free_p in case someone #define's free() */ + void (*free_p) (MemoryContext context, void *pointer); + void *(*realloc) (MemoryContext context, void *pointer, Size size); + void (*reset) (MemoryContext context); + void (*delete_context) (MemoryContext context); + Size (*get_chunk_space) (MemoryContext context, void *pointer); + bool (*is_empty) (MemoryContext context); + void (*stats) (MemoryContext context, + MemoryStatsPrintFunc printfunc, void *passthru, + MemoryContextCounters *totals, + bool print_to_stderr); +#ifdef MEMORY_CONTEXT_CHECKING + void (*check) (MemoryContext context); +#endif +} MemoryContextMethods; + + +typedef struct MemoryContextData +{ + NodeTag type; /* identifies exact kind of context */ + /* these two fields are placed here to minimize alignment wastage: */ + bool isReset; /* T = no space alloced since last reset */ + bool allowInCritSection; /* allow palloc in critical section */ + Size mem_allocated; /* track memory allocated for this context */ + const MemoryContextMethods *methods; /* virtual function table */ + MemoryContext parent; /* NULL if no parent (toplevel context) */ + MemoryContext firstchild; /* head of linked list of children */ + MemoryContext prevchild; /* previous child of same parent */ + MemoryContext nextchild; /* next child of same parent */ + const char *name; /* context name (just for debugging) */ + const char *ident; /* context ID if any (just for debugging) */ + MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */ +} MemoryContextData; + +/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */ + + +/* + * MemoryContextIsValid + * True iff memory context is valid. + * + * Add new context types to the set accepted by this macro. + */ +#define MemoryContextIsValid(context) \ + ((context) != NULL && \ + (IsA((context), AllocSetContext) || \ + IsA((context), SlabContext) || \ + IsA((context), GenerationContext))) + +#endif /* MEMNODES_H */ diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h new file mode 100644 index 0000000..93c60bd --- /dev/null +++ b/src/include/nodes/nodeFuncs.h @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------- + * + * nodeFuncs.h + * Various general-purpose manipulations of Node trees + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/nodeFuncs.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODEFUNCS_H +#define NODEFUNCS_H + +#include "nodes/parsenodes.h" + + +/* flags bits for query_tree_walker and query_tree_mutator */ +#define QTW_IGNORE_RT_SUBQUERIES 0x01 /* subqueries in rtable */ +#define QTW_IGNORE_CTE_SUBQUERIES 0x02 /* subqueries in cteList */ +#define QTW_IGNORE_RC_SUBQUERIES 0x03 /* both of above */ +#define QTW_IGNORE_JOINALIASES 0x04 /* JOIN alias var lists */ +#define QTW_IGNORE_RANGE_TABLE 0x08 /* skip rangetable entirely */ +#define QTW_EXAMINE_RTES_BEFORE 0x10 /* examine RTE nodes before their + * contents */ +#define QTW_EXAMINE_RTES_AFTER 0x20 /* examine RTE nodes after their + * contents */ +#define QTW_DONT_COPY_QUERY 0x40 /* do not copy top Query */ +#define QTW_EXAMINE_SORTGROUP 0x80 /* include SortGroupNode lists */ + +/* callback function for check_functions_in_node */ +typedef bool (*check_function_callback) (Oid func_id, void *context); + + +extern Oid exprType(const Node *expr); +extern int32 exprTypmod(const Node *expr); +extern bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod); +extern Node *applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid, + CoercionForm rformat, int rlocation, + bool overwrite_ok); +extern Node *relabel_to_typmod(Node *expr, int32 typmod); +extern Node *strip_implicit_coercions(Node *node); +extern bool expression_returns_set(Node *clause); + +extern Oid exprCollation(const Node *expr); +extern Oid exprInputCollation(const Node *expr); +extern void exprSetCollation(Node *expr, Oid collation); +extern void exprSetInputCollation(Node *expr, Oid inputcollation); + +extern int exprLocation(const Node *expr); + +extern void fix_opfuncids(Node *node); +extern void set_opfuncid(OpExpr *opexpr); +extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr); + +/* Is clause a FuncExpr clause? */ +static inline bool +is_funcclause(const void *clause) +{ + return clause != NULL && IsA(clause, FuncExpr); +} + +/* Is clause an OpExpr clause? */ +static inline bool +is_opclause(const void *clause) +{ + return clause != NULL && IsA(clause, OpExpr); +} + +/* Extract left arg of a binary opclause, or only arg of a unary opclause */ +static inline Node * +get_leftop(const void *clause) +{ + const OpExpr *expr = (const OpExpr *) clause; + + if (expr->args != NIL) + return (Node *) linitial(expr->args); + else + return NULL; +} + +/* Extract right arg of a binary opclause (NULL if it's a unary opclause) */ +static inline Node * +get_rightop(const void *clause) +{ + const OpExpr *expr = (const OpExpr *) clause; + + if (list_length(expr->args) >= 2) + return (Node *) lsecond(expr->args); + else + return NULL; +} + +/* Is clause an AND clause? */ +static inline bool +is_andclause(const void *clause) +{ + return (clause != NULL && + IsA(clause, BoolExpr) && + ((const BoolExpr *) clause)->boolop == AND_EXPR); +} + +/* Is clause an OR clause? */ +static inline bool +is_orclause(const void *clause) +{ + return (clause != NULL && + IsA(clause, BoolExpr) && + ((const BoolExpr *) clause)->boolop == OR_EXPR); +} + +/* Is clause a NOT clause? */ +static inline bool +is_notclause(const void *clause) +{ + return (clause != NULL && + IsA(clause, BoolExpr) && + ((const BoolExpr *) clause)->boolop == NOT_EXPR); +} + +/* Extract argument from a clause known to be a NOT clause */ +static inline Expr * +get_notclausearg(const void *notclause) +{ + return (Expr *) linitial(((const BoolExpr *) notclause)->args); +} + +extern bool check_functions_in_node(Node *node, check_function_callback checker, + void *context); + +extern bool expression_tree_walker(Node *node, bool (*walker) (), + void *context); +extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (), + void *context); + +extern bool query_tree_walker(Query *query, bool (*walker) (), + void *context, int flags); +extern Query *query_tree_mutator(Query *query, Node *(*mutator) (), + void *context, int flags); + +extern bool range_table_walker(List *rtable, bool (*walker) (), + void *context, int flags); +extern List *range_table_mutator(List *rtable, Node *(*mutator) (), + void *context, int flags); + +extern bool range_table_entry_walker(RangeTblEntry *rte, bool (*walker) (), + void *context, int flags); + +extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (), + void *context, int flags); +extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (), + void *context, int flags); + +extern bool raw_expression_tree_walker(Node *node, bool (*walker) (), + void *context); + +struct PlanState; +extern bool planstate_tree_walker(struct PlanState *planstate, bool (*walker) (), + void *context); + +#endif /* NODEFUNCS_H */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h new file mode 100644 index 0000000..04d00f3 --- /dev/null +++ b/src/include/nodes/nodes.h @@ -0,0 +1,861 @@ +/*------------------------------------------------------------------------- + * + * nodes.h + * Definitions for tagged nodes. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/nodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef NODES_H +#define NODES_H + +/* + * The first field of every node is NodeTag. Each node created (with makeNode) + * will have one of the following tags as the value of its first field. + * + * Note that inserting or deleting node types changes the numbers of other + * node types later in the list. This is no problem during development, since + * the node numbers are never stored on disk. But don't do it in a released + * branch, because that would represent an ABI break for extensions. + */ +typedef enum NodeTag +{ + T_Invalid = 0, + + /* + * TAGS FOR EXECUTOR NODES (execnodes.h) + */ + T_IndexInfo, + T_ExprContext, + T_ProjectionInfo, + T_JunkFilter, + T_OnConflictSetState, + T_MergeActionState, + T_ResultRelInfo, + T_EState, + T_TupleTableSlot, + + /* + * TAGS FOR PLAN NODES (plannodes.h) + */ + T_Plan, + T_Result, + T_ProjectSet, + T_ModifyTable, + T_Append, + T_MergeAppend, + T_RecursiveUnion, + T_BitmapAnd, + T_BitmapOr, + T_Scan, + T_SeqScan, + T_SampleScan, + T_IndexScan, + T_IndexOnlyScan, + T_BitmapIndexScan, + T_BitmapHeapScan, + T_TidScan, + T_TidRangeScan, + T_SubqueryScan, + T_FunctionScan, + T_ValuesScan, + T_TableFuncScan, + T_CteScan, + T_NamedTuplestoreScan, + T_WorkTableScan, + T_ForeignScan, + T_CustomScan, + T_Join, + T_NestLoop, + T_MergeJoin, + T_HashJoin, + T_Material, + T_Memoize, + T_Sort, + T_IncrementalSort, + T_Group, + T_Agg, + T_WindowAgg, + T_Unique, + T_Gather, + T_GatherMerge, + T_Hash, + T_SetOp, + T_LockRows, + T_Limit, + /* these aren't subclasses of Plan: */ + T_NestLoopParam, + T_PlanRowMark, + T_PartitionPruneInfo, + T_PartitionedRelPruneInfo, + T_PartitionPruneStepOp, + T_PartitionPruneStepCombine, + T_PlanInvalItem, + + /* + * TAGS FOR PLAN STATE NODES (execnodes.h) + * + * These should correspond one-to-one with Plan node types. + */ + T_PlanState, + T_ResultState, + T_ProjectSetState, + T_ModifyTableState, + T_AppendState, + T_MergeAppendState, + T_RecursiveUnionState, + T_BitmapAndState, + T_BitmapOrState, + T_ScanState, + T_SeqScanState, + T_SampleScanState, + T_IndexScanState, + T_IndexOnlyScanState, + T_BitmapIndexScanState, + T_BitmapHeapScanState, + T_TidScanState, + T_TidRangeScanState, + T_SubqueryScanState, + T_FunctionScanState, + T_TableFuncScanState, + T_ValuesScanState, + T_CteScanState, + T_NamedTuplestoreScanState, + T_WorkTableScanState, + T_ForeignScanState, + T_CustomScanState, + T_JoinState, + T_NestLoopState, + T_MergeJoinState, + T_HashJoinState, + T_MaterialState, + T_MemoizeState, + T_SortState, + T_IncrementalSortState, + T_GroupState, + T_AggState, + T_WindowAggState, + T_UniqueState, + T_GatherState, + T_GatherMergeState, + T_HashState, + T_SetOpState, + T_LockRowsState, + T_LimitState, + + /* + * TAGS FOR PRIMITIVE NODES (primnodes.h) + */ + T_Alias, + T_RangeVar, + T_TableFunc, + T_Var, + T_Const, + T_Param, + T_Aggref, + T_GroupingFunc, + T_WindowFunc, + T_SubscriptingRef, + T_FuncExpr, + T_NamedArgExpr, + T_OpExpr, + T_DistinctExpr, + T_NullIfExpr, + T_ScalarArrayOpExpr, + T_BoolExpr, + T_SubLink, + T_SubPlan, + T_AlternativeSubPlan, + T_FieldSelect, + T_FieldStore, + T_RelabelType, + T_CoerceViaIO, + T_ArrayCoerceExpr, + T_ConvertRowtypeExpr, + T_CollateExpr, + T_CaseExpr, + T_CaseWhen, + T_CaseTestExpr, + T_ArrayExpr, + T_RowExpr, + T_RowCompareExpr, + T_CoalesceExpr, + T_MinMaxExpr, + T_SQLValueFunction, + T_XmlExpr, + T_NullTest, + T_BooleanTest, + T_CoerceToDomain, + T_CoerceToDomainValue, + T_SetToDefault, + T_CurrentOfExpr, + T_NextValueExpr, + T_InferenceElem, + T_TargetEntry, + T_RangeTblRef, + T_JoinExpr, + T_FromExpr, + T_OnConflictExpr, + T_IntoClause, + + /* + * TAGS FOR EXPRESSION STATE NODES (execnodes.h) + * + * ExprState represents the evaluation state for a whole expression tree. + * Most Expr-based plan nodes do not have a corresponding expression state + * node, they're fully handled within execExpr* - but sometimes the state + * needs to be shared with other parts of the executor, as for example + * with SubPlanState, which nodeSubplan.c has to modify. + */ + T_ExprState, + T_WindowFuncExprState, + T_SetExprState, + T_SubPlanState, + T_DomainConstraintState, + + /* + * TAGS FOR PLANNER NODES (pathnodes.h) + */ + T_PlannerInfo, + T_PlannerGlobal, + T_RelOptInfo, + T_IndexOptInfo, + T_ForeignKeyOptInfo, + T_ParamPathInfo, + T_Path, + T_IndexPath, + T_BitmapHeapPath, + T_BitmapAndPath, + T_BitmapOrPath, + T_TidPath, + T_TidRangePath, + T_SubqueryScanPath, + T_ForeignPath, + T_CustomPath, + T_NestPath, + T_MergePath, + T_HashPath, + T_AppendPath, + T_MergeAppendPath, + T_GroupResultPath, + T_MaterialPath, + T_MemoizePath, + T_UniquePath, + T_GatherPath, + T_GatherMergePath, + T_ProjectionPath, + T_ProjectSetPath, + T_SortPath, + T_IncrementalSortPath, + T_GroupPath, + T_UpperUniquePath, + T_AggPath, + T_GroupingSetsPath, + T_MinMaxAggPath, + T_WindowAggPath, + T_SetOpPath, + T_RecursiveUnionPath, + T_LockRowsPath, + T_ModifyTablePath, + T_LimitPath, + /* these aren't subclasses of Path: */ + T_EquivalenceClass, + T_EquivalenceMember, + T_PathKey, + T_PathKeyInfo, + T_PathTarget, + T_RestrictInfo, + T_IndexClause, + T_PlaceHolderVar, + T_SpecialJoinInfo, + T_AppendRelInfo, + T_RowIdentityVarInfo, + T_PlaceHolderInfo, + T_MinMaxAggInfo, + T_PlannerParamItem, + T_RollupData, + T_GroupingSetData, + T_StatisticExtInfo, + T_MergeAction, + + /* + * TAGS FOR MEMORY NODES (memnodes.h) + */ + T_AllocSetContext, + T_SlabContext, + T_GenerationContext, + + /* + * TAGS FOR VALUE NODES (value.h) + */ + T_Integer, + T_Float, + T_Boolean, + T_String, + T_BitString, + + /* + * TAGS FOR LIST NODES (pg_list.h) + */ + T_List, + T_IntList, + T_OidList, + + /* + * TAGS FOR EXTENSIBLE NODES (extensible.h) + */ + T_ExtensibleNode, + + /* + * TAGS FOR STATEMENT NODES (mostly in parsenodes.h) + */ + T_RawStmt, + T_Query, + T_PlannedStmt, + T_InsertStmt, + T_DeleteStmt, + T_UpdateStmt, + T_MergeStmt, + T_SelectStmt, + T_ReturnStmt, + T_PLAssignStmt, + T_AlterTableStmt, + T_AlterTableCmd, + T_AlterDomainStmt, + T_SetOperationStmt, + T_GrantStmt, + T_GrantRoleStmt, + T_AlterDefaultPrivilegesStmt, + T_ClosePortalStmt, + T_ClusterStmt, + T_CopyStmt, + T_CreateStmt, + T_DefineStmt, + T_DropStmt, + T_TruncateStmt, + T_CommentStmt, + T_FetchStmt, + T_IndexStmt, + T_CreateFunctionStmt, + T_AlterFunctionStmt, + T_DoStmt, + T_RenameStmt, + T_RuleStmt, + T_NotifyStmt, + T_ListenStmt, + T_UnlistenStmt, + T_TransactionStmt, + T_ViewStmt, + T_LoadStmt, + T_CreateDomainStmt, + T_CreatedbStmt, + T_DropdbStmt, + T_VacuumStmt, + T_ExplainStmt, + T_CreateTableAsStmt, + T_CreateSeqStmt, + T_AlterSeqStmt, + T_VariableSetStmt, + T_VariableShowStmt, + T_DiscardStmt, + T_CreateTrigStmt, + T_CreatePLangStmt, + T_CreateRoleStmt, + T_AlterRoleStmt, + T_DropRoleStmt, + T_LockStmt, + T_ConstraintsSetStmt, + T_ReindexStmt, + T_CheckPointStmt, + T_CreateSchemaStmt, + T_AlterDatabaseStmt, + T_AlterDatabaseRefreshCollStmt, + T_AlterDatabaseSetStmt, + T_AlterRoleSetStmt, + T_CreateConversionStmt, + T_CreateCastStmt, + T_CreateOpClassStmt, + T_CreateOpFamilyStmt, + T_AlterOpFamilyStmt, + T_PrepareStmt, + T_ExecuteStmt, + T_DeallocateStmt, + T_DeclareCursorStmt, + T_CreateTableSpaceStmt, + T_DropTableSpaceStmt, + T_AlterObjectDependsStmt, + T_AlterObjectSchemaStmt, + T_AlterOwnerStmt, + T_AlterOperatorStmt, + T_AlterTypeStmt, + T_DropOwnedStmt, + T_ReassignOwnedStmt, + T_CompositeTypeStmt, + T_CreateEnumStmt, + T_CreateRangeStmt, + T_AlterEnumStmt, + T_AlterTSDictionaryStmt, + T_AlterTSConfigurationStmt, + T_CreateFdwStmt, + T_AlterFdwStmt, + T_CreateForeignServerStmt, + T_AlterForeignServerStmt, + T_CreateUserMappingStmt, + T_AlterUserMappingStmt, + T_DropUserMappingStmt, + T_AlterTableSpaceOptionsStmt, + T_AlterTableMoveAllStmt, + T_SecLabelStmt, + T_CreateForeignTableStmt, + T_ImportForeignSchemaStmt, + T_CreateExtensionStmt, + T_AlterExtensionStmt, + T_AlterExtensionContentsStmt, + T_CreateEventTrigStmt, + T_AlterEventTrigStmt, + T_RefreshMatViewStmt, + T_ReplicaIdentityStmt, + T_AlterSystemStmt, + T_CreatePolicyStmt, + T_AlterPolicyStmt, + T_CreateTransformStmt, + T_CreateAmStmt, + T_CreatePublicationStmt, + T_AlterPublicationStmt, + T_CreateSubscriptionStmt, + T_AlterSubscriptionStmt, + T_DropSubscriptionStmt, + T_CreateStatsStmt, + T_AlterCollationStmt, + T_CallStmt, + T_AlterStatsStmt, + + /* + * TAGS FOR PARSE TREE NODES (parsenodes.h) + */ + T_A_Expr, + T_ColumnRef, + T_ParamRef, + T_A_Const, + T_FuncCall, + T_A_Star, + T_A_Indices, + T_A_Indirection, + T_A_ArrayExpr, + T_ResTarget, + T_MultiAssignRef, + T_TypeCast, + T_CollateClause, + T_SortBy, + T_WindowDef, + T_RangeSubselect, + T_RangeFunction, + T_RangeTableSample, + T_RangeTableFunc, + T_RangeTableFuncCol, + T_TypeName, + T_ColumnDef, + T_IndexElem, + T_StatsElem, + T_Constraint, + T_DefElem, + T_RangeTblEntry, + T_RangeTblFunction, + T_TableSampleClause, + T_WithCheckOption, + T_SortGroupClause, + T_GroupingSet, + T_WindowClause, + T_ObjectWithArgs, + T_AccessPriv, + T_CreateOpClassItem, + T_TableLikeClause, + T_FunctionParameter, + T_LockingClause, + T_RowMarkClause, + T_XmlSerialize, + T_WithClause, + T_InferClause, + T_OnConflictClause, + T_CTESearchClause, + T_CTECycleClause, + T_CommonTableExpr, + T_MergeWhenClause, + T_RoleSpec, + T_TriggerTransition, + T_PartitionElem, + T_PartitionSpec, + T_PartitionBoundSpec, + T_PartitionRangeDatum, + T_PartitionCmd, + T_VacuumRelation, + T_PublicationObjSpec, + T_PublicationTable, + + /* + * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) + */ + T_IdentifySystemCmd, + T_BaseBackupCmd, + T_CreateReplicationSlotCmd, + T_DropReplicationSlotCmd, + T_ReadReplicationSlotCmd, + T_StartReplicationCmd, + T_TimeLineHistoryCmd, + + /* + * TAGS FOR RANDOM OTHER STUFF + * + * These are objects that aren't part of parse/plan/execute node tree + * structures, but we give them NodeTags anyway for identification + * purposes (usually because they are involved in APIs where we want to + * pass multiple object types through the same pointer). + */ + T_TriggerData, /* in commands/trigger.h */ + T_EventTriggerData, /* in commands/event_trigger.h */ + T_ReturnSetInfo, /* in nodes/execnodes.h */ + T_WindowObjectData, /* private in nodeWindowAgg.c */ + T_TIDBitmap, /* in nodes/tidbitmap.h */ + T_InlineCodeBlock, /* in nodes/parsenodes.h */ + T_FdwRoutine, /* in foreign/fdwapi.h */ + T_IndexAmRoutine, /* in access/amapi.h */ + T_TableAmRoutine, /* in access/tableam.h */ + T_TsmRoutine, /* in access/tsmapi.h */ + T_ForeignKeyCacheInfo, /* in utils/rel.h */ + T_CallContext, /* in nodes/parsenodes.h */ + T_SupportRequestSimplify, /* in nodes/supportnodes.h */ + T_SupportRequestSelectivity, /* in nodes/supportnodes.h */ + T_SupportRequestCost, /* in nodes/supportnodes.h */ + T_SupportRequestRows, /* in nodes/supportnodes.h */ + T_SupportRequestIndexCondition, /* in nodes/supportnodes.h */ + T_SupportRequestWFuncMonotonic /* in nodes/supportnodes.h */ +} NodeTag; + +/* + * The first field of a node of any type is guaranteed to be the NodeTag. + * Hence the type of any node can be gotten by casting it to Node. Declaring + * a variable to be of Node * (instead of void *) can also facilitate + * debugging. + */ +typedef struct Node +{ + NodeTag type; +} Node; + +#define nodeTag(nodeptr) (((const Node*)(nodeptr))->type) + +/* + * newNode - + * create a new node of the specified size and tag the node with the + * specified tag. + * + * !WARNING!: Avoid using newNode directly. You should be using the + * macro makeNode. eg. to create a Query node, use makeNode(Query) + * + * Note: the size argument should always be a compile-time constant, so the + * apparent risk of multiple evaluation doesn't matter in practice. + */ +#ifdef __GNUC__ + +/* With GCC, we can use a compound statement within an expression */ +#define newNode(size, tag) \ +({ Node *_result; \ + AssertMacro((size) >= sizeof(Node)); /* need the tag, at least */ \ + _result = (Node *) palloc0fast(size); \ + _result->type = (tag); \ + _result; \ +}) +#else + +/* + * There is no way to dereference the palloc'ed pointer to assign the + * tag, and also return the pointer itself, so we need a holder variable. + * Fortunately, this macro isn't recursive so we just define + * a global variable for this purpose. + */ +extern PGDLLIMPORT Node *newNodeMacroHolder; + +#define newNode(size, tag) \ +( \ + AssertMacro((size) >= sizeof(Node)), /* need the tag, at least */ \ + newNodeMacroHolder = (Node *) palloc0fast(size), \ + newNodeMacroHolder->type = (tag), \ + newNodeMacroHolder \ +) +#endif /* __GNUC__ */ + + +#define makeNode(_type_) ((_type_ *) newNode(sizeof(_type_),T_##_type_)) +#define NodeSetTag(nodeptr,t) (((Node*)(nodeptr))->type = (t)) + +#define IsA(nodeptr,_type_) (nodeTag(nodeptr) == T_##_type_) + +/* + * castNode(type, ptr) casts ptr to "type *", and if assertions are enabled, + * verifies that the node has the appropriate type (using its nodeTag()). + * + * Use an inline function when assertions are enabled, to avoid multiple + * evaluations of the ptr argument (which could e.g. be a function call). + */ +#ifdef USE_ASSERT_CHECKING +static inline Node * +castNodeImpl(NodeTag type, void *ptr) +{ + Assert(ptr == NULL || nodeTag(ptr) == type); + return (Node *) ptr; +} +#define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(T_##_type_, nodeptr)) +#else +#define castNode(_type_, nodeptr) ((_type_ *) (nodeptr)) +#endif /* USE_ASSERT_CHECKING */ + + +/* ---------------------------------------------------------------- + * extern declarations follow + * ---------------------------------------------------------------- + */ + +/* + * nodes/{outfuncs.c,print.c} + */ +struct Bitmapset; /* not to include bitmapset.h here */ +struct StringInfoData; /* not to include stringinfo.h here */ + +extern void outNode(struct StringInfoData *str, const void *obj); +extern void outToken(struct StringInfoData *str, const char *s); +extern void outBitmapset(struct StringInfoData *str, + const struct Bitmapset *bms); +extern void outDatum(struct StringInfoData *str, uintptr_t value, + int typlen, bool typbyval); +extern char *nodeToString(const void *obj); +extern char *bmsToString(const struct Bitmapset *bms); + +/* + * nodes/{readfuncs.c,read.c} + */ +extern void *stringToNode(const char *str); +#ifdef WRITE_READ_PARSE_PLAN_TREES +extern void *stringToNodeWithLocations(const char *str); +#endif +extern struct Bitmapset *readBitmapset(void); +extern uintptr_t readDatum(bool typbyval); +extern bool *readBoolCols(int numCols); +extern int *readIntCols(int numCols); +extern Oid *readOidCols(int numCols); +extern int16 *readAttrNumberCols(int numCols); + +/* + * nodes/copyfuncs.c + */ +extern void *copyObjectImpl(const void *obj); + +/* cast result back to argument type, if supported by compiler */ +#ifdef HAVE_TYPEOF +#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj)) +#else +#define copyObject(obj) copyObjectImpl(obj) +#endif + +/* + * nodes/equalfuncs.c + */ +extern bool equal(const void *a, const void *b); + + +/* + * Typedefs for identifying qualifier selectivities and plan costs as such. + * These are just plain "double"s, but declaring a variable as Selectivity + * or Cost makes the intent more obvious. + * + * These could have gone into plannodes.h or some such, but many files + * depend on them... + */ +typedef double Selectivity; /* fraction of tuples a qualifier will pass */ +typedef double Cost; /* execution cost (in page-access units) */ +typedef double Cardinality; /* (estimated) number of rows or other integer + * count */ + + +/* + * CmdType - + * enums for type of operation represented by a Query or PlannedStmt + * + * This is needed in both parsenodes.h and plannodes.h, so put it here... + */ +typedef enum CmdType +{ + CMD_UNKNOWN, + CMD_SELECT, /* select stmt */ + CMD_UPDATE, /* update stmt */ + CMD_INSERT, /* insert stmt */ + CMD_DELETE, /* delete stmt */ + CMD_MERGE, /* merge stmt */ + CMD_UTILITY, /* cmds like create, destroy, copy, vacuum, + * etc. */ + CMD_NOTHING /* dummy command for instead nothing rules + * with qual */ +} CmdType; + + +/* + * JoinType - + * enums for types of relation joins + * + * JoinType determines the exact semantics of joining two relations using + * a matching qualification. For example, it tells what to do with a tuple + * that has no match in the other relation. + * + * This is needed in both parsenodes.h and plannodes.h, so put it here... + */ +typedef enum JoinType +{ + /* + * The canonical kinds of joins according to the SQL JOIN syntax. Only + * these codes can appear in parser output (e.g., JoinExpr nodes). + */ + JOIN_INNER, /* matching tuple pairs only */ + JOIN_LEFT, /* pairs + unmatched LHS tuples */ + JOIN_FULL, /* pairs + unmatched LHS + unmatched RHS */ + JOIN_RIGHT, /* pairs + unmatched RHS tuples */ + + /* + * Semijoins and anti-semijoins (as defined in relational theory) do not + * appear in the SQL JOIN syntax, but there are standard idioms for + * representing them (e.g., using EXISTS). The planner recognizes these + * cases and converts them to joins. So the planner and executor must + * support these codes. NOTE: in JOIN_SEMI output, it is unspecified + * which matching RHS row is joined to. In JOIN_ANTI output, the row is + * guaranteed to be null-extended. + */ + JOIN_SEMI, /* 1 copy of each LHS row that has match(es) */ + JOIN_ANTI, /* 1 copy of each LHS row that has no match */ + + /* + * These codes are used internally in the planner, but are not supported + * by the executor (nor, indeed, by most of the planner). + */ + JOIN_UNIQUE_OUTER, /* LHS path must be made unique */ + JOIN_UNIQUE_INNER /* RHS path must be made unique */ + + /* + * We might need additional join types someday. + */ +} JoinType; + +/* + * OUTER joins are those for which pushed-down quals must behave differently + * from the join's own quals. This is in fact everything except INNER and + * SEMI joins. However, this macro must also exclude the JOIN_UNIQUE symbols + * since those are temporary proxies for what will eventually be an INNER + * join. + * + * Note: semijoins are a hybrid case, but we choose to treat them as not + * being outer joins. This is okay principally because the SQL syntax makes + * it impossible to have a pushed-down qual that refers to the inner relation + * of a semijoin; so there is no strong need to distinguish join quals from + * pushed-down quals. This is convenient because for almost all purposes, + * quals attached to a semijoin can be treated the same as innerjoin quals. + */ +#define IS_OUTER_JOIN(jointype) \ + (((1 << (jointype)) & \ + ((1 << JOIN_LEFT) | \ + (1 << JOIN_FULL) | \ + (1 << JOIN_RIGHT) | \ + (1 << JOIN_ANTI))) != 0) + +/* + * AggStrategy - + * overall execution strategies for Agg plan nodes + * + * This is needed in both pathnodes.h and plannodes.h, so put it here... + */ +typedef enum AggStrategy +{ + AGG_PLAIN, /* simple agg across all input rows */ + AGG_SORTED, /* grouped agg, input must be sorted */ + AGG_HASHED, /* grouped agg, use internal hashtable */ + AGG_MIXED /* grouped agg, hash and sort both used */ +} AggStrategy; + +/* + * AggSplit - + * splitting (partial aggregation) modes for Agg plan nodes + * + * This is needed in both pathnodes.h and plannodes.h, so put it here... + */ + +/* Primitive options supported by nodeAgg.c: */ +#define AGGSPLITOP_COMBINE 0x01 /* substitute combinefn for transfn */ +#define AGGSPLITOP_SKIPFINAL 0x02 /* skip finalfn, return state as-is */ +#define AGGSPLITOP_SERIALIZE 0x04 /* apply serialfn to output */ +#define AGGSPLITOP_DESERIALIZE 0x08 /* apply deserialfn to input */ + +/* Supported operating modes (i.e., useful combinations of these options): */ +typedef enum AggSplit +{ + /* Basic, non-split aggregation: */ + AGGSPLIT_SIMPLE = 0, + /* Initial phase of partial aggregation, with serialization: */ + AGGSPLIT_INITIAL_SERIAL = AGGSPLITOP_SKIPFINAL | AGGSPLITOP_SERIALIZE, + /* Final phase of partial aggregation, with deserialization: */ + AGGSPLIT_FINAL_DESERIAL = AGGSPLITOP_COMBINE | AGGSPLITOP_DESERIALIZE +} AggSplit; + +/* Test whether an AggSplit value selects each primitive option: */ +#define DO_AGGSPLIT_COMBINE(as) (((as) & AGGSPLITOP_COMBINE) != 0) +#define DO_AGGSPLIT_SKIPFINAL(as) (((as) & AGGSPLITOP_SKIPFINAL) != 0) +#define DO_AGGSPLIT_SERIALIZE(as) (((as) & AGGSPLITOP_SERIALIZE) != 0) +#define DO_AGGSPLIT_DESERIALIZE(as) (((as) & AGGSPLITOP_DESERIALIZE) != 0) + +/* + * SetOpCmd and SetOpStrategy - + * overall semantics and execution strategies for SetOp plan nodes + * + * This is needed in both pathnodes.h and plannodes.h, so put it here... + */ +typedef enum SetOpCmd +{ + SETOPCMD_INTERSECT, + SETOPCMD_INTERSECT_ALL, + SETOPCMD_EXCEPT, + SETOPCMD_EXCEPT_ALL +} SetOpCmd; + +typedef enum SetOpStrategy +{ + SETOP_SORTED, /* input must be sorted */ + SETOP_HASHED /* use internal hashtable */ +} SetOpStrategy; + +/* + * OnConflictAction - + * "ON CONFLICT" clause type of query + * + * This is needed in both parsenodes.h and plannodes.h, so put it here... + */ +typedef enum OnConflictAction +{ + ONCONFLICT_NONE, /* No "ON CONFLICT" clause */ + ONCONFLICT_NOTHING, /* ON CONFLICT ... DO NOTHING */ + ONCONFLICT_UPDATE /* ON CONFLICT ... DO UPDATE */ +} OnConflictAction; + +/* + * LimitOption - + * LIMIT option of query + * + * This is needed in both parsenodes.h and plannodes.h, so put it here... + */ +typedef enum LimitOption +{ + LIMIT_OPTION_COUNT, /* FETCH FIRST... ONLY */ + LIMIT_OPTION_WITH_TIES, /* FETCH FIRST... WITH TIES */ + LIMIT_OPTION_DEFAULT, /* No limit present */ +} LimitOption; + +#endif /* NODES_H */ diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h new file mode 100644 index 0000000..de2dd90 --- /dev/null +++ b/src/include/nodes/params.h @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------- + * + * params.h + * Support for finding the values associated with Param nodes. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/params.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARAMS_H +#define PARAMS_H + +/* Forward declarations, to avoid including other headers */ +struct Bitmapset; +struct ExprState; +struct Param; +struct ParseState; + + +/* + * ParamListInfo + * + * ParamListInfo structures are used to pass parameters into the executor + * for parameterized plans. We support two basic approaches to supplying + * parameter values, the "static" way and the "dynamic" way. + * + * In the static approach, per-parameter data is stored in an array of + * ParamExternData structs appended to the ParamListInfo struct. + * Each entry in the array defines the value to be substituted for a + * PARAM_EXTERN parameter. The "paramid" of a PARAM_EXTERN Param + * can range from 1 to numParams. + * + * Although parameter numbers are normally consecutive, we allow + * ptype == InvalidOid to signal an unused array entry. + * + * pflags is a flags field. Currently the only used bit is: + * PARAM_FLAG_CONST signals the planner that it may treat this parameter + * as a constant (i.e., generate a plan that works only for this value + * of the parameter). + * + * In the dynamic approach, all access to parameter values is done through + * hook functions found in the ParamListInfo struct. In this case, + * the ParamExternData array is typically unused and not allocated; + * but the legal range of paramid is still 1 to numParams. + * + * Although the data structure is really an array, not a list, we keep + * the old typedef name to avoid unnecessary code changes. + * + * There are 3 hook functions that can be associated with a ParamListInfo + * structure: + * + * If paramFetch isn't null, it is called to fetch the ParamExternData + * for a particular param ID, rather than accessing the relevant element + * of the ParamExternData array. This supports the case where the array + * isn't there at all, as well as cases where the data in the array + * might be obsolete or lazily evaluated. paramFetch must return the + * address of a ParamExternData struct describing the specified param ID; + * the convention above about ptype == InvalidOid signaling an invalid + * param ID still applies. The returned struct can either be placed in + * the "workspace" supplied by the caller, or it can be in storage + * controlled by the paramFetch hook if that's more convenient. + * (In either case, the struct is not expected to be long-lived.) + * If "speculative" is true, the paramFetch hook should not risk errors + * in trying to fetch the parameter value, and should report an invalid + * parameter instead. + * + * If paramCompile isn't null, then it controls what execExpr.c compiles + * for PARAM_EXTERN Param nodes --- typically, this hook would emit a + * EEOP_PARAM_CALLBACK step. This allows unnecessary work to be + * optimized away in compiled expressions. + * + * If parserSetup isn't null, then it is called to re-instantiate the + * original parsing hooks when a query needs to be re-parsed/planned. + * This is especially useful if the types of parameters might change + * from time to time, since it can replace the need to supply a fixed + * list of parameter types to the parser. + * + * Notice that the paramFetch and paramCompile hooks are actually passed + * the ParamListInfo struct's address; they can therefore access all + * three of the "arg" fields, and the distinction between paramFetchArg + * and paramCompileArg is rather arbitrary. + */ + +#define PARAM_FLAG_CONST 0x0001 /* parameter is constant */ + +typedef struct ParamExternData +{ + Datum value; /* parameter value */ + bool isnull; /* is it NULL? */ + uint16 pflags; /* flag bits, see above */ + Oid ptype; /* parameter's datatype, or 0 */ +} ParamExternData; + +typedef struct ParamListInfoData *ParamListInfo; + +typedef ParamExternData *(*ParamFetchHook) (ParamListInfo params, + int paramid, bool speculative, + ParamExternData *workspace); + +typedef void (*ParamCompileHook) (ParamListInfo params, struct Param *param, + struct ExprState *state, + Datum *resv, bool *resnull); + +typedef void (*ParserSetupHook) (struct ParseState *pstate, void *arg); + +typedef struct ParamListInfoData +{ + ParamFetchHook paramFetch; /* parameter fetch hook */ + void *paramFetchArg; + ParamCompileHook paramCompile; /* parameter compile hook */ + void *paramCompileArg; + ParserSetupHook parserSetup; /* parser setup hook */ + void *parserSetupArg; + char *paramValuesStr; /* params as a single string for errors */ + int numParams; /* nominal/maximum # of Params represented */ + + /* + * params[] may be of length zero if paramFetch is supplied; otherwise it + * must be of length numParams. + */ + ParamExternData params[FLEXIBLE_ARRAY_MEMBER]; +} ParamListInfoData; + + +/* ---------------- + * ParamExecData + * + * ParamExecData entries are used for executor internal parameters + * (that is, values being passed into or out of a sub-query). The + * paramid of a PARAM_EXEC Param is a (zero-based) index into an + * array of ParamExecData records, which is referenced through + * es_param_exec_vals or ecxt_param_exec_vals. + * + * If execPlan is not NULL, it points to a SubPlanState node that needs + * to be executed to produce the value. (This is done so that we can have + * lazy evaluation of InitPlans: they aren't executed until/unless a + * result value is needed.) Otherwise the value is assumed to be valid + * when needed. + * ---------------- + */ + +typedef struct ParamExecData +{ + void *execPlan; /* should be "SubPlanState *" */ + Datum value; + bool isnull; +} ParamExecData; + +/* type of argument for ParamsErrorCallback */ +typedef struct ParamsErrorCbData +{ + const char *portalName; + ParamListInfo params; +} ParamsErrorCbData; + +/* Functions found in src/backend/nodes/params.c */ +extern ParamListInfo makeParamList(int numParams); +extern ParamListInfo copyParamList(ParamListInfo from); +extern Size EstimateParamListSpace(ParamListInfo paramLI); +extern void SerializeParamList(ParamListInfo paramLI, char **start_address); +extern ParamListInfo RestoreParamList(char **start_address); +extern char *BuildParamLogString(ParamListInfo params, char **paramTextValues, + int valueLen); +extern void ParamsErrorCallback(void *arg); + +#endif /* PARAMS_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h new file mode 100644 index 0000000..6944362 --- /dev/null +++ b/src/include/nodes/parsenodes.h @@ -0,0 +1,3805 @@ +/*------------------------------------------------------------------------- + * + * parsenodes.h + * definitions for parse tree nodes + * + * Many of the node types used in parsetrees include a "location" field. + * This is a byte (not character) offset in the original source text, to be + * used for positioning an error cursor when there is an error related to + * the node. Access to the original source text is needed to make use of + * the location. At the topmost (statement) level, we also provide a + * statement length, likewise measured in bytes, for convenience in + * identifying statement boundaries in multi-statement source strings. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/parsenodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSENODES_H +#define PARSENODES_H + +#include "nodes/bitmapset.h" +#include "nodes/lockoptions.h" +#include "nodes/primnodes.h" +#include "nodes/value.h" +#include "partitioning/partdefs.h" + + +typedef enum OverridingKind +{ + OVERRIDING_NOT_SET = 0, + OVERRIDING_USER_VALUE, + OVERRIDING_SYSTEM_VALUE +} OverridingKind; + +/* Possible sources of a Query */ +typedef enum QuerySource +{ + QSRC_ORIGINAL, /* original parsetree (explicit query) */ + QSRC_PARSER, /* added by parse analysis (now unused) */ + QSRC_INSTEAD_RULE, /* added by unconditional INSTEAD rule */ + QSRC_QUAL_INSTEAD_RULE, /* added by conditional INSTEAD rule */ + QSRC_NON_INSTEAD_RULE /* added by non-INSTEAD rule */ +} QuerySource; + +/* Sort ordering options for ORDER BY and CREATE INDEX */ +typedef enum SortByDir +{ + SORTBY_DEFAULT, + SORTBY_ASC, + SORTBY_DESC, + SORTBY_USING /* not allowed in CREATE INDEX ... */ +} SortByDir; + +typedef enum SortByNulls +{ + SORTBY_NULLS_DEFAULT, + SORTBY_NULLS_FIRST, + SORTBY_NULLS_LAST +} SortByNulls; + +/* Options for [ ALL | DISTINCT ] */ +typedef enum SetQuantifier +{ + SET_QUANTIFIER_DEFAULT, + SET_QUANTIFIER_ALL, + SET_QUANTIFIER_DISTINCT +} SetQuantifier; + +/* + * Grantable rights are encoded so that we can OR them together in a bitmask. + * The present representation of AclItem limits us to 16 distinct rights, + * even though AclMode is defined as uint32. See utils/acl.h. + * + * Caution: changing these codes breaks stored ACLs, hence forces initdb. + */ +typedef uint32 AclMode; /* a bitmask of privilege bits */ + +#define ACL_INSERT (1<<0) /* for relations */ +#define ACL_SELECT (1<<1) +#define ACL_UPDATE (1<<2) +#define ACL_DELETE (1<<3) +#define ACL_TRUNCATE (1<<4) +#define ACL_REFERENCES (1<<5) +#define ACL_TRIGGER (1<<6) +#define ACL_EXECUTE (1<<7) /* for functions */ +#define ACL_USAGE (1<<8) /* for languages, namespaces, FDWs, and + * servers */ +#define ACL_CREATE (1<<9) /* for namespaces and databases */ +#define ACL_CREATE_TEMP (1<<10) /* for databases */ +#define ACL_CONNECT (1<<11) /* for databases */ +#define ACL_SET (1<<12) /* for configuration parameters */ +#define ACL_ALTER_SYSTEM (1<<13) /* for configuration parameters */ +#define N_ACL_RIGHTS 14 /* 1 plus the last 1<<x */ +#define ACL_NO_RIGHTS 0 +/* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */ +#define ACL_SELECT_FOR_UPDATE ACL_UPDATE + + +/***************************************************************************** + * Query Tree + *****************************************************************************/ + +/* + * Query - + * Parse analysis turns all statements into a Query tree + * for further processing by the rewriter and planner. + * + * Utility statements (i.e. non-optimizable statements) have the + * utilityStmt field set, and the rest of the Query is mostly dummy. + * + * Planning converts a Query tree into a Plan tree headed by a PlannedStmt + * node --- the Query structure is not used by the executor. + */ +typedef struct Query +{ + NodeTag type; + + CmdType commandType; /* select|insert|update|delete|merge|utility */ + + QuerySource querySource; /* where did I come from? */ + + uint64 queryId; /* query identifier (can be set by plugins) */ + + bool canSetTag; /* do I set the command result tag? */ + + Node *utilityStmt; /* non-null if commandType == CMD_UTILITY */ + + int resultRelation; /* rtable index of target relation for + * INSERT/UPDATE/DELETE/MERGE; 0 for SELECT */ + + bool hasAggs; /* has aggregates in tlist or havingQual */ + bool hasWindowFuncs; /* has window functions in tlist */ + bool hasTargetSRFs; /* has set-returning functions in tlist */ + bool hasSubLinks; /* has subquery SubLink */ + bool hasDistinctOn; /* distinctClause is from DISTINCT ON */ + bool hasRecursive; /* WITH RECURSIVE was specified */ + bool hasModifyingCTE; /* has INSERT/UPDATE/DELETE in WITH */ + bool hasForUpdate; /* FOR [KEY] UPDATE/SHARE was specified */ + bool hasRowSecurity; /* rewriter has applied some RLS policy */ + + bool isReturn; /* is a RETURN statement */ + + List *cteList; /* WITH list (of CommonTableExpr's) */ + + List *rtable; /* list of range table entries */ + FromExpr *jointree; /* table join tree (FROM and WHERE clauses); + * also USING clause for MERGE */ + + List *mergeActionList; /* list of actions for MERGE (only) */ + bool mergeUseOuterJoin; /* whether to use outer join */ + + List *targetList; /* target list (of TargetEntry) */ + + OverridingKind override; /* OVERRIDING clause */ + + OnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */ + + List *returningList; /* return-values list (of TargetEntry) */ + + List *groupClause; /* a list of SortGroupClause's */ + bool groupDistinct; /* is the group by clause distinct? */ + + List *groupingSets; /* a list of GroupingSet's if present */ + + Node *havingQual; /* qualifications applied to groups */ + + List *windowClause; /* a list of WindowClause's */ + + List *distinctClause; /* a list of SortGroupClause's */ + + List *sortClause; /* a list of SortGroupClause's */ + + Node *limitOffset; /* # of result tuples to skip (int8 expr) */ + Node *limitCount; /* # of result tuples to return (int8 expr) */ + LimitOption limitOption; /* limit type */ + + List *rowMarks; /* a list of RowMarkClause's */ + + Node *setOperations; /* set-operation tree if this is top level of + * a UNION/INTERSECT/EXCEPT query */ + + List *constraintDeps; /* a list of pg_constraint OIDs that the query + * depends on to be semantically valid */ + + List *withCheckOptions; /* a list of WithCheckOption's (added + * during rewrite) */ + + /* + * The following two fields identify the portion of the source text string + * containing this query. They are typically only populated in top-level + * Queries, not in sub-queries. When not set, they might both be zero, or + * both be -1 meaning "unknown". + */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ +} Query; + + +/**************************************************************************** + * Supporting data structures for Parse Trees + * + * Most of these node types appear in raw parsetrees output by the grammar, + * and get transformed to something else by the analyzer. A few of them + * are used as-is in transformed querytrees. + ****************************************************************************/ + +/* + * TypeName - specifies a type in definitions + * + * For TypeName structures generated internally, it is often easier to + * specify the type by OID than by name. If "names" is NIL then the + * actual type OID is given by typeOid, otherwise typeOid is unused. + * Similarly, if "typmods" is NIL then the actual typmod is expected to + * be prespecified in typemod, otherwise typemod is unused. + * + * If pct_type is true, then names is actually a field name and we look up + * the type of that field. Otherwise (the normal case), names is a type + * name possibly qualified with schema and database name. + */ +typedef struct TypeName +{ + NodeTag type; + List *names; /* qualified name (list of String nodes) */ + Oid typeOid; /* type identified by OID */ + bool setof; /* is a set? */ + bool pct_type; /* %TYPE specified? */ + List *typmods; /* type modifier expression(s) */ + int32 typemod; /* prespecified type modifier */ + List *arrayBounds; /* array bounds */ + int location; /* token location, or -1 if unknown */ +} TypeName; + +/* + * ColumnRef - specifies a reference to a column, or possibly a whole tuple + * + * The "fields" list must be nonempty. It can contain String nodes + * (representing names) and A_Star nodes (representing occurrence of a '*'). + * Currently, A_Star must appear only as the last list element --- the grammar + * is responsible for enforcing this! + * + * Note: any container subscripting or selection of fields from composite columns + * is represented by an A_Indirection node above the ColumnRef. However, + * for simplicity in the normal case, initial field selection from a table + * name is represented within ColumnRef and not by adding A_Indirection. + */ +typedef struct ColumnRef +{ + NodeTag type; + List *fields; /* field names (String nodes) or A_Star */ + int location; /* token location, or -1 if unknown */ +} ColumnRef; + +/* + * ParamRef - specifies a $n parameter reference + */ +typedef struct ParamRef +{ + NodeTag type; + int number; /* the number of the parameter */ + int location; /* token location, or -1 if unknown */ +} ParamRef; + +/* + * A_Expr - infix, prefix, and postfix expressions + */ +typedef enum A_Expr_Kind +{ + AEXPR_OP, /* normal operator */ + AEXPR_OP_ANY, /* scalar op ANY (array) */ + AEXPR_OP_ALL, /* scalar op ALL (array) */ + AEXPR_DISTINCT, /* IS DISTINCT FROM - name must be "=" */ + AEXPR_NOT_DISTINCT, /* IS NOT DISTINCT FROM - name must be "=" */ + AEXPR_NULLIF, /* NULLIF - name must be "=" */ + AEXPR_IN, /* [NOT] IN - name must be "=" or "<>" */ + AEXPR_LIKE, /* [NOT] LIKE - name must be "~~" or "!~~" */ + AEXPR_ILIKE, /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + AEXPR_SIMILAR, /* [NOT] SIMILAR - name must be "~" or "!~" */ + AEXPR_BETWEEN, /* name must be "BETWEEN" */ + AEXPR_NOT_BETWEEN, /* name must be "NOT BETWEEN" */ + AEXPR_BETWEEN_SYM, /* name must be "BETWEEN SYMMETRIC" */ + AEXPR_NOT_BETWEEN_SYM /* name must be "NOT BETWEEN SYMMETRIC" */ +} A_Expr_Kind; + +typedef struct A_Expr +{ + NodeTag type; + A_Expr_Kind kind; /* see above */ + List *name; /* possibly-qualified name of operator */ + Node *lexpr; /* left argument, or NULL if none */ + Node *rexpr; /* right argument, or NULL if none */ + int location; /* token location, or -1 if unknown */ +} A_Expr; + +/* + * A_Const - a literal constant + */ +typedef struct A_Const +{ + NodeTag type; + + /* + * Value nodes are inline for performance. You can treat 'val' as a node, + * as in IsA(&val, Integer). 'val' is not valid if isnull is true. + */ + union ValUnion + { + Node node; + Integer ival; + Float fval; + Boolean boolval; + String sval; + BitString bsval; + } val; + bool isnull; /* SQL NULL constant */ + int location; /* token location, or -1 if unknown */ +} A_Const; + +/* + * TypeCast - a CAST expression + */ +typedef struct TypeCast +{ + NodeTag type; + Node *arg; /* the expression being casted */ + TypeName *typeName; /* the target type */ + int location; /* token location, or -1 if unknown */ +} TypeCast; + +/* + * CollateClause - a COLLATE expression + */ +typedef struct CollateClause +{ + NodeTag type; + Node *arg; /* input expression */ + List *collname; /* possibly-qualified collation name */ + int location; /* token location, or -1 if unknown */ +} CollateClause; + +/* + * RoleSpec - a role name or one of a few special values. + */ +typedef enum RoleSpecType +{ + ROLESPEC_CSTRING, /* role name is stored as a C string */ + ROLESPEC_CURRENT_ROLE, /* role spec is CURRENT_ROLE */ + ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */ + ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */ + ROLESPEC_PUBLIC /* role name is "public" */ +} RoleSpecType; + +typedef struct RoleSpec +{ + NodeTag type; + RoleSpecType roletype; /* Type of this rolespec */ + char *rolename; /* filled only for ROLESPEC_CSTRING */ + int location; /* token location, or -1 if unknown */ +} RoleSpec; + +/* + * FuncCall - a function or aggregate invocation + * + * agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if + * agg_within_group is true, it was 'foo(...) WITHIN GROUP (ORDER BY ...)'. + * agg_star indicates we saw a 'foo(*)' construct, while agg_distinct + * indicates we saw 'foo(DISTINCT ...)'. In any of these cases, the + * construct *must* be an aggregate call. Otherwise, it might be either an + * aggregate or some other kind of function. However, if FILTER or OVER is + * present it had better be an aggregate or window function. + * + * Normally, you'd initialize this via makeFuncCall() and then only change the + * parts of the struct its defaults don't match afterwards, as needed. + */ +typedef struct FuncCall +{ + NodeTag type; + List *funcname; /* qualified name of function */ + List *args; /* the arguments (list of exprs) */ + List *agg_order; /* ORDER BY (list of SortBy) */ + Node *agg_filter; /* FILTER clause, if any */ + struct WindowDef *over; /* OVER clause, if any */ + bool agg_within_group; /* ORDER BY appeared in WITHIN GROUP */ + bool agg_star; /* argument was really '*' */ + bool agg_distinct; /* arguments were labeled DISTINCT */ + bool func_variadic; /* last argument was labeled VARIADIC */ + CoercionForm funcformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} FuncCall; + +/* + * A_Star - '*' representing all columns of a table or compound field + * + * This can appear within ColumnRef.fields, A_Indirection.indirection, and + * ResTarget.indirection lists. + */ +typedef struct A_Star +{ + NodeTag type; +} A_Star; + +/* + * A_Indices - array subscript or slice bounds ([idx] or [lidx:uidx]) + * + * In slice case, either or both of lidx and uidx can be NULL (omitted). + * In non-slice case, uidx holds the single subscript and lidx is always NULL. + */ +typedef struct A_Indices +{ + NodeTag type; + bool is_slice; /* true if slice (i.e., colon present) */ + Node *lidx; /* slice lower bound, if any */ + Node *uidx; /* subscript, or slice upper bound if any */ +} A_Indices; + +/* + * A_Indirection - select a field and/or array element from an expression + * + * The indirection list can contain A_Indices nodes (representing + * subscripting), String nodes (representing field selection --- the + * string value is the name of the field to select), and A_Star nodes + * (representing selection of all fields of a composite type). + * For example, a complex selection operation like + * (foo).field1[42][7].field2 + * would be represented with a single A_Indirection node having a 4-element + * indirection list. + * + * Currently, A_Star must appear only as the last list element --- the grammar + * is responsible for enforcing this! + */ +typedef struct A_Indirection +{ + NodeTag type; + Node *arg; /* the thing being selected from */ + List *indirection; /* subscripts and/or field names and/or * */ +} A_Indirection; + +/* + * A_ArrayExpr - an ARRAY[] construct + */ +typedef struct A_ArrayExpr +{ + NodeTag type; + List *elements; /* array element expressions */ + int location; /* token location, or -1 if unknown */ +} A_ArrayExpr; + +/* + * ResTarget - + * result target (used in target list of pre-transformed parse trees) + * + * In a SELECT target list, 'name' is the column label from an + * 'AS ColumnLabel' clause, or NULL if there was none, and 'val' is the + * value expression itself. The 'indirection' field is not used. + * + * INSERT uses ResTarget in its target-column-names list. Here, 'name' is + * the name of the destination column, 'indirection' stores any subscripts + * attached to the destination, and 'val' is not used. + * + * In an UPDATE target list, 'name' is the name of the destination column, + * 'indirection' stores any subscripts attached to the destination, and + * 'val' is the expression to assign. + * + * See A_Indirection for more info about what can appear in 'indirection'. + */ +typedef struct ResTarget +{ + NodeTag type; + char *name; /* column name or NULL */ + List *indirection; /* subscripts, field names, and '*', or NIL */ + Node *val; /* the value expression to compute or assign */ + int location; /* token location, or -1 if unknown */ +} ResTarget; + +/* + * MultiAssignRef - element of a row source expression for UPDATE + * + * In an UPDATE target list, when we have SET (a,b,c) = row-valued-expression, + * we generate separate ResTarget items for each of a,b,c. Their "val" trees + * are MultiAssignRef nodes numbered 1..n, linking to a common copy of the + * row-valued-expression (which parse analysis will process only once, when + * handling the MultiAssignRef with colno=1). + */ +typedef struct MultiAssignRef +{ + NodeTag type; + Node *source; /* the row-valued expression */ + int colno; /* column number for this target (1..n) */ + int ncolumns; /* number of targets in the construct */ +} MultiAssignRef; + +/* + * SortBy - for ORDER BY clause + */ +typedef struct SortBy +{ + NodeTag type; + Node *node; /* expression to sort on */ + SortByDir sortby_dir; /* ASC/DESC/USING/default */ + SortByNulls sortby_nulls; /* NULLS FIRST/LAST */ + List *useOp; /* name of op to use, if SORTBY_USING */ + int location; /* operator location, or -1 if none/unknown */ +} SortBy; + +/* + * WindowDef - raw representation of WINDOW and OVER clauses + * + * For entries in a WINDOW list, "name" is the window name being defined. + * For OVER clauses, we use "name" for the "OVER window" syntax, or "refname" + * for the "OVER (window)" syntax, which is subtly different --- the latter + * implies overriding the window frame clause. + */ +typedef struct WindowDef +{ + NodeTag type; + char *name; /* window's own name */ + char *refname; /* referenced window name, if any */ + List *partitionClause; /* PARTITION BY expression list */ + List *orderClause; /* ORDER BY (list of SortBy) */ + int frameOptions; /* frame_clause options, see below */ + Node *startOffset; /* expression for starting bound, if any */ + Node *endOffset; /* expression for ending bound, if any */ + int location; /* parse location, or -1 if none/unknown */ +} WindowDef; + +/* + * frameOptions is an OR of these bits. The NONDEFAULT and BETWEEN bits are + * used so that ruleutils.c can tell which properties were specified and + * which were defaulted; the correct behavioral bits must be set either way. + * The START_foo and END_foo options must come in pairs of adjacent bits for + * the convenience of gram.y, even though some of them are useless/invalid. + */ +#define FRAMEOPTION_NONDEFAULT 0x00001 /* any specified? */ +#define FRAMEOPTION_RANGE 0x00002 /* RANGE behavior */ +#define FRAMEOPTION_ROWS 0x00004 /* ROWS behavior */ +#define FRAMEOPTION_GROUPS 0x00008 /* GROUPS behavior */ +#define FRAMEOPTION_BETWEEN 0x00010 /* BETWEEN given? */ +#define FRAMEOPTION_START_UNBOUNDED_PRECEDING 0x00020 /* start is U. P. */ +#define FRAMEOPTION_END_UNBOUNDED_PRECEDING 0x00040 /* (disallowed) */ +#define FRAMEOPTION_START_UNBOUNDED_FOLLOWING 0x00080 /* (disallowed) */ +#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING 0x00100 /* end is U. F. */ +#define FRAMEOPTION_START_CURRENT_ROW 0x00200 /* start is C. R. */ +#define FRAMEOPTION_END_CURRENT_ROW 0x00400 /* end is C. R. */ +#define FRAMEOPTION_START_OFFSET_PRECEDING 0x00800 /* start is O. P. */ +#define FRAMEOPTION_END_OFFSET_PRECEDING 0x01000 /* end is O. P. */ +#define FRAMEOPTION_START_OFFSET_FOLLOWING 0x02000 /* start is O. F. */ +#define FRAMEOPTION_END_OFFSET_FOLLOWING 0x04000 /* end is O. F. */ +#define FRAMEOPTION_EXCLUDE_CURRENT_ROW 0x08000 /* omit C.R. */ +#define FRAMEOPTION_EXCLUDE_GROUP 0x10000 /* omit C.R. & peers */ +#define FRAMEOPTION_EXCLUDE_TIES 0x20000 /* omit C.R.'s peers */ + +#define FRAMEOPTION_START_OFFSET \ + (FRAMEOPTION_START_OFFSET_PRECEDING | FRAMEOPTION_START_OFFSET_FOLLOWING) +#define FRAMEOPTION_END_OFFSET \ + (FRAMEOPTION_END_OFFSET_PRECEDING | FRAMEOPTION_END_OFFSET_FOLLOWING) +#define FRAMEOPTION_EXCLUSION \ + (FRAMEOPTION_EXCLUDE_CURRENT_ROW | FRAMEOPTION_EXCLUDE_GROUP | \ + FRAMEOPTION_EXCLUDE_TIES) + +#define FRAMEOPTION_DEFAULTS \ + (FRAMEOPTION_RANGE | FRAMEOPTION_START_UNBOUNDED_PRECEDING | \ + FRAMEOPTION_END_CURRENT_ROW) + +/* + * RangeSubselect - subquery appearing in a FROM clause + */ +typedef struct RangeSubselect +{ + NodeTag type; + bool lateral; /* does it have LATERAL prefix? */ + Node *subquery; /* the untransformed sub-select clause */ + Alias *alias; /* table alias & optional column aliases */ +} RangeSubselect; + +/* + * RangeFunction - function call appearing in a FROM clause + * + * functions is a List because we use this to represent the construct + * ROWS FROM(func1(...), func2(...), ...). Each element of this list is a + * two-element sublist, the first element being the untransformed function + * call tree, and the second element being a possibly-empty list of ColumnDef + * nodes representing any columndef list attached to that function within the + * ROWS FROM() syntax. + * + * alias and coldeflist represent any alias and/or columndef list attached + * at the top level. (We disallow coldeflist appearing both here and + * per-function, but that's checked in parse analysis, not by the grammar.) + */ +typedef struct RangeFunction +{ + NodeTag type; + bool lateral; /* does it have LATERAL prefix? */ + bool ordinality; /* does it have WITH ORDINALITY suffix? */ + bool is_rowsfrom; /* is result of ROWS FROM() syntax? */ + List *functions; /* per-function information, see above */ + Alias *alias; /* table alias & optional column aliases */ + List *coldeflist; /* list of ColumnDef nodes to describe result + * of function returning RECORD */ +} RangeFunction; + +/* + * RangeTableFunc - raw form of "table functions" such as XMLTABLE + */ +typedef struct RangeTableFunc +{ + NodeTag type; + bool lateral; /* does it have LATERAL prefix? */ + Node *docexpr; /* document expression */ + Node *rowexpr; /* row generator expression */ + List *namespaces; /* list of namespaces as ResTarget */ + List *columns; /* list of RangeTableFuncCol */ + Alias *alias; /* table alias & optional column aliases */ + int location; /* token location, or -1 if unknown */ +} RangeTableFunc; + +/* + * RangeTableFuncCol - one column in a RangeTableFunc->columns + * + * If for_ordinality is true (FOR ORDINALITY), then the column is an int4 + * column and the rest of the fields are ignored. + */ +typedef struct RangeTableFuncCol +{ + NodeTag type; + char *colname; /* name of generated column */ + TypeName *typeName; /* type of generated column */ + bool for_ordinality; /* does it have FOR ORDINALITY? */ + bool is_not_null; /* does it have NOT NULL? */ + Node *colexpr; /* column filter expression */ + Node *coldefexpr; /* column default value expression */ + int location; /* token location, or -1 if unknown */ +} RangeTableFuncCol; + +/* + * RangeTableSample - TABLESAMPLE appearing in a raw FROM clause + * + * This node, appearing only in raw parse trees, represents + * <relation> TABLESAMPLE <method> (<params>) REPEATABLE (<num>) + * Currently, the <relation> can only be a RangeVar, but we might in future + * allow RangeSubselect and other options. Note that the RangeTableSample + * is wrapped around the node representing the <relation>, rather than being + * a subfield of it. + */ +typedef struct RangeTableSample +{ + NodeTag type; + Node *relation; /* relation to be sampled */ + List *method; /* sampling method name (possibly qualified) */ + List *args; /* argument(s) for sampling method */ + Node *repeatable; /* REPEATABLE expression, or NULL if none */ + int location; /* method name location, or -1 if unknown */ +} RangeTableSample; + +/* + * ColumnDef - column definition (used in various creates) + * + * If the column has a default value, we may have the value expression + * in either "raw" form (an untransformed parse tree) or "cooked" form + * (a post-parse-analysis, executable expression tree), depending on + * how this ColumnDef node was created (by parsing, or by inheritance + * from an existing relation). We should never have both in the same node! + * + * Similarly, we may have a COLLATE specification in either raw form + * (represented as a CollateClause with arg==NULL) or cooked form + * (the collation's OID). + * + * The constraints list may contain a CONSTR_DEFAULT item in a raw + * parsetree produced by gram.y, but transformCreateStmt will remove + * the item and set raw_default instead. CONSTR_DEFAULT items + * should not appear in any subsequent processing. + */ +typedef struct ColumnDef +{ + NodeTag type; + char *colname; /* name of column */ + TypeName *typeName; /* type of column */ + char *compression; /* compression method for column */ + int inhcount; /* number of times column is inherited */ + bool is_local; /* column has local (non-inherited) def'n */ + bool is_not_null; /* NOT NULL constraint specified? */ + bool is_from_type; /* column definition came from table type */ + char storage; /* attstorage setting, or 0 for default */ + Node *raw_default; /* default value (untransformed parse tree) */ + Node *cooked_default; /* default value (transformed expr tree) */ + char identity; /* attidentity setting */ + RangeVar *identitySequence; /* to store identity sequence name for + * ALTER TABLE ... ADD COLUMN */ + char generated; /* attgenerated setting */ + CollateClause *collClause; /* untransformed COLLATE spec, if any */ + Oid collOid; /* collation OID (InvalidOid if not set) */ + List *constraints; /* other constraints on column */ + List *fdwoptions; /* per-column FDW options */ + int location; /* parse location, or -1 if none/unknown */ +} ColumnDef; + +/* + * TableLikeClause - CREATE TABLE ( ... LIKE ... ) clause + */ +typedef struct TableLikeClause +{ + NodeTag type; + RangeVar *relation; + bits32 options; /* OR of TableLikeOption flags */ + Oid relationOid; /* If table has been looked up, its OID */ +} TableLikeClause; + +typedef enum TableLikeOption +{ + CREATE_TABLE_LIKE_COMMENTS = 1 << 0, + CREATE_TABLE_LIKE_COMPRESSION = 1 << 1, + CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 2, + CREATE_TABLE_LIKE_DEFAULTS = 1 << 3, + CREATE_TABLE_LIKE_GENERATED = 1 << 4, + CREATE_TABLE_LIKE_IDENTITY = 1 << 5, + CREATE_TABLE_LIKE_INDEXES = 1 << 6, + CREATE_TABLE_LIKE_STATISTICS = 1 << 7, + CREATE_TABLE_LIKE_STORAGE = 1 << 8, + CREATE_TABLE_LIKE_ALL = PG_INT32_MAX +} TableLikeOption; + +/* + * IndexElem - index parameters (used in CREATE INDEX, and in ON CONFLICT) + * + * For a plain index attribute, 'name' is the name of the table column to + * index, and 'expr' is NULL. For an index expression, 'name' is NULL and + * 'expr' is the expression tree. + */ +typedef struct IndexElem +{ + NodeTag type; + char *name; /* name of attribute to index, or NULL */ + Node *expr; /* expression to index, or NULL */ + char *indexcolname; /* name for index column; NULL = default */ + List *collation; /* name of collation; NIL = default */ + List *opclass; /* name of desired opclass; NIL = default */ + List *opclassopts; /* opclass-specific options, or NIL */ + SortByDir ordering; /* ASC/DESC/default */ + SortByNulls nulls_ordering; /* FIRST/LAST/default */ +} IndexElem; + +/* + * DefElem - a generic "name = value" option definition + * + * In some contexts the name can be qualified. Also, certain SQL commands + * allow a SET/ADD/DROP action to be attached to option settings, so it's + * convenient to carry a field for that too. (Note: currently, it is our + * practice that the grammar allows namespace and action only in statements + * where they are relevant; C code can just ignore those fields in other + * statements.) + */ +typedef enum DefElemAction +{ + DEFELEM_UNSPEC, /* no action given */ + DEFELEM_SET, + DEFELEM_ADD, + DEFELEM_DROP +} DefElemAction; + +typedef struct DefElem +{ + NodeTag type; + char *defnamespace; /* NULL if unqualified name */ + char *defname; + Node *arg; /* typically Integer, Float, String, or + * TypeName */ + DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */ + int location; /* token location, or -1 if unknown */ +} DefElem; + +/* + * LockingClause - raw representation of FOR [NO KEY] UPDATE/[KEY] SHARE + * options + * + * Note: lockedRels == NIL means "all relations in query". Otherwise it + * is a list of RangeVar nodes. (We use RangeVar mainly because it carries + * a location field --- currently, parse analysis insists on unqualified + * names in LockingClause.) + */ +typedef struct LockingClause +{ + NodeTag type; + List *lockedRels; /* FOR [KEY] UPDATE/SHARE relations */ + LockClauseStrength strength; + LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */ +} LockingClause; + +/* + * XMLSERIALIZE (in raw parse tree only) + */ +typedef struct XmlSerialize +{ + NodeTag type; + XmlOptionType xmloption; /* DOCUMENT or CONTENT */ + Node *expr; + TypeName *typeName; + int location; /* token location, or -1 if unknown */ +} XmlSerialize; + +/* Partitioning related definitions */ + +/* + * PartitionElem - parse-time representation of a single partition key + * + * expr can be either a raw expression tree or a parse-analyzed expression. + * We don't store these on-disk, though. + */ +typedef struct PartitionElem +{ + NodeTag type; + char *name; /* name of column to partition on, or NULL */ + Node *expr; /* expression to partition on, or NULL */ + List *collation; /* name of collation; NIL = default */ + List *opclass; /* name of desired opclass; NIL = default */ + int location; /* token location, or -1 if unknown */ +} PartitionElem; + +/* + * PartitionSpec - parse-time representation of a partition key specification + * + * This represents the key space we will be partitioning on. + */ +typedef struct PartitionSpec +{ + NodeTag type; + char *strategy; /* partitioning strategy ('hash', 'list' or + * 'range') */ + List *partParams; /* List of PartitionElems */ + int location; /* token location, or -1 if unknown */ +} PartitionSpec; + +/* Internal codes for partitioning strategies */ +#define PARTITION_STRATEGY_HASH 'h' +#define PARTITION_STRATEGY_LIST 'l' +#define PARTITION_STRATEGY_RANGE 'r' + +/* + * PartitionBoundSpec - a partition bound specification + * + * This represents the portion of the partition key space assigned to a + * particular partition. These are stored on disk in pg_class.relpartbound. + */ +struct PartitionBoundSpec +{ + NodeTag type; + + char strategy; /* see PARTITION_STRATEGY codes above */ + bool is_default; /* is it a default partition bound? */ + + /* Partitioning info for HASH strategy: */ + int modulus; + int remainder; + + /* Partitioning info for LIST strategy: */ + List *listdatums; /* List of Consts (or A_Consts in raw tree) */ + + /* Partitioning info for RANGE strategy: */ + List *lowerdatums; /* List of PartitionRangeDatums */ + List *upperdatums; /* List of PartitionRangeDatums */ + + int location; /* token location, or -1 if unknown */ +}; + +/* + * PartitionRangeDatum - one of the values in a range partition bound + * + * This can be MINVALUE, MAXVALUE or a specific bounded value. + */ +typedef enum PartitionRangeDatumKind +{ + PARTITION_RANGE_DATUM_MINVALUE = -1, /* less than any other value */ + PARTITION_RANGE_DATUM_VALUE = 0, /* a specific (bounded) value */ + PARTITION_RANGE_DATUM_MAXVALUE = 1 /* greater than any other value */ +} PartitionRangeDatumKind; + +typedef struct PartitionRangeDatum +{ + NodeTag type; + + PartitionRangeDatumKind kind; + Node *value; /* Const (or A_Const in raw tree), if kind is + * PARTITION_RANGE_DATUM_VALUE, else NULL */ + + int location; /* token location, or -1 if unknown */ +} PartitionRangeDatum; + +/* + * PartitionCmd - info for ALTER TABLE/INDEX ATTACH/DETACH PARTITION commands + */ +typedef struct PartitionCmd +{ + NodeTag type; + RangeVar *name; /* name of partition to attach/detach */ + PartitionBoundSpec *bound; /* FOR VALUES, if attaching */ + bool concurrent; +} PartitionCmd; + +/**************************************************************************** + * Nodes for a Query tree + ****************************************************************************/ + +/*-------------------- + * RangeTblEntry - + * A range table is a List of RangeTblEntry nodes. + * + * A range table entry may represent a plain relation, a sub-select in + * FROM, or the result of a JOIN clause. (Only explicit JOIN syntax + * produces an RTE, not the implicit join resulting from multiple FROM + * items. This is because we only need the RTE to deal with SQL features + * like outer joins and join-output-column aliasing.) Other special + * RTE types also exist, as indicated by RTEKind. + * + * Note that we consider RTE_RELATION to cover anything that has a pg_class + * entry. relkind distinguishes the sub-cases. + * + * alias is an Alias node representing the AS alias-clause attached to the + * FROM expression, or NULL if no clause. + * + * eref is the table reference name and column reference names (either + * real or aliases). Note that system columns (OID etc) are not included + * in the column list. + * eref->aliasname is required to be present, and should generally be used + * to identify the RTE for error messages etc. + * + * In RELATION RTEs, the colnames in both alias and eref are indexed by + * physical attribute number; this means there must be colname entries for + * dropped columns. When building an RTE we insert empty strings ("") for + * dropped columns. Note however that a stored rule may have nonempty + * colnames for columns dropped since the rule was created (and for that + * matter the colnames might be out of date due to column renamings). + * The same comments apply to FUNCTION RTEs when a function's return type + * is a named composite type. + * + * In JOIN RTEs, the colnames in both alias and eref are one-to-one with + * joinaliasvars entries. A JOIN RTE will omit columns of its inputs when + * those columns are known to be dropped at parse time. Again, however, + * a stored rule might contain entries for columns dropped since the rule + * was created. (This is only possible for columns not actually referenced + * in the rule.) When loading a stored rule, we replace the joinaliasvars + * items for any such columns with null pointers. (We can't simply delete + * them from the joinaliasvars list, because that would affect the attnums + * of Vars referencing the rest of the list.) + * + * inh is true for relation references that should be expanded to include + * inheritance children, if the rel has any. This *must* be false for + * RTEs other than RTE_RELATION entries. + * + * inFromCl marks those range variables that are listed in the FROM clause. + * It's false for RTEs that are added to a query behind the scenes, such + * as the NEW and OLD variables for a rule, or the subqueries of a UNION. + * This flag is not used during parsing (except in transformLockingClause, + * q.v.); the parser now uses a separate "namespace" data structure to + * control visibility. But it is needed by ruleutils.c to determine + * whether RTEs should be shown in decompiled queries. + * + * requiredPerms and checkAsUser specify run-time access permissions + * checks to be performed at query startup. The user must have *all* + * of the permissions that are OR'd together in requiredPerms (zero + * indicates no permissions checking). If checkAsUser is not zero, + * then do the permissions checks using the access rights of that user, + * not the current effective user ID. (This allows rules to act as + * setuid gateways.) Permissions checks only apply to RELATION RTEs. + * + * For SELECT/INSERT/UPDATE permissions, if the user doesn't have + * table-wide permissions then it is sufficient to have the permissions + * on all columns identified in selectedCols (for SELECT) and/or + * insertedCols and/or updatedCols (INSERT with ON CONFLICT DO UPDATE may + * have all 3). selectedCols, insertedCols and updatedCols are bitmapsets, + * which cannot have negative integer members, so we subtract + * FirstLowInvalidHeapAttributeNumber from column numbers before storing + * them in these fields. A whole-row Var reference is represented by + * setting the bit for InvalidAttrNumber. + * + * updatedCols is also used in some other places, for example, to determine + * which triggers to fire and in FDWs to know which changed columns they + * need to ship off. + * + * extraUpdatedCols is no longer used or maintained; it's always empty. + * + * securityQuals is a list of security barrier quals (boolean expressions), + * to be tested in the listed order before returning a row from the + * relation. It is always NIL in parser output. Entries are added by the + * rewriter to implement security-barrier views and/or row-level security. + * Note that the planner turns each boolean expression into an implicitly + * AND'ed sublist, as is its usual habit with qualification expressions. + *-------------------- + */ +typedef enum RTEKind +{ + RTE_RELATION, /* ordinary relation reference */ + RTE_SUBQUERY, /* subquery in FROM */ + RTE_JOIN, /* join */ + RTE_FUNCTION, /* function in FROM */ + RTE_TABLEFUNC, /* TableFunc(.., column list) */ + RTE_VALUES, /* VALUES (<exprlist>), (<exprlist>), ... */ + RTE_CTE, /* common table expr (WITH list element) */ + RTE_NAMEDTUPLESTORE, /* tuplestore, e.g. for AFTER triggers */ + RTE_RESULT /* RTE represents an empty FROM clause; such + * RTEs are added by the planner, they're not + * present during parsing or rewriting */ +} RTEKind; + +typedef struct RangeTblEntry +{ + NodeTag type; + + RTEKind rtekind; /* see above */ + + /* + * XXX the fields applicable to only some rte kinds should be merged into + * a union. I didn't do this yet because the diffs would impact a lot of + * code that is being actively worked on. FIXME someday. + */ + + /* + * Fields valid for a plain relation RTE (else zero): + * + * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate + * that the tuple format of the tuplestore is the same as the referenced + * relation. This allows plans referencing AFTER trigger transition + * tables to be invalidated if the underlying table is altered. + * + * rellockmode is really LOCKMODE, but it's declared int to avoid having + * to include lock-related headers here. It must be RowExclusiveLock if + * the RTE is an INSERT/UPDATE/DELETE/MERGE target, else RowShareLock if + * the RTE is a SELECT FOR UPDATE/FOR SHARE target, else AccessShareLock. + * + * Note: in some cases, rule expansion may result in RTEs that are marked + * with RowExclusiveLock even though they are not the target of the + * current query; this happens if a DO ALSO rule simply scans the original + * target table. We leave such RTEs with their original lockmode so as to + * avoid getting an additional, lesser lock. + */ + Oid relid; /* OID of the relation */ + char relkind; /* relation kind (see pg_class.relkind) */ + int rellockmode; /* lock level that query requires on the rel */ + struct TableSampleClause *tablesample; /* sampling info, or NULL */ + + /* + * Fields valid for a subquery RTE (else NULL): + */ + Query *subquery; /* the sub-query */ + bool security_barrier; /* is from security_barrier view? */ + + /* + * Fields valid for a join RTE (else NULL/zero): + * + * joinaliasvars is a list of (usually) Vars corresponding to the columns + * of the join result. An alias Var referencing column K of the join + * result can be replaced by the K'th element of joinaliasvars --- but to + * simplify the task of reverse-listing aliases correctly, we do not do + * that until planning time. In detail: an element of joinaliasvars can + * be a Var of one of the join's input relations, or such a Var with an + * implicit coercion to the join's output column type, or a COALESCE + * expression containing the two input column Vars (possibly coerced). + * Elements beyond the first joinmergedcols entries are always just Vars, + * and are never referenced from elsewhere in the query (that is, join + * alias Vars are generated only for merged columns). We keep these + * entries only because they're needed in expandRTE() and similar code. + * + * Within a Query loaded from a stored rule, it is possible for non-merged + * joinaliasvars items to be null pointers, which are placeholders for + * (necessarily unreferenced) columns dropped since the rule was made. + * Also, once planning begins, joinaliasvars items can be almost anything, + * as a result of subquery-flattening substitutions. + * + * joinleftcols is an integer list of physical column numbers of the left + * join input rel that are included in the join; likewise joinrighttcols + * for the right join input rel. (Which rels those are can be determined + * from the associated JoinExpr.) If the join is USING/NATURAL, then the + * first joinmergedcols entries in each list identify the merged columns. + * The merged columns come first in the join output, then remaining + * columns of the left input, then remaining columns of the right. + * + * Note that input columns could have been dropped after creation of a + * stored rule, if they are not referenced in the query (in particular, + * merged columns could not be dropped); this is not accounted for in + * joinleftcols/joinrighttcols. + */ + JoinType jointype; /* type of join */ + int joinmergedcols; /* number of merged (JOIN USING) columns */ + List *joinaliasvars; /* list of alias-var expansions */ + List *joinleftcols; /* left-side input column numbers */ + List *joinrightcols; /* right-side input column numbers */ + + /* + * join_using_alias is an alias clause attached directly to JOIN/USING. It + * is different from the alias field (below) in that it does not hide the + * range variables of the tables being joined. + */ + Alias *join_using_alias; + + /* + * Fields valid for a function RTE (else NIL/zero): + * + * When funcordinality is true, the eref->colnames list includes an alias + * for the ordinality column. The ordinality column is otherwise + * implicit, and must be accounted for "by hand" in places such as + * expandRTE(). + */ + List *functions; /* list of RangeTblFunction nodes */ + bool funcordinality; /* is this called WITH ORDINALITY? */ + + /* + * Fields valid for a TableFunc RTE (else NULL): + */ + TableFunc *tablefunc; + + /* + * Fields valid for a values RTE (else NIL): + */ + List *values_lists; /* list of expression lists */ + + /* + * Fields valid for a CTE RTE (else NULL/zero): + */ + char *ctename; /* name of the WITH list item */ + Index ctelevelsup; /* number of query levels up */ + bool self_reference; /* is this a recursive self-reference? */ + + /* + * Fields valid for CTE, VALUES, ENR, and TableFunc RTEs (else NIL): + * + * We need these for CTE RTEs so that the types of self-referential + * columns are well-defined. For VALUES RTEs, storing these explicitly + * saves having to re-determine the info by scanning the values_lists. For + * ENRs, we store the types explicitly here (we could get the information + * from the catalogs if 'relid' was supplied, but we'd still need these + * for TupleDesc-based ENRs, so we might as well always store the type + * info here). For TableFuncs, these fields are redundant with data in + * the TableFunc node, but keeping them here allows some code sharing with + * the other cases. + * + * For ENRs only, we have to consider the possibility of dropped columns. + * A dropped column is included in these lists, but it will have zeroes in + * all three lists (as well as an empty-string entry in eref). Testing + * for zero coltype is the standard way to detect a dropped column. + */ + List *coltypes; /* OID list of column type OIDs */ + List *coltypmods; /* integer list of column typmods */ + List *colcollations; /* OID list of column collation OIDs */ + + /* + * Fields valid for ENR RTEs (else NULL/zero): + */ + char *enrname; /* name of ephemeral named relation */ + Cardinality enrtuples; /* estimated or actual from caller */ + + /* + * Fields valid in all RTEs: + */ + Alias *alias; /* user-written alias clause, if any */ + Alias *eref; /* expanded reference names */ + bool lateral; /* subquery, function, or values is LATERAL? */ + bool inh; /* inheritance requested? */ + bool inFromCl; /* present in FROM clause? */ + AclMode requiredPerms; /* bitmask of required access permissions */ + Oid checkAsUser; /* if valid, check access as this role */ + Bitmapset *selectedCols; /* columns needing SELECT permission */ + Bitmapset *insertedCols; /* columns needing INSERT permission */ + Bitmapset *updatedCols; /* columns needing UPDATE permission */ + Bitmapset *extraUpdatedCols; /* generated columns being updated */ + List *securityQuals; /* security barrier quals to apply, if any */ +} RangeTblEntry; + +/* + * RangeTblFunction - + * RangeTblEntry subsidiary data for one function in a FUNCTION RTE. + * + * If the function had a column definition list (required for an + * otherwise-unspecified RECORD result), funccolnames lists the names given + * in the definition list, funccoltypes lists their declared column types, + * funccoltypmods lists their typmods, funccolcollations their collations. + * Otherwise, those fields are NIL. + * + * Notice we don't attempt to store info about the results of functions + * returning named composite types, because those can change from time to + * time. We do however remember how many columns we thought the type had + * (including dropped columns!), so that we can successfully ignore any + * columns added after the query was parsed. + */ +typedef struct RangeTblFunction +{ + NodeTag type; + + Node *funcexpr; /* expression tree for func call */ + int funccolcount; /* number of columns it contributes to RTE */ + /* These fields record the contents of a column definition list, if any: */ + List *funccolnames; /* column names (list of String) */ + List *funccoltypes; /* OID list of column type OIDs */ + List *funccoltypmods; /* integer list of column typmods */ + List *funccolcollations; /* OID list of column collation OIDs */ + /* This is set during planning for use by the executor: */ + Bitmapset *funcparams; /* PARAM_EXEC Param IDs affecting this func */ +} RangeTblFunction; + +/* + * TableSampleClause - TABLESAMPLE appearing in a transformed FROM clause + * + * Unlike RangeTableSample, this is a subnode of the relevant RangeTblEntry. + */ +typedef struct TableSampleClause +{ + NodeTag type; + Oid tsmhandler; /* OID of the tablesample handler function */ + List *args; /* tablesample argument expression(s) */ + Expr *repeatable; /* REPEATABLE expression, or NULL if none */ +} TableSampleClause; + +/* + * WithCheckOption - + * representation of WITH CHECK OPTION checks to be applied to new tuples + * when inserting/updating an auto-updatable view, or RLS WITH CHECK + * policies to be applied when inserting/updating a relation with RLS. + */ +typedef enum WCOKind +{ + WCO_VIEW_CHECK, /* WCO on an auto-updatable view */ + WCO_RLS_INSERT_CHECK, /* RLS INSERT WITH CHECK policy */ + WCO_RLS_UPDATE_CHECK, /* RLS UPDATE WITH CHECK policy */ + WCO_RLS_CONFLICT_CHECK, /* RLS ON CONFLICT DO UPDATE USING policy */ + WCO_RLS_MERGE_UPDATE_CHECK, /* RLS MERGE UPDATE USING policy */ + WCO_RLS_MERGE_DELETE_CHECK /* RLS MERGE DELETE USING policy */ +} WCOKind; + +typedef struct WithCheckOption +{ + NodeTag type; + WCOKind kind; /* kind of WCO */ + char *relname; /* name of relation that specified the WCO */ + char *polname; /* name of RLS policy being checked */ + Node *qual; /* constraint qual to check */ + bool cascaded; /* true for a cascaded WCO on a view */ +} WithCheckOption; + +/* + * SortGroupClause - + * representation of ORDER BY, GROUP BY, PARTITION BY, + * DISTINCT, DISTINCT ON items + * + * You might think that ORDER BY is only interested in defining ordering, + * and GROUP/DISTINCT are only interested in defining equality. However, + * one way to implement grouping is to sort and then apply a "uniq"-like + * filter. So it's also interesting to keep track of possible sort operators + * for GROUP/DISTINCT, and in particular to try to sort for the grouping + * in a way that will also yield a requested ORDER BY ordering. So we need + * to be able to compare ORDER BY and GROUP/DISTINCT lists, which motivates + * the decision to give them the same representation. + * + * tleSortGroupRef must match ressortgroupref of exactly one entry of the + * query's targetlist; that is the expression to be sorted or grouped by. + * eqop is the OID of the equality operator. + * sortop is the OID of the ordering operator (a "<" or ">" operator), + * or InvalidOid if not available. + * nulls_first means about what you'd expect. If sortop is InvalidOid + * then nulls_first is meaningless and should be set to false. + * hashable is true if eqop is hashable (note this condition also depends + * on the datatype of the input expression). + * + * In an ORDER BY item, all fields must be valid. (The eqop isn't essential + * here, but it's cheap to get it along with the sortop, and requiring it + * to be valid eases comparisons to grouping items.) Note that this isn't + * actually enough information to determine an ordering: if the sortop is + * collation-sensitive, a collation OID is needed too. We don't store the + * collation in SortGroupClause because it's not available at the time the + * parser builds the SortGroupClause; instead, consult the exposed collation + * of the referenced targetlist expression to find out what it is. + * + * In a grouping item, eqop must be valid. If the eqop is a btree equality + * operator, then sortop should be set to a compatible ordering operator. + * We prefer to set eqop/sortop/nulls_first to match any ORDER BY item that + * the query presents for the same tlist item. If there is none, we just + * use the default ordering op for the datatype. + * + * If the tlist item's type has a hash opclass but no btree opclass, then + * we will set eqop to the hash equality operator, sortop to InvalidOid, + * and nulls_first to false. A grouping item of this kind can only be + * implemented by hashing, and of course it'll never match an ORDER BY item. + * + * The hashable flag is provided since we generally have the requisite + * information readily available when the SortGroupClause is constructed, + * and it's relatively expensive to get it again later. Note there is no + * need for a "sortable" flag since OidIsValid(sortop) serves the purpose. + * + * A query might have both ORDER BY and DISTINCT (or DISTINCT ON) clauses. + * In SELECT DISTINCT, the distinctClause list is as long or longer than the + * sortClause list, while in SELECT DISTINCT ON it's typically shorter. + * The two lists must match up to the end of the shorter one --- the parser + * rearranges the distinctClause if necessary to make this true. (This + * restriction ensures that only one sort step is needed to both satisfy the + * ORDER BY and set up for the Unique step. This is semantically necessary + * for DISTINCT ON, and presents no real drawback for DISTINCT.) + */ +typedef struct SortGroupClause +{ + NodeTag type; + Index tleSortGroupRef; /* reference into targetlist */ + Oid eqop; /* the equality operator ('=' op) */ + Oid sortop; /* the ordering operator ('<' op), or 0 */ + bool nulls_first; /* do NULLs come before normal values? */ + bool hashable; /* can eqop be implemented by hashing? */ +} SortGroupClause; + +/* + * GroupingSet - + * representation of CUBE, ROLLUP and GROUPING SETS clauses + * + * In a Query with grouping sets, the groupClause contains a flat list of + * SortGroupClause nodes for each distinct expression used. The actual + * structure of the GROUP BY clause is given by the groupingSets tree. + * + * In the raw parser output, GroupingSet nodes (of all types except SIMPLE + * which is not used) are potentially mixed in with the expressions in the + * groupClause of the SelectStmt. (An expression can't contain a GroupingSet, + * but a list may mix GroupingSet and expression nodes.) At this stage, the + * content of each node is a list of expressions, some of which may be RowExprs + * which represent sublists rather than actual row constructors, and nested + * GroupingSet nodes where legal in the grammar. The structure directly + * reflects the query syntax. + * + * In parse analysis, the transformed expressions are used to build the tlist + * and groupClause list (of SortGroupClause nodes), and the groupingSets tree + * is eventually reduced to a fixed format: + * + * EMPTY nodes represent (), and obviously have no content + * + * SIMPLE nodes represent a list of one or more expressions to be treated as an + * atom by the enclosing structure; the content is an integer list of + * ressortgroupref values (see SortGroupClause) + * + * CUBE and ROLLUP nodes contain a list of one or more SIMPLE nodes. + * + * SETS nodes contain a list of EMPTY, SIMPLE, CUBE or ROLLUP nodes, but after + * parse analysis they cannot contain more SETS nodes; enough of the syntactic + * transforms of the spec have been applied that we no longer have arbitrarily + * deep nesting (though we still preserve the use of cube/rollup). + * + * Note that if the groupingSets tree contains no SIMPLE nodes (only EMPTY + * nodes at the leaves), then the groupClause will be empty, but this is still + * an aggregation query (similar to using aggs or HAVING without GROUP BY). + * + * As an example, the following clause: + * + * GROUP BY GROUPING SETS ((a,b), CUBE(c,(d,e))) + * + * looks like this after raw parsing: + * + * SETS( RowExpr(a,b) , CUBE( c, RowExpr(d,e) ) ) + * + * and parse analysis converts it to: + * + * SETS( SIMPLE(1,2), CUBE( SIMPLE(3), SIMPLE(4,5) ) ) + */ +typedef enum GroupingSetKind +{ + GROUPING_SET_EMPTY, + GROUPING_SET_SIMPLE, + GROUPING_SET_ROLLUP, + GROUPING_SET_CUBE, + GROUPING_SET_SETS +} GroupingSetKind; + +typedef struct GroupingSet +{ + NodeTag type; + GroupingSetKind kind; + List *content; + int location; +} GroupingSet; + +/* + * WindowClause - + * transformed representation of WINDOW and OVER clauses + * + * A parsed Query's windowClause list contains these structs. "name" is set + * if the clause originally came from WINDOW, and is NULL if it originally + * was an OVER clause (but note that we collapse out duplicate OVERs). + * partitionClause and orderClause are lists of SortGroupClause structs. + * If we have RANGE with offset PRECEDING/FOLLOWING, the semantics of that are + * specified by startInRangeFunc/inRangeColl/inRangeAsc/inRangeNullsFirst + * for the start offset, or endInRangeFunc/inRange* for the end offset. + * winref is an ID number referenced by WindowFunc nodes; it must be unique + * among the members of a Query's windowClause list. + * When refname isn't null, the partitionClause is always copied from there; + * the orderClause might or might not be copied (see copiedOrder); the framing + * options are never copied, per spec. + */ +typedef struct WindowClause +{ + NodeTag type; + char *name; /* window name (NULL in an OVER clause) */ + char *refname; /* referenced window name, if any */ + List *partitionClause; /* PARTITION BY list */ + List *orderClause; /* ORDER BY list */ + int frameOptions; /* frame_clause options, see WindowDef */ + Node *startOffset; /* expression for starting bound, if any */ + Node *endOffset; /* expression for ending bound, if any */ + List *runCondition; /* qual to help short-circuit execution */ + Oid startInRangeFunc; /* in_range function for startOffset */ + Oid endInRangeFunc; /* in_range function for endOffset */ + Oid inRangeColl; /* collation for in_range tests */ + bool inRangeAsc; /* use ASC sort order for in_range tests? */ + bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ + Index winref; /* ID referenced by window functions */ + bool copiedOrder; /* did we copy orderClause from refname? */ +} WindowClause; + +/* + * RowMarkClause - + * parser output representation of FOR [KEY] UPDATE/SHARE clauses + * + * Query.rowMarks contains a separate RowMarkClause node for each relation + * identified as a FOR [KEY] UPDATE/SHARE target. If one of these clauses + * is applied to a subquery, we generate RowMarkClauses for all normal and + * subquery rels in the subquery, but they are marked pushedDown = true to + * distinguish them from clauses that were explicitly written at this query + * level. Also, Query.hasForUpdate tells whether there were explicit FOR + * UPDATE/SHARE/KEY SHARE clauses in the current query level. + */ +typedef struct RowMarkClause +{ + NodeTag type; + Index rti; /* range table index of target relation */ + LockClauseStrength strength; + LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */ + bool pushedDown; /* pushed down from higher query level? */ +} RowMarkClause; + +/* + * WithClause - + * representation of WITH clause + * + * Note: WithClause does not propagate into the Query representation; + * but CommonTableExpr does. + */ +typedef struct WithClause +{ + NodeTag type; + List *ctes; /* list of CommonTableExprs */ + bool recursive; /* true = WITH RECURSIVE */ + int location; /* token location, or -1 if unknown */ +} WithClause; + +/* + * InferClause - + * ON CONFLICT unique index inference clause + * + * Note: InferClause does not propagate into the Query representation. + */ +typedef struct InferClause +{ + NodeTag type; + List *indexElems; /* IndexElems to infer unique index */ + Node *whereClause; /* qualification (partial-index predicate) */ + char *conname; /* Constraint name, or NULL if unnamed */ + int location; /* token location, or -1 if unknown */ +} InferClause; + +/* + * OnConflictClause - + * representation of ON CONFLICT clause + * + * Note: OnConflictClause does not propagate into the Query representation. + */ +typedef struct OnConflictClause +{ + NodeTag type; + OnConflictAction action; /* DO NOTHING or UPDATE? */ + InferClause *infer; /* Optional index inference clause */ + List *targetList; /* the target list (of ResTarget) */ + Node *whereClause; /* qualifications */ + int location; /* token location, or -1 if unknown */ +} OnConflictClause; + +/* + * CommonTableExpr - + * representation of WITH list element + */ + +typedef enum CTEMaterialize +{ + CTEMaterializeDefault, /* no option specified */ + CTEMaterializeAlways, /* MATERIALIZED */ + CTEMaterializeNever /* NOT MATERIALIZED */ +} CTEMaterialize; + +typedef struct CTESearchClause +{ + NodeTag type; + List *search_col_list; + bool search_breadth_first; + char *search_seq_column; + int location; +} CTESearchClause; + +typedef struct CTECycleClause +{ + NodeTag type; + List *cycle_col_list; + char *cycle_mark_column; + Node *cycle_mark_value; + Node *cycle_mark_default; + char *cycle_path_column; + int location; + /* These fields are set during parse analysis: */ + Oid cycle_mark_type; /* common type of _value and _default */ + int cycle_mark_typmod; + Oid cycle_mark_collation; + Oid cycle_mark_neop; /* <> operator for type */ +} CTECycleClause; + +typedef struct CommonTableExpr +{ + NodeTag type; + char *ctename; /* query name (never qualified) */ + List *aliascolnames; /* optional list of column names */ + CTEMaterialize ctematerialized; /* is this an optimization fence? */ + /* SelectStmt/InsertStmt/etc before parse analysis, Query afterwards: */ + Node *ctequery; /* the CTE's subquery */ + CTESearchClause *search_clause; + CTECycleClause *cycle_clause; + int location; /* token location, or -1 if unknown */ + /* These fields are set during parse analysis: */ + bool cterecursive; /* is this CTE actually recursive? */ + int cterefcount; /* number of RTEs referencing this CTE + * (excluding internal self-references) */ + List *ctecolnames; /* list of output column names */ + List *ctecoltypes; /* OID list of output column type OIDs */ + List *ctecoltypmods; /* integer list of output column typmods */ + List *ctecolcollations; /* OID list of column collation OIDs */ +} CommonTableExpr; + +/* Convenience macro to get the output tlist of a CTE's query */ +#define GetCTETargetList(cte) \ + (AssertMacro(IsA((cte)->ctequery, Query)), \ + ((Query *) (cte)->ctequery)->commandType == CMD_SELECT ? \ + ((Query *) (cte)->ctequery)->targetList : \ + ((Query *) (cte)->ctequery)->returningList) + +/* + * MergeWhenClause - + * raw parser representation of a WHEN clause in a MERGE statement + * + * This is transformed into MergeAction by parse analysis + */ +typedef struct MergeWhenClause +{ + NodeTag type; + bool matched; /* true=MATCHED, false=NOT MATCHED */ + CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */ + OverridingKind override; /* OVERRIDING clause */ + Node *condition; /* WHEN conditions (raw parser) */ + List *targetList; /* INSERT/UPDATE targetlist */ + /* the following members are only used in INSERT actions */ + List *values; /* VALUES to INSERT, or NULL */ +} MergeWhenClause; + +/* + * MergeAction - + * Transformed representation of a WHEN clause in a MERGE statement + */ +typedef struct MergeAction +{ + NodeTag type; + bool matched; /* true=MATCHED, false=NOT MATCHED */ + CmdType commandType; /* INSERT/UPDATE/DELETE/DO NOTHING */ + OverridingKind override; /* OVERRIDING clause */ + Node *qual; /* transformed WHEN conditions */ + List *targetList; /* the target list (of TargetEntry) */ + List *updateColnos; /* target attribute numbers of an UPDATE */ +} MergeAction; + +/* + * TriggerTransition - + * representation of transition row or table naming clause + * + * Only transition tables are initially supported in the syntax, and only for + * AFTER triggers, but other permutations are accepted by the parser so we can + * give a meaningful message from C code. + */ +typedef struct TriggerTransition +{ + NodeTag type; + char *name; + bool isNew; + bool isTable; +} TriggerTransition; + +/***************************************************************************** + * Raw Grammar Output Statements + *****************************************************************************/ + +/* + * RawStmt --- container for any one statement's raw parse tree + * + * Parse analysis converts a raw parse tree headed by a RawStmt node into + * an analyzed statement headed by a Query node. For optimizable statements, + * the conversion is complex. For utility statements, the parser usually just + * transfers the raw parse tree (sans RawStmt) into the utilityStmt field of + * the Query node, and all the useful work happens at execution time. + * + * stmt_location/stmt_len identify the portion of the source text string + * containing this raw statement (useful for multi-statement strings). + */ +typedef struct RawStmt +{ + NodeTag type; + Node *stmt; /* raw parse tree */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ +} RawStmt; + +/***************************************************************************** + * Optimizable Statements + *****************************************************************************/ + +/* ---------------------- + * Insert Statement + * + * The source expression is represented by SelectStmt for both the + * SELECT and VALUES cases. If selectStmt is NULL, then the query + * is INSERT ... DEFAULT VALUES. + * ---------------------- + */ +typedef struct InsertStmt +{ + NodeTag type; + RangeVar *relation; /* relation to insert into */ + List *cols; /* optional: names of the target columns */ + Node *selectStmt; /* the source SELECT/VALUES, or NULL */ + OnConflictClause *onConflictClause; /* ON CONFLICT clause */ + List *returningList; /* list of expressions to return */ + WithClause *withClause; /* WITH clause */ + OverridingKind override; /* OVERRIDING clause */ +} InsertStmt; + +/* ---------------------- + * Delete Statement + * ---------------------- + */ +typedef struct DeleteStmt +{ + NodeTag type; + RangeVar *relation; /* relation to delete from */ + List *usingClause; /* optional using clause for more tables */ + Node *whereClause; /* qualifications */ + List *returningList; /* list of expressions to return */ + WithClause *withClause; /* WITH clause */ +} DeleteStmt; + +/* ---------------------- + * Update Statement + * ---------------------- + */ +typedef struct UpdateStmt +{ + NodeTag type; + RangeVar *relation; /* relation to update */ + List *targetList; /* the target list (of ResTarget) */ + Node *whereClause; /* qualifications */ + List *fromClause; /* optional from clause for more tables */ + List *returningList; /* list of expressions to return */ + WithClause *withClause; /* WITH clause */ +} UpdateStmt; + +/* ---------------------- + * Merge Statement + * ---------------------- + */ +typedef struct MergeStmt +{ + NodeTag type; + RangeVar *relation; /* target relation to merge into */ + Node *sourceRelation; /* source relation */ + Node *joinCondition; /* join condition between source and target */ + List *mergeWhenClauses; /* list of MergeWhenClause(es) */ + WithClause *withClause; /* WITH clause */ +} MergeStmt; + +/* ---------------------- + * Select Statement + * + * A "simple" SELECT is represented in the output of gram.y by a single + * SelectStmt node; so is a VALUES construct. A query containing set + * operators (UNION, INTERSECT, EXCEPT) is represented by a tree of SelectStmt + * nodes, in which the leaf nodes are component SELECTs and the internal nodes + * represent UNION, INTERSECT, or EXCEPT operators. Using the same node + * type for both leaf and internal nodes allows gram.y to stick ORDER BY, + * LIMIT, etc, clause values into a SELECT statement without worrying + * whether it is a simple or compound SELECT. + * ---------------------- + */ +typedef enum SetOperation +{ + SETOP_NONE = 0, + SETOP_UNION, + SETOP_INTERSECT, + SETOP_EXCEPT +} SetOperation; + +typedef struct SelectStmt +{ + NodeTag type; + + /* + * These fields are used only in "leaf" SelectStmts. + */ + List *distinctClause; /* NULL, list of DISTINCT ON exprs, or + * lcons(NIL,NIL) for all (SELECT DISTINCT) */ + IntoClause *intoClause; /* target for SELECT INTO */ + List *targetList; /* the target list (of ResTarget) */ + List *fromClause; /* the FROM clause */ + Node *whereClause; /* WHERE qualification */ + List *groupClause; /* GROUP BY clauses */ + bool groupDistinct; /* Is this GROUP BY DISTINCT? */ + Node *havingClause; /* HAVING conditional-expression */ + List *windowClause; /* WINDOW window_name AS (...), ... */ + + /* + * In a "leaf" node representing a VALUES list, the above fields are all + * null, and instead this field is set. Note that the elements of the + * sublists are just expressions, without ResTarget decoration. Also note + * that a list element can be DEFAULT (represented as a SetToDefault + * node), regardless of the context of the VALUES list. It's up to parse + * analysis to reject that where not valid. + */ + List *valuesLists; /* untransformed list of expression lists */ + + /* + * These fields are used in both "leaf" SelectStmts and upper-level + * SelectStmts. + */ + List *sortClause; /* sort clause (a list of SortBy's) */ + Node *limitOffset; /* # of result tuples to skip */ + Node *limitCount; /* # of result tuples to return */ + LimitOption limitOption; /* limit type */ + List *lockingClause; /* FOR UPDATE (list of LockingClause's) */ + WithClause *withClause; /* WITH clause */ + + /* + * These fields are used only in upper-level SelectStmts. + */ + SetOperation op; /* type of set op */ + bool all; /* ALL specified? */ + struct SelectStmt *larg; /* left child */ + struct SelectStmt *rarg; /* right child */ + /* Eventually add fields for CORRESPONDING spec here */ +} SelectStmt; + + +/* ---------------------- + * Set Operation node for post-analysis query trees + * + * After parse analysis, a SELECT with set operations is represented by a + * top-level Query node containing the leaf SELECTs as subqueries in its + * range table. Its setOperations field shows the tree of set operations, + * with leaf SelectStmt nodes replaced by RangeTblRef nodes, and internal + * nodes replaced by SetOperationStmt nodes. Information about the output + * column types is added, too. (Note that the child nodes do not necessarily + * produce these types directly, but we've checked that their output types + * can be coerced to the output column type.) Also, if it's not UNION ALL, + * information about the types' sort/group semantics is provided in the form + * of a SortGroupClause list (same representation as, eg, DISTINCT). + * The resolved common column collations are provided too; but note that if + * it's not UNION ALL, it's okay for a column to not have a common collation, + * so a member of the colCollations list could be InvalidOid even though the + * column has a collatable type. + * ---------------------- + */ +typedef struct SetOperationStmt +{ + NodeTag type; + SetOperation op; /* type of set op */ + bool all; /* ALL specified? */ + Node *larg; /* left child */ + Node *rarg; /* right child */ + /* Eventually add fields for CORRESPONDING spec here */ + + /* Fields derived during parse analysis: */ + List *colTypes; /* OID list of output column type OIDs */ + List *colTypmods; /* integer list of output column typmods */ + List *colCollations; /* OID list of output column collation OIDs */ + List *groupClauses; /* a list of SortGroupClause's */ + /* groupClauses is NIL if UNION ALL, but must be set otherwise */ +} SetOperationStmt; + + +/* + * RETURN statement (inside SQL function body) + */ +typedef struct ReturnStmt +{ + NodeTag type; + Node *returnval; +} ReturnStmt; + + +/* ---------------------- + * PL/pgSQL Assignment Statement + * + * Like SelectStmt, this is transformed into a SELECT Query. + * However, the targetlist of the result looks more like an UPDATE. + * ---------------------- + */ +typedef struct PLAssignStmt +{ + NodeTag type; + + char *name; /* initial column name */ + List *indirection; /* subscripts and field names, if any */ + int nnames; /* number of names to use in ColumnRef */ + SelectStmt *val; /* the PL/pgSQL expression to assign */ + int location; /* name's token location, or -1 if unknown */ +} PLAssignStmt; + + +/***************************************************************************** + * Other Statements (no optimizations required) + * + * These are not touched by parser/analyze.c except to put them into + * the utilityStmt field of a Query. This is eventually passed to + * ProcessUtility (by-passing rewriting and planning). Some of the + * statements do need attention from parse analysis, and this is + * done by routines in parser/parse_utilcmd.c after ProcessUtility + * receives the command for execution. + * DECLARE CURSOR, EXPLAIN, and CREATE TABLE AS are special cases: + * they contain optimizable statements, which get processed normally + * by parser/analyze.c. + *****************************************************************************/ + +/* + * When a command can act on several kinds of objects with only one + * parse structure required, use these constants to designate the + * object type. Note that commands typically don't support all the types. + */ + +typedef enum ObjectType +{ + OBJECT_ACCESS_METHOD, + OBJECT_AGGREGATE, + OBJECT_AMOP, + OBJECT_AMPROC, + OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */ + OBJECT_CAST, + OBJECT_COLUMN, + OBJECT_COLLATION, + OBJECT_CONVERSION, + OBJECT_DATABASE, + OBJECT_DEFAULT, + OBJECT_DEFACL, + OBJECT_DOMAIN, + OBJECT_DOMCONSTRAINT, + OBJECT_EVENT_TRIGGER, + OBJECT_EXTENSION, + OBJECT_FDW, + OBJECT_FOREIGN_SERVER, + OBJECT_FOREIGN_TABLE, + OBJECT_FUNCTION, + OBJECT_INDEX, + OBJECT_LANGUAGE, + OBJECT_LARGEOBJECT, + OBJECT_MATVIEW, + OBJECT_OPCLASS, + OBJECT_OPERATOR, + OBJECT_OPFAMILY, + OBJECT_PARAMETER_ACL, + OBJECT_POLICY, + OBJECT_PROCEDURE, + OBJECT_PUBLICATION, + OBJECT_PUBLICATION_NAMESPACE, + OBJECT_PUBLICATION_REL, + OBJECT_ROLE, + OBJECT_ROUTINE, + OBJECT_RULE, + OBJECT_SCHEMA, + OBJECT_SEQUENCE, + OBJECT_SUBSCRIPTION, + OBJECT_STATISTIC_EXT, + OBJECT_TABCONSTRAINT, + OBJECT_TABLE, + OBJECT_TABLESPACE, + OBJECT_TRANSFORM, + OBJECT_TRIGGER, + OBJECT_TSCONFIGURATION, + OBJECT_TSDICTIONARY, + OBJECT_TSPARSER, + OBJECT_TSTEMPLATE, + OBJECT_TYPE, + OBJECT_USER_MAPPING, + OBJECT_VIEW +} ObjectType; + +/* ---------------------- + * Create Schema Statement + * + * NOTE: the schemaElts list contains raw parsetrees for component statements + * of the schema, such as CREATE TABLE, GRANT, etc. These are analyzed and + * executed after the schema itself is created. + * ---------------------- + */ +typedef struct CreateSchemaStmt +{ + NodeTag type; + char *schemaname; /* the name of the schema to create */ + RoleSpec *authrole; /* the owner of the created schema */ + List *schemaElts; /* schema components (list of parsenodes) */ + bool if_not_exists; /* just do nothing if schema already exists? */ +} CreateSchemaStmt; + +typedef enum DropBehavior +{ + DROP_RESTRICT, /* drop fails if any dependent objects */ + DROP_CASCADE /* remove dependent objects too */ +} DropBehavior; + +/* ---------------------- + * Alter Table + * ---------------------- + */ +typedef struct AlterTableStmt +{ + NodeTag type; + RangeVar *relation; /* table to work on */ + List *cmds; /* list of subcommands */ + ObjectType objtype; /* type of object */ + bool missing_ok; /* skip error if table missing */ +} AlterTableStmt; + +typedef enum AlterTableType +{ + AT_AddColumn, /* add column */ + AT_AddColumnRecurse, /* internal to commands/tablecmds.c */ + AT_AddColumnToView, /* implicitly via CREATE OR REPLACE VIEW */ + AT_ColumnDefault, /* alter column default */ + AT_CookedColumnDefault, /* add a pre-cooked column default */ + AT_DropNotNull, /* alter column drop not null */ + AT_SetNotNull, /* alter column set not null */ + AT_DropExpression, /* alter column drop expression */ + AT_CheckNotNull, /* check column is already marked not null */ + AT_SetStatistics, /* alter column set statistics */ + AT_SetOptions, /* alter column set ( options ) */ + AT_ResetOptions, /* alter column reset ( options ) */ + AT_SetStorage, /* alter column set storage */ + AT_SetCompression, /* alter column set compression */ + AT_DropColumn, /* drop column */ + AT_DropColumnRecurse, /* internal to commands/tablecmds.c */ + AT_AddIndex, /* add index */ + AT_ReAddIndex, /* internal to commands/tablecmds.c */ + AT_AddConstraint, /* add constraint */ + AT_AddConstraintRecurse, /* internal to commands/tablecmds.c */ + AT_ReAddConstraint, /* internal to commands/tablecmds.c */ + AT_ReAddDomainConstraint, /* internal to commands/tablecmds.c */ + AT_AlterConstraint, /* alter constraint */ + AT_ValidateConstraint, /* validate constraint */ + AT_ValidateConstraintRecurse, /* internal to commands/tablecmds.c */ + AT_AddIndexConstraint, /* add constraint using existing index */ + AT_DropConstraint, /* drop constraint */ + AT_DropConstraintRecurse, /* internal to commands/tablecmds.c */ + AT_ReAddComment, /* internal to commands/tablecmds.c */ + AT_AlterColumnType, /* alter column type */ + AT_AlterColumnGenericOptions, /* alter column OPTIONS (...) */ + AT_ChangeOwner, /* change owner */ + AT_ClusterOn, /* CLUSTER ON */ + AT_DropCluster, /* SET WITHOUT CLUSTER */ + AT_SetLogged, /* SET LOGGED */ + AT_SetUnLogged, /* SET UNLOGGED */ + AT_DropOids, /* SET WITHOUT OIDS */ + AT_SetAccessMethod, /* SET ACCESS METHOD */ + AT_SetTableSpace, /* SET TABLESPACE */ + AT_SetRelOptions, /* SET (...) -- AM specific parameters */ + AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */ + AT_ReplaceRelOptions, /* replace reloption list in its entirety */ + AT_EnableTrig, /* ENABLE TRIGGER name */ + AT_EnableAlwaysTrig, /* ENABLE ALWAYS TRIGGER name */ + AT_EnableReplicaTrig, /* ENABLE REPLICA TRIGGER name */ + AT_DisableTrig, /* DISABLE TRIGGER name */ + AT_EnableTrigAll, /* ENABLE TRIGGER ALL */ + AT_DisableTrigAll, /* DISABLE TRIGGER ALL */ + AT_EnableTrigUser, /* ENABLE TRIGGER USER */ + AT_DisableTrigUser, /* DISABLE TRIGGER USER */ + AT_EnableRule, /* ENABLE RULE name */ + AT_EnableAlwaysRule, /* ENABLE ALWAYS RULE name */ + AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */ + AT_DisableRule, /* DISABLE RULE name */ + AT_AddInherit, /* INHERIT parent */ + AT_DropInherit, /* NO INHERIT parent */ + AT_AddOf, /* OF <type_name> */ + AT_DropOf, /* NOT OF */ + AT_ReplicaIdentity, /* REPLICA IDENTITY */ + AT_EnableRowSecurity, /* ENABLE ROW SECURITY */ + AT_DisableRowSecurity, /* DISABLE ROW SECURITY */ + AT_ForceRowSecurity, /* FORCE ROW SECURITY */ + AT_NoForceRowSecurity, /* NO FORCE ROW SECURITY */ + AT_GenericOptions, /* OPTIONS (...) */ + AT_AttachPartition, /* ATTACH PARTITION */ + AT_DetachPartition, /* DETACH PARTITION */ + AT_DetachPartitionFinalize, /* DETACH PARTITION FINALIZE */ + AT_AddIdentity, /* ADD IDENTITY */ + AT_SetIdentity, /* SET identity column options */ + AT_DropIdentity, /* DROP IDENTITY */ + AT_ReAddStatistics /* internal to commands/tablecmds.c */ +} AlterTableType; + +typedef struct ReplicaIdentityStmt +{ + NodeTag type; + char identity_type; + char *name; +} ReplicaIdentityStmt; + +typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ +{ + NodeTag type; + AlterTableType subtype; /* Type of table alteration to apply */ + char *name; /* column, constraint, or trigger to act on, + * or tablespace */ + int16 num; /* attribute number for columns referenced by + * number */ + RoleSpec *newowner; + Node *def; /* definition of new column, index, + * constraint, or parent table */ + DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ + bool missing_ok; /* skip error if missing? */ + bool recurse; /* exec-time recursion */ +} AlterTableCmd; + + +/* ---------------------- + * Alter Collation + * ---------------------- + */ +typedef struct AlterCollationStmt +{ + NodeTag type; + List *collname; +} AlterCollationStmt; + + +/* ---------------------- + * Alter Domain + * + * The fields are used in different ways by the different variants of + * this command. + * ---------------------- + */ +typedef struct AlterDomainStmt +{ + NodeTag type; + char subtype; /*------------ + * T = alter column default + * N = alter column drop not null + * O = alter column set not null + * C = add constraint + * X = drop constraint + *------------ + */ + List *typeName; /* domain to work on */ + char *name; /* column or constraint name to act on */ + Node *def; /* definition of default or constraint */ + DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ + bool missing_ok; /* skip error if missing? */ +} AlterDomainStmt; + + +/* ---------------------- + * Grant|Revoke Statement + * ---------------------- + */ +typedef enum GrantTargetType +{ + ACL_TARGET_OBJECT, /* grant on specific named object(s) */ + ACL_TARGET_ALL_IN_SCHEMA, /* grant on all objects in given schema(s) */ + ACL_TARGET_DEFAULTS /* ALTER DEFAULT PRIVILEGES */ +} GrantTargetType; + +typedef struct GrantStmt +{ + NodeTag type; + bool is_grant; /* true = GRANT, false = REVOKE */ + GrantTargetType targtype; /* type of the grant target */ + ObjectType objtype; /* kind of object being operated on */ + List *objects; /* list of RangeVar nodes, ObjectWithArgs + * nodes, or plain names (as String values) */ + List *privileges; /* list of AccessPriv nodes */ + /* privileges == NIL denotes ALL PRIVILEGES */ + List *grantees; /* list of RoleSpec nodes */ + bool grant_option; /* grant or revoke grant option */ + RoleSpec *grantor; + DropBehavior behavior; /* drop behavior (for REVOKE) */ +} GrantStmt; + +/* + * ObjectWithArgs represents a function/procedure/operator name plus parameter + * identification. + * + * objargs includes only the types of the input parameters of the object. + * In some contexts, that will be all we have, and it's enough to look up + * objects according to the traditional Postgres rules (i.e., when only input + * arguments matter). + * + * objfuncargs, if not NIL, carries the full specification of the parameter + * list, including parameter mode annotations. + * + * Some grammar productions can set args_unspecified = true instead of + * providing parameter info. In this case, lookup will succeed only if + * the object name is unique. Note that otherwise, NIL parameter lists + * mean zero arguments. + */ +typedef struct ObjectWithArgs +{ + NodeTag type; + List *objname; /* qualified name of function/operator */ + List *objargs; /* list of Typename nodes (input args only) */ + List *objfuncargs; /* list of FunctionParameter nodes */ + bool args_unspecified; /* argument list was omitted? */ +} ObjectWithArgs; + +/* + * An access privilege, with optional list of column names + * priv_name == NULL denotes ALL PRIVILEGES (only used with a column list) + * cols == NIL denotes "all columns" + * Note that simple "ALL PRIVILEGES" is represented as a NIL list, not + * an AccessPriv with both fields null. + */ +typedef struct AccessPriv +{ + NodeTag type; + char *priv_name; /* string name of privilege */ + List *cols; /* list of String */ +} AccessPriv; + +/* ---------------------- + * Grant/Revoke Role Statement + * + * Note: because of the parsing ambiguity with the GRANT <privileges> + * statement, granted_roles is a list of AccessPriv; the execution code + * should complain if any column lists appear. grantee_roles is a list + * of role names, as String values. + * ---------------------- + */ +typedef struct GrantRoleStmt +{ + NodeTag type; + List *granted_roles; /* list of roles to be granted/revoked */ + List *grantee_roles; /* list of member roles to add/delete */ + bool is_grant; /* true = GRANT, false = REVOKE */ + bool admin_opt; /* with admin option */ + RoleSpec *grantor; /* set grantor to other than current role */ + DropBehavior behavior; /* drop behavior (for REVOKE) */ +} GrantRoleStmt; + +/* ---------------------- + * Alter Default Privileges Statement + * ---------------------- + */ +typedef struct AlterDefaultPrivilegesStmt +{ + NodeTag type; + List *options; /* list of DefElem */ + GrantStmt *action; /* GRANT/REVOKE action (with objects=NIL) */ +} AlterDefaultPrivilegesStmt; + +/* ---------------------- + * Copy Statement + * + * We support "COPY relation FROM file", "COPY relation TO file", and + * "COPY (query) TO file". In any given CopyStmt, exactly one of "relation" + * and "query" must be non-NULL. + * ---------------------- + */ +typedef struct CopyStmt +{ + NodeTag type; + RangeVar *relation; /* the relation to copy */ + Node *query; /* the query (SELECT or DML statement with + * RETURNING) to copy, as a raw parse tree */ + List *attlist; /* List of column names (as Strings), or NIL + * for all columns */ + bool is_from; /* TO or FROM */ + bool is_program; /* is 'filename' a program to popen? */ + char *filename; /* filename, or NULL for STDIN/STDOUT */ + List *options; /* List of DefElem nodes */ + Node *whereClause; /* WHERE condition (or NULL) */ +} CopyStmt; + +/* ---------------------- + * SET Statement (includes RESET) + * + * "SET var TO DEFAULT" and "RESET var" are semantically equivalent, but we + * preserve the distinction in VariableSetKind for CreateCommandTag(). + * ---------------------- + */ +typedef enum VariableSetKind +{ + VAR_SET_VALUE, /* SET var = value */ + VAR_SET_DEFAULT, /* SET var TO DEFAULT */ + VAR_SET_CURRENT, /* SET var FROM CURRENT */ + VAR_SET_MULTI, /* special case for SET TRANSACTION ... */ + VAR_RESET, /* RESET var */ + VAR_RESET_ALL /* RESET ALL */ +} VariableSetKind; + +typedef struct VariableSetStmt +{ + NodeTag type; + VariableSetKind kind; + char *name; /* variable to be set */ + List *args; /* List of A_Const nodes */ + bool is_local; /* SET LOCAL? */ +} VariableSetStmt; + +/* ---------------------- + * Show Statement + * ---------------------- + */ +typedef struct VariableShowStmt +{ + NodeTag type; + char *name; +} VariableShowStmt; + +/* ---------------------- + * Create Table Statement + * + * NOTE: in the raw gram.y output, ColumnDef and Constraint nodes are + * intermixed in tableElts, and constraints is NIL. After parse analysis, + * tableElts contains just ColumnDefs, and constraints contains just + * Constraint nodes (in fact, only CONSTR_CHECK nodes, in the present + * implementation). + * ---------------------- + */ + +typedef struct CreateStmt +{ + NodeTag type; + RangeVar *relation; /* relation to create */ + List *tableElts; /* column definitions (list of ColumnDef) */ + List *inhRelations; /* relations to inherit from (list of + * RangeVar) */ + PartitionBoundSpec *partbound; /* FOR VALUES clause */ + PartitionSpec *partspec; /* PARTITION BY clause */ + TypeName *ofTypename; /* OF typename */ + List *constraints; /* constraints (list of Constraint nodes) */ + List *options; /* options from WITH clause */ + OnCommitAction oncommit; /* what do we do at COMMIT? */ + char *tablespacename; /* table space to use, or NULL */ + char *accessMethod; /* table access method */ + bool if_not_exists; /* just do nothing if it already exists? */ +} CreateStmt; + +/* ---------- + * Definitions for constraints in CreateStmt + * + * Note that column defaults are treated as a type of constraint, + * even though that's a bit odd semantically. + * + * For constraints that use expressions (CONSTR_CHECK, CONSTR_DEFAULT) + * we may have the expression in either "raw" form (an untransformed + * parse tree) or "cooked" form (the nodeToString representation of + * an executable expression tree), depending on how this Constraint + * node was created (by parsing, or by inheritance from an existing + * relation). We should never have both in the same node! + * + * FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype + * and pg_constraint.confdeltype columns; FKCONSTR_MATCH_xxx values are + * stored into pg_constraint.confmatchtype. Changing the code values may + * require an initdb! + * + * If skip_validation is true then we skip checking that the existing rows + * in the table satisfy the constraint, and just install the catalog entries + * for the constraint. A new FK constraint is marked as valid iff + * initially_valid is true. (Usually skip_validation and initially_valid + * are inverses, but we can set both true if the table is known empty.) + * + * Constraint attributes (DEFERRABLE etc) are initially represented as + * separate Constraint nodes for simplicity of parsing. parse_utilcmd.c makes + * a pass through the constraints list to insert the info into the appropriate + * Constraint node. + * ---------- + */ + +typedef enum ConstrType /* types of constraints */ +{ + CONSTR_NULL, /* not standard SQL, but a lot of people + * expect it */ + CONSTR_NOTNULL, + CONSTR_DEFAULT, + CONSTR_IDENTITY, + CONSTR_GENERATED, + CONSTR_CHECK, + CONSTR_PRIMARY, + CONSTR_UNIQUE, + CONSTR_EXCLUSION, + CONSTR_FOREIGN, + CONSTR_ATTR_DEFERRABLE, /* attributes for previous constraint node */ + CONSTR_ATTR_NOT_DEFERRABLE, + CONSTR_ATTR_DEFERRED, + CONSTR_ATTR_IMMEDIATE +} ConstrType; + +/* Foreign key action codes */ +#define FKCONSTR_ACTION_NOACTION 'a' +#define FKCONSTR_ACTION_RESTRICT 'r' +#define FKCONSTR_ACTION_CASCADE 'c' +#define FKCONSTR_ACTION_SETNULL 'n' +#define FKCONSTR_ACTION_SETDEFAULT 'd' + +/* Foreign key matchtype codes */ +#define FKCONSTR_MATCH_FULL 'f' +#define FKCONSTR_MATCH_PARTIAL 'p' +#define FKCONSTR_MATCH_SIMPLE 's' + +typedef struct Constraint +{ + NodeTag type; + ConstrType contype; /* see above */ + + /* Fields used for most/all constraint types: */ + char *conname; /* Constraint name, or NULL if unnamed */ + bool deferrable; /* DEFERRABLE? */ + bool initdeferred; /* INITIALLY DEFERRED? */ + int location; /* token location, or -1 if unknown */ + + /* Fields used for constraints with expressions (CHECK and DEFAULT): */ + bool is_no_inherit; /* is constraint non-inheritable? */ + Node *raw_expr; /* expr, as untransformed parse tree */ + char *cooked_expr; /* expr, as nodeToString representation */ + char generated_when; /* ALWAYS or BY DEFAULT */ + + /* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */ + bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ + List *keys; /* String nodes naming referenced key + * column(s) */ + List *including; /* String nodes naming referenced nonkey + * column(s) */ + + /* Fields used for EXCLUSION constraints: */ + List *exclusions; /* list of (IndexElem, operator name) pairs */ + + /* Fields used for index constraints (UNIQUE, PRIMARY KEY, EXCLUSION): */ + List *options; /* options from WITH clause */ + char *indexname; /* existing index to use; otherwise NULL */ + char *indexspace; /* index tablespace; NULL for default */ + bool reset_default_tblspc; /* reset default_tablespace prior to + * creating the index */ + /* These could be, but currently are not, used for UNIQUE/PKEY: */ + char *access_method; /* index access method; NULL for default */ + Node *where_clause; /* partial index predicate */ + + /* Fields used for FOREIGN KEY constraints: */ + RangeVar *pktable; /* Primary key table */ + List *fk_attrs; /* Attributes of foreign key */ + List *pk_attrs; /* Corresponding attrs in PK table */ + char fk_matchtype; /* FULL, PARTIAL, SIMPLE */ + char fk_upd_action; /* ON UPDATE action */ + char fk_del_action; /* ON DELETE action */ + List *fk_del_set_cols; /* ON DELETE SET NULL/DEFAULT (col1, col2) */ + List *old_conpfeqop; /* pg_constraint.conpfeqop of my former self */ + Oid old_pktable_oid; /* pg_constraint.confrelid of my former + * self */ + + /* Fields used for constraints that allow a NOT VALID specification */ + bool skip_validation; /* skip validation of existing rows? */ + bool initially_valid; /* mark the new constraint as valid? */ +} Constraint; + +/* ---------------------- + * Create/Drop Table Space Statements + * ---------------------- + */ + +typedef struct CreateTableSpaceStmt +{ + NodeTag type; + char *tablespacename; + RoleSpec *owner; + char *location; + List *options; +} CreateTableSpaceStmt; + +typedef struct DropTableSpaceStmt +{ + NodeTag type; + char *tablespacename; + bool missing_ok; /* skip error if missing? */ +} DropTableSpaceStmt; + +typedef struct AlterTableSpaceOptionsStmt +{ + NodeTag type; + char *tablespacename; + List *options; + bool isReset; +} AlterTableSpaceOptionsStmt; + +typedef struct AlterTableMoveAllStmt +{ + NodeTag type; + char *orig_tablespacename; + ObjectType objtype; /* Object type to move */ + List *roles; /* List of roles to move objects of */ + char *new_tablespacename; + bool nowait; +} AlterTableMoveAllStmt; + +/* ---------------------- + * Create/Alter Extension Statements + * ---------------------- + */ + +typedef struct CreateExtensionStmt +{ + NodeTag type; + char *extname; + bool if_not_exists; /* just do nothing if it already exists? */ + List *options; /* List of DefElem nodes */ +} CreateExtensionStmt; + +/* Only used for ALTER EXTENSION UPDATE; later might need an action field */ +typedef struct AlterExtensionStmt +{ + NodeTag type; + char *extname; + List *options; /* List of DefElem nodes */ +} AlterExtensionStmt; + +typedef struct AlterExtensionContentsStmt +{ + NodeTag type; + char *extname; /* Extension's name */ + int action; /* +1 = add object, -1 = drop object */ + ObjectType objtype; /* Object's type */ + Node *object; /* Qualified name of the object */ +} AlterExtensionContentsStmt; + +/* ---------------------- + * Create/Alter FOREIGN DATA WRAPPER Statements + * ---------------------- + */ + +typedef struct CreateFdwStmt +{ + NodeTag type; + char *fdwname; /* foreign-data wrapper name */ + List *func_options; /* HANDLER/VALIDATOR options */ + List *options; /* generic options to FDW */ +} CreateFdwStmt; + +typedef struct AlterFdwStmt +{ + NodeTag type; + char *fdwname; /* foreign-data wrapper name */ + List *func_options; /* HANDLER/VALIDATOR options */ + List *options; /* generic options to FDW */ +} AlterFdwStmt; + +/* ---------------------- + * Create/Alter FOREIGN SERVER Statements + * ---------------------- + */ + +typedef struct CreateForeignServerStmt +{ + NodeTag type; + char *servername; /* server name */ + char *servertype; /* optional server type */ + char *version; /* optional server version */ + char *fdwname; /* FDW name */ + bool if_not_exists; /* just do nothing if it already exists? */ + List *options; /* generic options to server */ +} CreateForeignServerStmt; + +typedef struct AlterForeignServerStmt +{ + NodeTag type; + char *servername; /* server name */ + char *version; /* optional server version */ + List *options; /* generic options to server */ + bool has_version; /* version specified */ +} AlterForeignServerStmt; + +/* ---------------------- + * Create FOREIGN TABLE Statement + * ---------------------- + */ + +typedef struct CreateForeignTableStmt +{ + CreateStmt base; + char *servername; + List *options; +} CreateForeignTableStmt; + +/* ---------------------- + * Create/Drop USER MAPPING Statements + * ---------------------- + */ + +typedef struct CreateUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + bool if_not_exists; /* just do nothing if it already exists? */ + List *options; /* generic options to server */ +} CreateUserMappingStmt; + +typedef struct AlterUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + List *options; /* generic options to server */ +} AlterUserMappingStmt; + +typedef struct DropUserMappingStmt +{ + NodeTag type; + RoleSpec *user; /* user role */ + char *servername; /* server name */ + bool missing_ok; /* ignore missing mappings */ +} DropUserMappingStmt; + +/* ---------------------- + * Import Foreign Schema Statement + * ---------------------- + */ + +typedef enum ImportForeignSchemaType +{ + FDW_IMPORT_SCHEMA_ALL, /* all relations wanted */ + FDW_IMPORT_SCHEMA_LIMIT_TO, /* include only listed tables in import */ + FDW_IMPORT_SCHEMA_EXCEPT /* exclude listed tables from import */ +} ImportForeignSchemaType; + +typedef struct ImportForeignSchemaStmt +{ + NodeTag type; + char *server_name; /* FDW server name */ + char *remote_schema; /* remote schema name to query */ + char *local_schema; /* local schema to create objects in */ + ImportForeignSchemaType list_type; /* type of table list */ + List *table_list; /* List of RangeVar */ + List *options; /* list of options to pass to FDW */ +} ImportForeignSchemaStmt; + +/*---------------------- + * Create POLICY Statement + *---------------------- + */ +typedef struct CreatePolicyStmt +{ + NodeTag type; + char *policy_name; /* Policy's name */ + RangeVar *table; /* the table name the policy applies to */ + char *cmd_name; /* the command name the policy applies to */ + bool permissive; /* restrictive or permissive policy */ + List *roles; /* the roles associated with the policy */ + Node *qual; /* the policy's condition */ + Node *with_check; /* the policy's WITH CHECK condition. */ +} CreatePolicyStmt; + +/*---------------------- + * Alter POLICY Statement + *---------------------- + */ +typedef struct AlterPolicyStmt +{ + NodeTag type; + char *policy_name; /* Policy's name */ + RangeVar *table; /* the table name the policy applies to */ + List *roles; /* the roles associated with the policy */ + Node *qual; /* the policy's condition */ + Node *with_check; /* the policy's WITH CHECK condition. */ +} AlterPolicyStmt; + +/*---------------------- + * Create ACCESS METHOD Statement + *---------------------- + */ +typedef struct CreateAmStmt +{ + NodeTag type; + char *amname; /* access method name */ + List *handler_name; /* handler function name */ + char amtype; /* type of access method */ +} CreateAmStmt; + +/* ---------------------- + * Create TRIGGER Statement + * ---------------------- + */ +typedef struct CreateTrigStmt +{ + NodeTag type; + bool replace; /* replace trigger if already exists */ + bool isconstraint; /* This is a constraint trigger */ + char *trigname; /* TRIGGER's name */ + RangeVar *relation; /* relation trigger is on */ + List *funcname; /* qual. name of function to call */ + List *args; /* list of String or NIL */ + bool row; /* ROW/STATEMENT */ + /* timing uses the TRIGGER_TYPE bits defined in catalog/pg_trigger.h */ + int16 timing; /* BEFORE, AFTER, or INSTEAD */ + /* events uses the TRIGGER_TYPE bits defined in catalog/pg_trigger.h */ + int16 events; /* "OR" of INSERT/UPDATE/DELETE/TRUNCATE */ + List *columns; /* column names, or NIL for all columns */ + Node *whenClause; /* qual expression, or NULL if none */ + /* explicitly named transition data */ + List *transitionRels; /* TriggerTransition nodes, or NIL if none */ + /* The remaining fields are only used for constraint triggers */ + bool deferrable; /* [NOT] DEFERRABLE */ + bool initdeferred; /* INITIALLY {DEFERRED|IMMEDIATE} */ + RangeVar *constrrel; /* opposite relation, if RI trigger */ +} CreateTrigStmt; + +/* ---------------------- + * Create EVENT TRIGGER Statement + * ---------------------- + */ +typedef struct CreateEventTrigStmt +{ + NodeTag type; + char *trigname; /* TRIGGER's name */ + char *eventname; /* event's identifier */ + List *whenclause; /* list of DefElems indicating filtering */ + List *funcname; /* qual. name of function to call */ +} CreateEventTrigStmt; + +/* ---------------------- + * Alter EVENT TRIGGER Statement + * ---------------------- + */ +typedef struct AlterEventTrigStmt +{ + NodeTag type; + char *trigname; /* TRIGGER's name */ + char tgenabled; /* trigger's firing configuration WRT + * session_replication_role */ +} AlterEventTrigStmt; + +/* ---------------------- + * Create LANGUAGE Statements + * ---------------------- + */ +typedef struct CreatePLangStmt +{ + NodeTag type; + bool replace; /* T => replace if already exists */ + char *plname; /* PL name */ + List *plhandler; /* PL call handler function (qual. name) */ + List *plinline; /* optional inline function (qual. name) */ + List *plvalidator; /* optional validator function (qual. name) */ + bool pltrusted; /* PL is trusted */ +} CreatePLangStmt; + +/* ---------------------- + * Create/Alter/Drop Role Statements + * + * Note: these node types are also used for the backwards-compatible + * Create/Alter/Drop User/Group statements. In the ALTER and DROP cases + * there's really no need to distinguish what the original spelling was, + * but for CREATE we mark the type because the defaults vary. + * ---------------------- + */ +typedef enum RoleStmtType +{ + ROLESTMT_ROLE, + ROLESTMT_USER, + ROLESTMT_GROUP +} RoleStmtType; + +typedef struct CreateRoleStmt +{ + NodeTag type; + RoleStmtType stmt_type; /* ROLE/USER/GROUP */ + char *role; /* role name */ + List *options; /* List of DefElem nodes */ +} CreateRoleStmt; + +typedef struct AlterRoleStmt +{ + NodeTag type; + RoleSpec *role; /* role */ + List *options; /* List of DefElem nodes */ + int action; /* +1 = add members, -1 = drop members */ +} AlterRoleStmt; + +typedef struct AlterRoleSetStmt +{ + NodeTag type; + RoleSpec *role; /* role */ + char *database; /* database name, or NULL */ + VariableSetStmt *setstmt; /* SET or RESET subcommand */ +} AlterRoleSetStmt; + +typedef struct DropRoleStmt +{ + NodeTag type; + List *roles; /* List of roles to remove */ + bool missing_ok; /* skip error if a role is missing? */ +} DropRoleStmt; + +/* ---------------------- + * {Create|Alter} SEQUENCE Statement + * ---------------------- + */ + +typedef struct CreateSeqStmt +{ + NodeTag type; + RangeVar *sequence; /* the sequence to create */ + List *options; + Oid ownerId; /* ID of owner, or InvalidOid for default */ + bool for_identity; + bool if_not_exists; /* just do nothing if it already exists? */ +} CreateSeqStmt; + +typedef struct AlterSeqStmt +{ + NodeTag type; + RangeVar *sequence; /* the sequence to alter */ + List *options; + bool for_identity; + bool missing_ok; /* skip error if a role is missing? */ +} AlterSeqStmt; + +/* ---------------------- + * Create {Aggregate|Operator|Type} Statement + * ---------------------- + */ +typedef struct DefineStmt +{ + NodeTag type; + ObjectType kind; /* aggregate, operator, type */ + bool oldstyle; /* hack to signal old CREATE AGG syntax */ + List *defnames; /* qualified name (list of String) */ + List *args; /* a list of TypeName (if needed) */ + List *definition; /* a list of DefElem */ + bool if_not_exists; /* just do nothing if it already exists? */ + bool replace; /* replace if already exists? */ +} DefineStmt; + +/* ---------------------- + * Create Domain Statement + * ---------------------- + */ +typedef struct CreateDomainStmt +{ + NodeTag type; + List *domainname; /* qualified name (list of String) */ + TypeName *typeName; /* the base type */ + CollateClause *collClause; /* untransformed COLLATE spec, if any */ + List *constraints; /* constraints (list of Constraint nodes) */ +} CreateDomainStmt; + +/* ---------------------- + * Create Operator Class Statement + * ---------------------- + */ +typedef struct CreateOpClassStmt +{ + NodeTag type; + List *opclassname; /* qualified name (list of String) */ + List *opfamilyname; /* qualified name (ditto); NIL if omitted */ + char *amname; /* name of index AM opclass is for */ + TypeName *datatype; /* datatype of indexed column */ + List *items; /* List of CreateOpClassItem nodes */ + bool isDefault; /* Should be marked as default for type? */ +} CreateOpClassStmt; + +#define OPCLASS_ITEM_OPERATOR 1 +#define OPCLASS_ITEM_FUNCTION 2 +#define OPCLASS_ITEM_STORAGETYPE 3 + +typedef struct CreateOpClassItem +{ + NodeTag type; + int itemtype; /* see codes above */ + ObjectWithArgs *name; /* operator or function name and args */ + int number; /* strategy num or support proc num */ + List *order_family; /* only used for ordering operators */ + List *class_args; /* amproclefttype/amprocrighttype or + * amoplefttype/amoprighttype */ + /* fields used for a storagetype item: */ + TypeName *storedtype; /* datatype stored in index */ +} CreateOpClassItem; + +/* ---------------------- + * Create Operator Family Statement + * ---------------------- + */ +typedef struct CreateOpFamilyStmt +{ + NodeTag type; + List *opfamilyname; /* qualified name (list of String) */ + char *amname; /* name of index AM opfamily is for */ +} CreateOpFamilyStmt; + +/* ---------------------- + * Alter Operator Family Statement + * ---------------------- + */ +typedef struct AlterOpFamilyStmt +{ + NodeTag type; + List *opfamilyname; /* qualified name (list of String) */ + char *amname; /* name of index AM opfamily is for */ + bool isDrop; /* ADD or DROP the items? */ + List *items; /* List of CreateOpClassItem nodes */ +} AlterOpFamilyStmt; + +/* ---------------------- + * Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement + * ---------------------- + */ + +typedef struct DropStmt +{ + NodeTag type; + List *objects; /* list of names */ + ObjectType removeType; /* object type */ + DropBehavior behavior; /* RESTRICT or CASCADE behavior */ + bool missing_ok; /* skip error if object is missing? */ + bool concurrent; /* drop index concurrently? */ +} DropStmt; + +/* ---------------------- + * Truncate Table Statement + * ---------------------- + */ +typedef struct TruncateStmt +{ + NodeTag type; + List *relations; /* relations (RangeVars) to be truncated */ + bool restart_seqs; /* restart owned sequences? */ + DropBehavior behavior; /* RESTRICT or CASCADE behavior */ +} TruncateStmt; + +/* ---------------------- + * Comment On Statement + * ---------------------- + */ +typedef struct CommentStmt +{ + NodeTag type; + ObjectType objtype; /* Object's type */ + Node *object; /* Qualified name of the object */ + char *comment; /* Comment to insert, or NULL to remove */ +} CommentStmt; + +/* ---------------------- + * SECURITY LABEL Statement + * ---------------------- + */ +typedef struct SecLabelStmt +{ + NodeTag type; + ObjectType objtype; /* Object's type */ + Node *object; /* Qualified name of the object */ + char *provider; /* Label provider (or NULL) */ + char *label; /* New security label to be assigned */ +} SecLabelStmt; + +/* ---------------------- + * Declare Cursor Statement + * + * The "query" field is initially a raw parse tree, and is converted to a + * Query node during parse analysis. Note that rewriting and planning + * of the query are always postponed until execution. + * ---------------------- + */ +#define CURSOR_OPT_BINARY 0x0001 /* BINARY */ +#define CURSOR_OPT_SCROLL 0x0002 /* SCROLL explicitly given */ +#define CURSOR_OPT_NO_SCROLL 0x0004 /* NO SCROLL explicitly given */ +#define CURSOR_OPT_INSENSITIVE 0x0008 /* INSENSITIVE */ +#define CURSOR_OPT_ASENSITIVE 0x0010 /* ASENSITIVE */ +#define CURSOR_OPT_HOLD 0x0020 /* WITH HOLD */ +/* these planner-control flags do not correspond to any SQL grammar: */ +#define CURSOR_OPT_FAST_PLAN 0x0100 /* prefer fast-start plan */ +#define CURSOR_OPT_GENERIC_PLAN 0x0200 /* force use of generic plan */ +#define CURSOR_OPT_CUSTOM_PLAN 0x0400 /* force use of custom plan */ +#define CURSOR_OPT_PARALLEL_OK 0x0800 /* parallel mode OK */ + +typedef struct DeclareCursorStmt +{ + NodeTag type; + char *portalname; /* name of the portal (cursor) */ + int options; /* bitmask of options (see above) */ + Node *query; /* the query (see comments above) */ +} DeclareCursorStmt; + +/* ---------------------- + * Close Portal Statement + * ---------------------- + */ +typedef struct ClosePortalStmt +{ + NodeTag type; + char *portalname; /* name of the portal (cursor) */ + /* NULL means CLOSE ALL */ +} ClosePortalStmt; + +/* ---------------------- + * Fetch Statement (also Move) + * ---------------------- + */ +typedef enum FetchDirection +{ + /* for these, howMany is how many rows to fetch; FETCH_ALL means ALL */ + FETCH_FORWARD, + FETCH_BACKWARD, + /* for these, howMany indicates a position; only one row is fetched */ + FETCH_ABSOLUTE, + FETCH_RELATIVE +} FetchDirection; + +#define FETCH_ALL LONG_MAX + +typedef struct FetchStmt +{ + NodeTag type; + FetchDirection direction; /* see above */ + long howMany; /* number of rows, or position argument */ + char *portalname; /* name of portal (cursor) */ + bool ismove; /* true if MOVE */ +} FetchStmt; + +/* ---------------------- + * Create Index Statement + * + * This represents creation of an index and/or an associated constraint. + * If isconstraint is true, we should create a pg_constraint entry along + * with the index. But if indexOid isn't InvalidOid, we are not creating an + * index, just a UNIQUE/PKEY constraint using an existing index. isconstraint + * must always be true in this case, and the fields describing the index + * properties are empty. + * ---------------------- + */ +typedef struct IndexStmt +{ + NodeTag type; + char *idxname; /* name of new index, or NULL for default */ + RangeVar *relation; /* relation to build index on */ + char *accessMethod; /* name of access method (eg. btree) */ + char *tableSpace; /* tablespace, or NULL for default */ + List *indexParams; /* columns to index: a list of IndexElem */ + List *indexIncludingParams; /* additional columns to index: a list + * of IndexElem */ + List *options; /* WITH clause options: a list of DefElem */ + Node *whereClause; /* qualification (partial-index predicate) */ + List *excludeOpNames; /* exclusion operator names, or NIL if none */ + char *idxcomment; /* comment to apply to index, or NULL */ + Oid indexOid; /* OID of an existing index, if any */ + Oid oldNode; /* relfilenode of existing storage, if any */ + SubTransactionId oldCreateSubid; /* rd_createSubid of oldNode */ + SubTransactionId oldFirstRelfilenodeSubid; /* rd_firstRelfilenodeSubid of + * oldNode */ + bool unique; /* is index unique? */ + bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ + bool primary; /* is index a primary key? */ + bool isconstraint; /* is it for a pkey/unique constraint? */ + bool deferrable; /* is the constraint DEFERRABLE? */ + bool initdeferred; /* is the constraint INITIALLY DEFERRED? */ + bool transformed; /* true when transformIndexStmt is finished */ + bool concurrent; /* should this be a concurrent index build? */ + bool if_not_exists; /* just do nothing if index already exists? */ + bool reset_default_tblspc; /* reset default_tablespace prior to + * executing */ +} IndexStmt; + +/* ---------------------- + * Create Statistics Statement + * ---------------------- + */ +typedef struct CreateStatsStmt +{ + NodeTag type; + List *defnames; /* qualified name (list of String) */ + List *stat_types; /* stat types (list of String) */ + List *exprs; /* expressions to build statistics on */ + List *relations; /* rels to build stats on (list of RangeVar) */ + char *stxcomment; /* comment to apply to stats, or NULL */ + bool transformed; /* true when transformStatsStmt is finished */ + bool if_not_exists; /* do nothing if stats name already exists */ +} CreateStatsStmt; + +/* + * StatsElem - statistics parameters (used in CREATE STATISTICS) + * + * For a plain attribute, 'name' is the name of the referenced table column + * and 'expr' is NULL. For an expression, 'name' is NULL and 'expr' is the + * expression tree. + */ +typedef struct StatsElem +{ + NodeTag type; + char *name; /* name of attribute to index, or NULL */ + Node *expr; /* expression to index, or NULL */ +} StatsElem; + + +/* ---------------------- + * Alter Statistics Statement + * ---------------------- + */ +typedef struct AlterStatsStmt +{ + NodeTag type; + List *defnames; /* qualified name (list of String) */ + int stxstattarget; /* statistics target */ + bool missing_ok; /* skip error if statistics object is missing */ +} AlterStatsStmt; + +/* ---------------------- + * Create Function Statement + * ---------------------- + */ +typedef struct CreateFunctionStmt +{ + NodeTag type; + bool is_procedure; /* it's really CREATE PROCEDURE */ + bool replace; /* T => replace if already exists */ + List *funcname; /* qualified name of function to create */ + List *parameters; /* a list of FunctionParameter */ + TypeName *returnType; /* the return type */ + List *options; /* a list of DefElem */ + Node *sql_body; +} CreateFunctionStmt; + +typedef enum FunctionParameterMode +{ + /* the assigned enum values appear in pg_proc, don't change 'em! */ + FUNC_PARAM_IN = 'i', /* input only */ + FUNC_PARAM_OUT = 'o', /* output only */ + FUNC_PARAM_INOUT = 'b', /* both */ + FUNC_PARAM_VARIADIC = 'v', /* variadic (always input) */ + FUNC_PARAM_TABLE = 't', /* table function output column */ + /* this is not used in pg_proc: */ + FUNC_PARAM_DEFAULT = 'd' /* default; effectively same as IN */ +} FunctionParameterMode; + +typedef struct FunctionParameter +{ + NodeTag type; + char *name; /* parameter name, or NULL if not given */ + TypeName *argType; /* TypeName for parameter type */ + FunctionParameterMode mode; /* IN/OUT/etc */ + Node *defexpr; /* raw default expr, or NULL if not given */ +} FunctionParameter; + +typedef struct AlterFunctionStmt +{ + NodeTag type; + ObjectType objtype; + ObjectWithArgs *func; /* name and args of function */ + List *actions; /* list of DefElem */ +} AlterFunctionStmt; + +/* ---------------------- + * DO Statement + * + * DoStmt is the raw parser output, InlineCodeBlock is the execution-time API + * ---------------------- + */ +typedef struct DoStmt +{ + NodeTag type; + List *args; /* List of DefElem nodes */ +} DoStmt; + +typedef struct InlineCodeBlock +{ + NodeTag type; + char *source_text; /* source text of anonymous code block */ + Oid langOid; /* OID of selected language */ + bool langIsTrusted; /* trusted property of the language */ + bool atomic; /* atomic execution context */ +} InlineCodeBlock; + +/* ---------------------- + * CALL statement + * + * OUT-mode arguments are removed from the transformed funcexpr. The outargs + * list contains copies of the expressions for all output arguments, in the + * order of the procedure's declared arguments. (outargs is never evaluated, + * but is useful to the caller as a reference for what to assign to.) + * ---------------------- + */ +typedef struct CallStmt +{ + NodeTag type; + FuncCall *funccall; /* from the parser */ + FuncExpr *funcexpr; /* transformed call, with only input args */ + List *outargs; /* transformed output-argument expressions */ +} CallStmt; + +typedef struct CallContext +{ + NodeTag type; + bool atomic; +} CallContext; + +/* ---------------------- + * Alter Object Rename Statement + * ---------------------- + */ +typedef struct RenameStmt +{ + NodeTag type; + ObjectType renameType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */ + ObjectType relationType; /* if column name, associated relation type */ + RangeVar *relation; /* in case it's a table */ + Node *object; /* in case it's some other object */ + char *subname; /* name of contained object (column, rule, + * trigger, etc) */ + char *newname; /* the new name */ + DropBehavior behavior; /* RESTRICT or CASCADE behavior */ + bool missing_ok; /* skip error if missing? */ +} RenameStmt; + +/* ---------------------- + * ALTER object DEPENDS ON EXTENSION extname + * ---------------------- + */ +typedef struct AlterObjectDependsStmt +{ + NodeTag type; + ObjectType objectType; /* OBJECT_FUNCTION, OBJECT_TRIGGER, etc */ + RangeVar *relation; /* in case a table is involved */ + Node *object; /* name of the object */ + String *extname; /* extension name */ + bool remove; /* set true to remove dep rather than add */ +} AlterObjectDependsStmt; + +/* ---------------------- + * ALTER object SET SCHEMA Statement + * ---------------------- + */ +typedef struct AlterObjectSchemaStmt +{ + NodeTag type; + ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ + RangeVar *relation; /* in case it's a table */ + Node *object; /* in case it's some other object */ + char *newschema; /* the new schema */ + bool missing_ok; /* skip error if missing? */ +} AlterObjectSchemaStmt; + +/* ---------------------- + * Alter Object Owner Statement + * ---------------------- + */ +typedef struct AlterOwnerStmt +{ + NodeTag type; + ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ + RangeVar *relation; /* in case it's a table */ + Node *object; /* in case it's some other object */ + RoleSpec *newowner; /* the new owner */ +} AlterOwnerStmt; + +/* ---------------------- + * Alter Operator Set ( this-n-that ) + * ---------------------- + */ +typedef struct AlterOperatorStmt +{ + NodeTag type; + ObjectWithArgs *opername; /* operator name and argument types */ + List *options; /* List of DefElem nodes */ +} AlterOperatorStmt; + +/* ------------------------ + * Alter Type Set ( this-n-that ) + * ------------------------ + */ +typedef struct AlterTypeStmt +{ + NodeTag type; + List *typeName; /* type name (possibly qualified) */ + List *options; /* List of DefElem nodes */ +} AlterTypeStmt; + +/* ---------------------- + * Create Rule Statement + * ---------------------- + */ +typedef struct RuleStmt +{ + NodeTag type; + RangeVar *relation; /* relation the rule is for */ + char *rulename; /* name of the rule */ + Node *whereClause; /* qualifications */ + CmdType event; /* SELECT, INSERT, etc */ + bool instead; /* is a 'do instead'? */ + List *actions; /* the action statements */ + bool replace; /* OR REPLACE */ +} RuleStmt; + +/* ---------------------- + * Notify Statement + * ---------------------- + */ +typedef struct NotifyStmt +{ + NodeTag type; + char *conditionname; /* condition name to notify */ + char *payload; /* the payload string, or NULL if none */ +} NotifyStmt; + +/* ---------------------- + * Listen Statement + * ---------------------- + */ +typedef struct ListenStmt +{ + NodeTag type; + char *conditionname; /* condition name to listen on */ +} ListenStmt; + +/* ---------------------- + * Unlisten Statement + * ---------------------- + */ +typedef struct UnlistenStmt +{ + NodeTag type; + char *conditionname; /* name to unlisten on, or NULL for all */ +} UnlistenStmt; + +/* ---------------------- + * {Begin|Commit|Rollback} Transaction Statement + * ---------------------- + */ +typedef enum TransactionStmtKind +{ + TRANS_STMT_BEGIN, + TRANS_STMT_START, /* semantically identical to BEGIN */ + TRANS_STMT_COMMIT, + TRANS_STMT_ROLLBACK, + TRANS_STMT_SAVEPOINT, + TRANS_STMT_RELEASE, + TRANS_STMT_ROLLBACK_TO, + TRANS_STMT_PREPARE, + TRANS_STMT_COMMIT_PREPARED, + TRANS_STMT_ROLLBACK_PREPARED +} TransactionStmtKind; + +typedef struct TransactionStmt +{ + NodeTag type; + TransactionStmtKind kind; /* see above */ + List *options; /* for BEGIN/START commands */ + char *savepoint_name; /* for savepoint commands */ + char *gid; /* for two-phase-commit related commands */ + bool chain; /* AND CHAIN option */ +} TransactionStmt; + +/* ---------------------- + * Create Type Statement, composite types + * ---------------------- + */ +typedef struct CompositeTypeStmt +{ + NodeTag type; + RangeVar *typevar; /* the composite type to be created */ + List *coldeflist; /* list of ColumnDef nodes */ +} CompositeTypeStmt; + +/* ---------------------- + * Create Type Statement, enum types + * ---------------------- + */ +typedef struct CreateEnumStmt +{ + NodeTag type; + List *typeName; /* qualified name (list of String) */ + List *vals; /* enum values (list of String) */ +} CreateEnumStmt; + +/* ---------------------- + * Create Type Statement, range types + * ---------------------- + */ +typedef struct CreateRangeStmt +{ + NodeTag type; + List *typeName; /* qualified name (list of String) */ + List *params; /* range parameters (list of DefElem) */ +} CreateRangeStmt; + +/* ---------------------- + * Alter Type Statement, enum types + * ---------------------- + */ +typedef struct AlterEnumStmt +{ + NodeTag type; + List *typeName; /* qualified name (list of String) */ + char *oldVal; /* old enum value's name, if renaming */ + char *newVal; /* new enum value's name */ + char *newValNeighbor; /* neighboring enum value, if specified */ + bool newValIsAfter; /* place new enum value after neighbor? */ + bool skipIfNewValExists; /* no error if new already exists? */ +} AlterEnumStmt; + +/* ---------------------- + * Create View Statement + * ---------------------- + */ +typedef enum ViewCheckOption +{ + NO_CHECK_OPTION, + LOCAL_CHECK_OPTION, + CASCADED_CHECK_OPTION +} ViewCheckOption; + +typedef struct ViewStmt +{ + NodeTag type; + RangeVar *view; /* the view to be created */ + List *aliases; /* target column names */ + Node *query; /* the SELECT query (as a raw parse tree) */ + bool replace; /* replace an existing view? */ + List *options; /* options from WITH clause */ + ViewCheckOption withCheckOption; /* WITH CHECK OPTION */ +} ViewStmt; + +/* ---------------------- + * Load Statement + * ---------------------- + */ +typedef struct LoadStmt +{ + NodeTag type; + char *filename; /* file to load */ +} LoadStmt; + +/* ---------------------- + * Createdb Statement + * ---------------------- + */ +typedef struct CreatedbStmt +{ + NodeTag type; + char *dbname; /* name of database to create */ + List *options; /* List of DefElem nodes */ +} CreatedbStmt; + +/* ---------------------- + * Alter Database + * ---------------------- + */ +typedef struct AlterDatabaseStmt +{ + NodeTag type; + char *dbname; /* name of database to alter */ + List *options; /* List of DefElem nodes */ +} AlterDatabaseStmt; + +typedef struct AlterDatabaseRefreshCollStmt +{ + NodeTag type; + char *dbname; +} AlterDatabaseRefreshCollStmt; + +typedef struct AlterDatabaseSetStmt +{ + NodeTag type; + char *dbname; /* database name */ + VariableSetStmt *setstmt; /* SET or RESET subcommand */ +} AlterDatabaseSetStmt; + +/* ---------------------- + * Dropdb Statement + * ---------------------- + */ +typedef struct DropdbStmt +{ + NodeTag type; + char *dbname; /* database to drop */ + bool missing_ok; /* skip error if db is missing? */ + List *options; /* currently only FORCE is supported */ +} DropdbStmt; + +/* ---------------------- + * Alter System Statement + * ---------------------- + */ +typedef struct AlterSystemStmt +{ + NodeTag type; + VariableSetStmt *setstmt; /* SET subcommand */ +} AlterSystemStmt; + +/* ---------------------- + * Cluster Statement (support pbrown's cluster index implementation) + * ---------------------- + */ +typedef struct ClusterStmt +{ + NodeTag type; + RangeVar *relation; /* relation being indexed, or NULL if all */ + char *indexname; /* original index defined */ + List *params; /* list of DefElem nodes */ +} ClusterStmt; + +/* ---------------------- + * Vacuum and Analyze Statements + * + * Even though these are nominally two statements, it's convenient to use + * just one node type for both. + * ---------------------- + */ +typedef struct VacuumStmt +{ + NodeTag type; + List *options; /* list of DefElem nodes */ + List *rels; /* list of VacuumRelation, or NIL for all */ + bool is_vacuumcmd; /* true for VACUUM, false for ANALYZE */ +} VacuumStmt; + +/* + * Info about a single target table of VACUUM/ANALYZE. + * + * If the OID field is set, it always identifies the table to process. + * Then the relation field can be NULL; if it isn't, it's used only to report + * failure to open/lock the relation. + */ +typedef struct VacuumRelation +{ + NodeTag type; + RangeVar *relation; /* table name to process, or NULL */ + Oid oid; /* table's OID; InvalidOid if not looked up */ + List *va_cols; /* list of column names, or NIL for all */ +} VacuumRelation; + +/* ---------------------- + * Explain Statement + * + * The "query" field is initially a raw parse tree, and is converted to a + * Query node during parse analysis. Note that rewriting and planning + * of the query are always postponed until execution. + * ---------------------- + */ +typedef struct ExplainStmt +{ + NodeTag type; + Node *query; /* the query (see comments above) */ + List *options; /* list of DefElem nodes */ +} ExplainStmt; + +/* ---------------------- + * CREATE TABLE AS Statement (a/k/a SELECT INTO) + * + * A query written as CREATE TABLE AS will produce this node type natively. + * A query written as SELECT ... INTO will be transformed to this form during + * parse analysis. + * A query written as CREATE MATERIALIZED view will produce this node type, + * during parse analysis, since it needs all the same data. + * + * The "query" field is handled similarly to EXPLAIN, though note that it + * can be a SELECT or an EXECUTE, but not other DML statements. + * ---------------------- + */ +typedef struct CreateTableAsStmt +{ + NodeTag type; + Node *query; /* the query (see comments above) */ + IntoClause *into; /* destination table */ + ObjectType objtype; /* OBJECT_TABLE or OBJECT_MATVIEW */ + bool is_select_into; /* it was written as SELECT INTO */ + bool if_not_exists; /* just do nothing if it already exists? */ +} CreateTableAsStmt; + +/* ---------------------- + * REFRESH MATERIALIZED VIEW Statement + * ---------------------- + */ +typedef struct RefreshMatViewStmt +{ + NodeTag type; + bool concurrent; /* allow concurrent access? */ + bool skipData; /* true for WITH NO DATA */ + RangeVar *relation; /* relation to insert into */ +} RefreshMatViewStmt; + +/* ---------------------- + * Checkpoint Statement + * ---------------------- + */ +typedef struct CheckPointStmt +{ + NodeTag type; +} CheckPointStmt; + +/* ---------------------- + * Discard Statement + * ---------------------- + */ + +typedef enum DiscardMode +{ + DISCARD_ALL, + DISCARD_PLANS, + DISCARD_SEQUENCES, + DISCARD_TEMP +} DiscardMode; + +typedef struct DiscardStmt +{ + NodeTag type; + DiscardMode target; +} DiscardStmt; + +/* ---------------------- + * LOCK Statement + * ---------------------- + */ +typedef struct LockStmt +{ + NodeTag type; + List *relations; /* relations to lock */ + int mode; /* lock mode */ + bool nowait; /* no wait mode */ +} LockStmt; + +/* ---------------------- + * SET CONSTRAINTS Statement + * ---------------------- + */ +typedef struct ConstraintsSetStmt +{ + NodeTag type; + List *constraints; /* List of names as RangeVars */ + bool deferred; +} ConstraintsSetStmt; + +/* ---------------------- + * REINDEX Statement + * ---------------------- + */ +typedef enum ReindexObjectType +{ + REINDEX_OBJECT_INDEX, /* index */ + REINDEX_OBJECT_TABLE, /* table or materialized view */ + REINDEX_OBJECT_SCHEMA, /* schema */ + REINDEX_OBJECT_SYSTEM, /* system catalogs */ + REINDEX_OBJECT_DATABASE /* database */ +} ReindexObjectType; + +typedef struct ReindexStmt +{ + NodeTag type; + ReindexObjectType kind; /* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE, + * etc. */ + RangeVar *relation; /* Table or index to reindex */ + const char *name; /* name of database to reindex */ + List *params; /* list of DefElem nodes */ +} ReindexStmt; + +/* ---------------------- + * CREATE CONVERSION Statement + * ---------------------- + */ +typedef struct CreateConversionStmt +{ + NodeTag type; + List *conversion_name; /* Name of the conversion */ + char *for_encoding_name; /* source encoding name */ + char *to_encoding_name; /* destination encoding name */ + List *func_name; /* qualified conversion function name */ + bool def; /* is this a default conversion? */ +} CreateConversionStmt; + +/* ---------------------- + * CREATE CAST Statement + * ---------------------- + */ +typedef struct CreateCastStmt +{ + NodeTag type; + TypeName *sourcetype; + TypeName *targettype; + ObjectWithArgs *func; + CoercionContext context; + bool inout; +} CreateCastStmt; + +/* ---------------------- + * CREATE TRANSFORM Statement + * ---------------------- + */ +typedef struct CreateTransformStmt +{ + NodeTag type; + bool replace; + TypeName *type_name; + char *lang; + ObjectWithArgs *fromsql; + ObjectWithArgs *tosql; +} CreateTransformStmt; + +/* ---------------------- + * PREPARE Statement + * ---------------------- + */ +typedef struct PrepareStmt +{ + NodeTag type; + char *name; /* Name of plan, arbitrary */ + List *argtypes; /* Types of parameters (List of TypeName) */ + Node *query; /* The query itself (as a raw parsetree) */ +} PrepareStmt; + + +/* ---------------------- + * EXECUTE Statement + * ---------------------- + */ + +typedef struct ExecuteStmt +{ + NodeTag type; + char *name; /* The name of the plan to execute */ + List *params; /* Values to assign to parameters */ +} ExecuteStmt; + + +/* ---------------------- + * DEALLOCATE Statement + * ---------------------- + */ +typedef struct DeallocateStmt +{ + NodeTag type; + char *name; /* The name of the plan to remove */ + /* NULL means DEALLOCATE ALL */ +} DeallocateStmt; + +/* + * DROP OWNED statement + */ +typedef struct DropOwnedStmt +{ + NodeTag type; + List *roles; + DropBehavior behavior; +} DropOwnedStmt; + +/* + * REASSIGN OWNED statement + */ +typedef struct ReassignOwnedStmt +{ + NodeTag type; + List *roles; + RoleSpec *newrole; +} ReassignOwnedStmt; + +/* + * TS Dictionary stmts: DefineStmt, RenameStmt and DropStmt are default + */ +typedef struct AlterTSDictionaryStmt +{ + NodeTag type; + List *dictname; /* qualified name (list of String) */ + List *options; /* List of DefElem nodes */ +} AlterTSDictionaryStmt; + +/* + * TS Configuration stmts: DefineStmt, RenameStmt and DropStmt are default + */ +typedef enum AlterTSConfigType +{ + ALTER_TSCONFIG_ADD_MAPPING, + ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN, + ALTER_TSCONFIG_REPLACE_DICT, + ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN, + ALTER_TSCONFIG_DROP_MAPPING +} AlterTSConfigType; + +typedef struct AlterTSConfigurationStmt +{ + NodeTag type; + AlterTSConfigType kind; /* ALTER_TSCONFIG_ADD_MAPPING, etc */ + List *cfgname; /* qualified name (list of String) */ + + /* + * dicts will be non-NIL if ADD/ALTER MAPPING was specified. If dicts is + * NIL, but tokentype isn't, DROP MAPPING was specified. + */ + List *tokentype; /* list of String */ + List *dicts; /* list of list of String */ + bool override; /* if true - remove old variant */ + bool replace; /* if true - replace dictionary by another */ + bool missing_ok; /* for DROP - skip error if missing? */ +} AlterTSConfigurationStmt; + +typedef struct PublicationTable +{ + NodeTag type; + RangeVar *relation; /* relation to be published */ + Node *whereClause; /* qualifications */ + List *columns; /* List of columns in a publication table */ +} PublicationTable; + +/* + * Publication object type + */ +typedef enum PublicationObjSpecType +{ + PUBLICATIONOBJ_TABLE, /* A table */ + PUBLICATIONOBJ_TABLES_IN_SCHEMA, /* All tables in schema */ + PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA, /* All tables in first element of + * search_path */ + PUBLICATIONOBJ_CONTINUATION /* Continuation of previous type */ +} PublicationObjSpecType; + +typedef struct PublicationObjSpec +{ + NodeTag type; + PublicationObjSpecType pubobjtype; /* type of this publication object */ + char *name; + PublicationTable *pubtable; + int location; /* token location, or -1 if unknown */ +} PublicationObjSpec; + +typedef struct CreatePublicationStmt +{ + NodeTag type; + char *pubname; /* Name of the publication */ + List *options; /* List of DefElem nodes */ + List *pubobjects; /* Optional list of publication objects */ + bool for_all_tables; /* Special publication for all tables in db */ +} CreatePublicationStmt; + +typedef enum AlterPublicationAction +{ + AP_AddObjects, /* add objects to publication */ + AP_DropObjects, /* remove objects from publication */ + AP_SetObjects /* set list of objects */ +} AlterPublicationAction; + +typedef struct AlterPublicationStmt +{ + NodeTag type; + char *pubname; /* Name of the publication */ + + /* parameters used for ALTER PUBLICATION ... WITH */ + List *options; /* List of DefElem nodes */ + + /* + * Parameters used for ALTER PUBLICATION ... ADD/DROP/SET publication + * objects. + */ + List *pubobjects; /* Optional list of publication objects */ + bool for_all_tables; /* Special publication for all tables in db */ + AlterPublicationAction action; /* What action to perform with the given + * objects */ +} AlterPublicationStmt; + +typedef struct CreateSubscriptionStmt +{ + NodeTag type; + char *subname; /* Name of the subscription */ + char *conninfo; /* Connection string to publisher */ + List *publication; /* One or more publication to subscribe to */ + List *options; /* List of DefElem nodes */ +} CreateSubscriptionStmt; + +typedef enum AlterSubscriptionType +{ + ALTER_SUBSCRIPTION_OPTIONS, + ALTER_SUBSCRIPTION_CONNECTION, + ALTER_SUBSCRIPTION_SET_PUBLICATION, + ALTER_SUBSCRIPTION_ADD_PUBLICATION, + ALTER_SUBSCRIPTION_DROP_PUBLICATION, + ALTER_SUBSCRIPTION_REFRESH, + ALTER_SUBSCRIPTION_ENABLED, + ALTER_SUBSCRIPTION_SKIP +} AlterSubscriptionType; + +typedef struct AlterSubscriptionStmt +{ + NodeTag type; + AlterSubscriptionType kind; /* ALTER_SUBSCRIPTION_OPTIONS, etc */ + char *subname; /* Name of the subscription */ + char *conninfo; /* Connection string to publisher */ + List *publication; /* One or more publication to subscribe to */ + List *options; /* List of DefElem nodes */ +} AlterSubscriptionStmt; + +typedef struct DropSubscriptionStmt +{ + NodeTag type; + char *subname; /* Name of the subscription */ + bool missing_ok; /* Skip error if missing? */ + DropBehavior behavior; /* RESTRICT or CASCADE behavior */ +} DropSubscriptionStmt; + +#endif /* PARSENODES_H */ diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h new file mode 100644 index 0000000..9d804d4 --- /dev/null +++ b/src/include/nodes/pathnodes.h @@ -0,0 +1,2737 @@ +/*------------------------------------------------------------------------- + * + * pathnodes.h + * Definitions for planner's internal data structures, especially Paths. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/pathnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef PATHNODES_H +#define PATHNODES_H + +#include "access/sdir.h" +#include "lib/stringinfo.h" +#include "nodes/params.h" +#include "nodes/parsenodes.h" +#include "storage/block.h" + + +/* + * Relids + * Set of relation identifiers (indexes into the rangetable). + */ +typedef Bitmapset *Relids; + +/* + * When looking for a "cheapest path", this enum specifies whether we want + * cheapest startup cost or cheapest total cost. + */ +typedef enum CostSelector +{ + STARTUP_COST, TOTAL_COST +} CostSelector; + +/* + * The cost estimate produced by cost_qual_eval() includes both a one-time + * (startup) cost, and a per-tuple cost. + */ +typedef struct QualCost +{ + Cost startup; /* one-time cost */ + Cost per_tuple; /* per-evaluation cost */ +} QualCost; + +/* + * Costing aggregate function execution requires these statistics about + * the aggregates to be executed by a given Agg node. Note that the costs + * include the execution costs of the aggregates' argument expressions as + * well as the aggregate functions themselves. Also, the fields must be + * defined so that initializing the struct to zeroes with memset is correct. + */ +typedef struct AggClauseCosts +{ + QualCost transCost; /* total per-input-row execution costs */ + QualCost finalCost; /* total per-aggregated-row costs */ + Size transitionSpace; /* space for pass-by-ref transition data */ +} AggClauseCosts; + +/* + * This enum identifies the different types of "upper" (post-scan/join) + * relations that we might deal with during planning. + */ +typedef enum UpperRelationKind +{ + UPPERREL_SETOP, /* result of UNION/INTERSECT/EXCEPT, if any */ + UPPERREL_PARTIAL_GROUP_AGG, /* result of partial grouping/aggregation, if + * any */ + UPPERREL_GROUP_AGG, /* result of grouping/aggregation, if any */ + UPPERREL_WINDOW, /* result of window functions, if any */ + UPPERREL_PARTIAL_DISTINCT, /* result of partial "SELECT DISTINCT", if any */ + UPPERREL_DISTINCT, /* result of "SELECT DISTINCT", if any */ + UPPERREL_ORDERED, /* result of ORDER BY, if any */ + UPPERREL_FINAL /* result of any remaining top-level actions */ + /* NB: UPPERREL_FINAL must be last enum entry; it's used to size arrays */ +} UpperRelationKind; + +/*---------- + * PlannerGlobal + * Global information for planning/optimization + * + * PlannerGlobal holds state for an entire planner invocation; this state + * is shared across all levels of sub-Queries that exist in the command being + * planned. + *---------- + */ +typedef struct PlannerGlobal +{ + NodeTag type; + + ParamListInfo boundParams; /* Param values provided to planner() */ + + List *subplans; /* Plans for SubPlan nodes */ + + List *subroots; /* PlannerInfos for SubPlan nodes */ + + Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */ + + List *finalrtable; /* "flat" rangetable for executor */ + + List *finalrowmarks; /* "flat" list of PlanRowMarks */ + + List *resultRelations; /* "flat" list of integer RT indexes */ + + List *appendRelations; /* "flat" list of AppendRelInfos */ + + List *relationOids; /* OIDs of relations the plan depends on */ + + List *invalItems; /* other dependencies, as PlanInvalItems */ + + List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */ + + Index lastPHId; /* highest PlaceHolderVar ID assigned */ + + Index lastRowMarkId; /* highest PlanRowMark ID assigned */ + + int lastPlanNodeId; /* highest plan node ID assigned */ + + bool transientPlan; /* redo plan when TransactionXmin changes? */ + + bool dependsOnRole; /* is plan specific to current role? */ + + bool parallelModeOK; /* parallel mode potentially OK? */ + + bool parallelModeNeeded; /* parallel mode actually required? */ + + char maxParallelHazard; /* worst PROPARALLEL hazard level */ + + PartitionDirectory partition_directory; /* partition descriptors */ +} PlannerGlobal; + +/* macro for fetching the Plan associated with a SubPlan node */ +#define planner_subplan_get_plan(root, subplan) \ + ((Plan *) list_nth((root)->glob->subplans, (subplan)->plan_id - 1)) + + +/*---------- + * PlannerInfo + * Per-query information for planning/optimization + * + * This struct is conventionally called "root" in all the planner routines. + * It holds links to all of the planner's working state, in addition to the + * original Query. Note that at present the planner extensively modifies + * the passed-in Query data structure; someday that should stop. + * + * For reasons explained in optimizer/optimizer.h, we define the typedef + * either here or in that header, whichever is read first. + *---------- + */ +#ifndef HAVE_PLANNERINFO_TYPEDEF +typedef struct PlannerInfo PlannerInfo; +#define HAVE_PLANNERINFO_TYPEDEF 1 +#endif + +struct PlannerInfo +{ + NodeTag type; + + Query *parse; /* the Query being planned */ + + PlannerGlobal *glob; /* global info for current planner run */ + + Index query_level; /* 1 at the outermost Query */ + + PlannerInfo *parent_root; /* NULL at outermost Query */ + + /* + * plan_params contains the expressions that this query level needs to + * make available to a lower query level that is currently being planned. + * outer_params contains the paramIds of PARAM_EXEC Params that outer + * query levels will make available to this query level. + */ + List *plan_params; /* list of PlannerParamItems, see below */ + Bitmapset *outer_params; + + /* + * simple_rel_array holds pointers to "base rels" and "other rels" (see + * comments for RelOptInfo for more info). It is indexed by rangetable + * index (so entry 0 is always wasted). Entries can be NULL when an RTE + * does not correspond to a base relation, such as a join RTE or an + * unreferenced view RTE; or if the RelOptInfo hasn't been made yet. + */ + struct RelOptInfo **simple_rel_array; /* All 1-rel RelOptInfos */ + int simple_rel_array_size; /* allocated size of array */ + + /* + * simple_rte_array is the same length as simple_rel_array and holds + * pointers to the associated rangetable entries. Using this is a shade + * faster than using rt_fetch(), mostly due to fewer indirections. + */ + RangeTblEntry **simple_rte_array; /* rangetable as an array */ + + /* + * append_rel_array is the same length as the above arrays, and holds + * pointers to the corresponding AppendRelInfo entry indexed by + * child_relid, or NULL if the rel is not an appendrel child. The array + * itself is not allocated if append_rel_list is empty. + */ + struct AppendRelInfo **append_rel_array; + + /* + * all_baserels is a Relids set of all base relids (but not "other" + * relids) in the query; that is, the Relids identifier of the final join + * we need to form. This is computed in make_one_rel, just before we + * start making Paths. + */ + Relids all_baserels; + + /* + * nullable_baserels is a Relids set of base relids that are nullable by + * some outer join in the jointree; these are rels that are potentially + * nullable below the WHERE clause, SELECT targetlist, etc. This is + * computed in deconstruct_jointree. + */ + Relids nullable_baserels; + + /* + * join_rel_list is a list of all join-relation RelOptInfos we have + * considered in this planning run. For small problems we just scan the + * list to do lookups, but when there are many join relations we build a + * hash table for faster lookups. The hash table is present and valid + * when join_rel_hash is not NULL. Note that we still maintain the list + * even when using the hash table for lookups; this simplifies life for + * GEQO. + */ + List *join_rel_list; /* list of join-relation RelOptInfos */ + struct HTAB *join_rel_hash; /* optional hashtable for join relations */ + + /* + * When doing a dynamic-programming-style join search, join_rel_level[k] + * is a list of all join-relation RelOptInfos of level k, and + * join_cur_level is the current level. New join-relation RelOptInfos are + * automatically added to the join_rel_level[join_cur_level] list. + * join_rel_level is NULL if not in use. + */ + List **join_rel_level; /* lists of join-relation RelOptInfos */ + int join_cur_level; /* index of list being extended */ + + List *init_plans; /* init SubPlans for query */ + + List *cte_plan_ids; /* per-CTE-item list of subplan IDs (or -1 if + * no subplan was made for that CTE) */ + + List *multiexpr_params; /* List of Lists of Params for MULTIEXPR + * subquery outputs */ + + List *eq_classes; /* list of active EquivalenceClasses */ + + bool ec_merging_done; /* set true once ECs are canonical */ + + List *canon_pathkeys; /* list of "canonical" PathKeys */ + + List *left_join_clauses; /* list of RestrictInfos for mergejoinable + * outer join clauses w/nonnullable var on + * left */ + + List *right_join_clauses; /* list of RestrictInfos for mergejoinable + * outer join clauses w/nonnullable var on + * right */ + + List *full_join_clauses; /* list of RestrictInfos for mergejoinable + * full join clauses */ + + List *join_info_list; /* list of SpecialJoinInfos */ + + /* + * all_result_relids is empty for SELECT, otherwise it contains at least + * parse->resultRelation. For UPDATE/DELETE/MERGE across an inheritance + * or partitioning tree, the result rel's child relids are added. When + * using multi-level partitioning, intermediate partitioned rels are + * included. leaf_result_relids is similar except that only actual result + * tables, not partitioned tables, are included in it. + */ + Relids all_result_relids; /* set of all result relids */ + Relids leaf_result_relids; /* set of all leaf relids */ + + /* + * Note: for AppendRelInfos describing partitions of a partitioned table, + * we guarantee that partitions that come earlier in the partitioned + * table's PartitionDesc will appear earlier in append_rel_list. + */ + List *append_rel_list; /* list of AppendRelInfos */ + + List *row_identity_vars; /* list of RowIdentityVarInfos */ + + List *rowMarks; /* list of PlanRowMarks */ + + List *placeholder_list; /* list of PlaceHolderInfos */ + + List *fkey_list; /* list of ForeignKeyOptInfos */ + + List *query_pathkeys; /* desired pathkeys for query_planner() */ + + List *group_pathkeys; /* groupClause pathkeys, if any */ + List *window_pathkeys; /* pathkeys of bottom window, if any */ + List *distinct_pathkeys; /* distinctClause pathkeys, if any */ + List *sort_pathkeys; /* sortClause pathkeys, if any */ + + List *part_schemes; /* Canonicalised partition schemes used in the + * query. */ + + List *initial_rels; /* RelOptInfos we are now trying to join */ + + /* Use fetch_upper_rel() to get any particular upper rel */ + List *upper_rels[UPPERREL_FINAL + 1]; /* upper-rel RelOptInfos */ + + /* Result tlists chosen by grouping_planner for upper-stage processing */ + struct PathTarget *upper_targets[UPPERREL_FINAL + 1]; + + /* + * The fully-processed targetlist is kept here. It differs from + * parse->targetList in that (for INSERT) it's been reordered to match the + * target table, and defaults have been filled in. Also, additional + * resjunk targets may be present. preprocess_targetlist() does most of + * that work, but note that more resjunk targets can get added during + * appendrel expansion. (Hence, upper_targets mustn't get set up till + * after that.) + */ + List *processed_tlist; + + /* + * For UPDATE, this list contains the target table's attribute numbers to + * which the first N entries of processed_tlist are to be assigned. (Any + * additional entries in processed_tlist must be resjunk.) DO NOT use the + * resnos in processed_tlist to identify the UPDATE target columns. + */ + List *update_colnos; + + /* Fields filled during create_plan() for use in setrefs.c */ + AttrNumber *grouping_map; /* for GroupingFunc fixup */ + List *minmax_aggs; /* List of MinMaxAggInfos */ + + MemoryContext planner_cxt; /* context holding PlannerInfo */ + + Cardinality total_table_pages; /* # of pages in all non-dummy tables of + * query */ + + Selectivity tuple_fraction; /* tuple_fraction passed to query_planner */ + Cardinality limit_tuples; /* limit_tuples passed to query_planner */ + + Index qual_security_level; /* minimum security_level for quals */ + /* Note: qual_security_level is zero if there are no securityQuals */ + + bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */ + bool hasLateralRTEs; /* true if any RTEs are marked LATERAL */ + bool hasHavingQual; /* true if havingQual was non-null */ + bool hasPseudoConstantQuals; /* true if any RestrictInfo has + * pseudoconstant = true */ + bool hasAlternativeSubPlans; /* true if we've made any of those */ + bool hasRecursion; /* true if planning a recursive WITH item */ + + /* + * Information about aggregates. Filled by preprocess_aggrefs(). + */ + List *agginfos; /* AggInfo structs */ + List *aggtransinfos; /* AggTransInfo structs */ + int numOrderedAggs; /* number w/ DISTINCT/ORDER BY/WITHIN GROUP */ + bool hasNonPartialAggs; /* does any agg not support partial mode? */ + bool hasNonSerialAggs; /* is any partial agg non-serializable? */ + + /* These fields are used only when hasRecursion is true: */ + int wt_param_id; /* PARAM_EXEC ID for the work table */ + struct Path *non_recursive_path; /* a path for non-recursive term */ + + /* These fields are workspace for createplan.c */ + Relids curOuterRels; /* outer rels above current node */ + List *curOuterParams; /* not-yet-assigned NestLoopParams */ + + /* These fields are workspace for setrefs.c */ + bool *isAltSubplan; /* array corresponding to glob->subplans */ + bool *isUsedSubplan; /* array corresponding to glob->subplans */ + + /* optional private data for join_search_hook, e.g., GEQO */ + void *join_search_private; + + /* Does this query modify any partition key columns? */ + bool partColsUpdated; +}; + + +/* + * In places where it's known that simple_rte_array[] must have been prepared + * already, we just index into it to fetch RTEs. In code that might be + * executed before or after entering query_planner(), use this macro. + */ +#define planner_rt_fetch(rti, root) \ + ((root)->simple_rte_array ? (root)->simple_rte_array[rti] : \ + rt_fetch(rti, (root)->parse->rtable)) + +/* + * If multiple relations are partitioned the same way, all such partitions + * will have a pointer to the same PartitionScheme. A list of PartitionScheme + * objects is attached to the PlannerInfo. By design, the partition scheme + * incorporates only the general properties of the partition method (LIST vs. + * RANGE, number of partitioning columns and the type information for each) + * and not the specific bounds. + * + * We store the opclass-declared input data types instead of the partition key + * datatypes since the former rather than the latter are used to compare + * partition bounds. Since partition key data types and the opclass declared + * input data types are expected to be binary compatible (per ResolveOpClass), + * both of those should have same byval and length properties. + */ +typedef struct PartitionSchemeData +{ + char strategy; /* partition strategy */ + int16 partnatts; /* number of partition attributes */ + Oid *partopfamily; /* OIDs of operator families */ + Oid *partopcintype; /* OIDs of opclass declared input data types */ + Oid *partcollation; /* OIDs of partitioning collations */ + + /* Cached information about partition key data types. */ + int16 *parttyplen; + bool *parttypbyval; + + /* Cached information about partition comparison functions. */ + struct FmgrInfo *partsupfunc; +} PartitionSchemeData; + +typedef struct PartitionSchemeData *PartitionScheme; + +/*---------- + * RelOptInfo + * Per-relation information for planning/optimization + * + * For planning purposes, a "base rel" is either a plain relation (a table) + * or the output of a sub-SELECT or function that appears in the range table. + * In either case it is uniquely identified by an RT index. A "joinrel" + * is the joining of two or more base rels. A joinrel is identified by + * the set of RT indexes for its component baserels. We create RelOptInfo + * nodes for each baserel and joinrel, and store them in the PlannerInfo's + * simple_rel_array and join_rel_list respectively. + * + * Note that there is only one joinrel for any given set of component + * baserels, no matter what order we assemble them in; so an unordered + * set is the right datatype to identify it with. + * + * We also have "other rels", which are like base rels in that they refer to + * single RT indexes; but they are not part of the join tree, and are given + * a different RelOptKind to identify them. + * Currently the only kind of otherrels are those made for member relations + * of an "append relation", that is an inheritance set or UNION ALL subquery. + * An append relation has a parent RTE that is a base rel, which represents + * the entire append relation. The member RTEs are otherrels. The parent + * is present in the query join tree but the members are not. The member + * RTEs and otherrels are used to plan the scans of the individual tables or + * subqueries of the append set; then the parent baserel is given Append + * and/or MergeAppend paths comprising the best paths for the individual + * member rels. (See comments for AppendRelInfo for more information.) + * + * At one time we also made otherrels to represent join RTEs, for use in + * handling join alias Vars. Currently this is not needed because all join + * alias Vars are expanded to non-aliased form during preprocess_expression. + * + * We also have relations representing joins between child relations of + * different partitioned tables. These relations are not added to + * join_rel_level lists as they are not joined directly by the dynamic + * programming algorithm. + * + * There is also a RelOptKind for "upper" relations, which are RelOptInfos + * that describe post-scan/join processing steps, such as aggregation. + * Many of the fields in these RelOptInfos are meaningless, but their Path + * fields always hold Paths showing ways to do that processing step. + * + * Lastly, there is a RelOptKind for "dead" relations, which are base rels + * that we have proven we don't need to join after all. + * + * Parts of this data structure are specific to various scan and join + * mechanisms. It didn't seem worth creating new node types for them. + * + * relids - Set of base-relation identifiers; it is a base relation + * if there is just one, a join relation if more than one + * rows - estimated number of tuples in the relation after restriction + * clauses have been applied (ie, output rows of a plan for it) + * consider_startup - true if there is any value in keeping plain paths for + * this rel on the basis of having cheap startup cost + * consider_param_startup - the same for parameterized paths + * reltarget - Default Path output tlist for this rel; normally contains + * Var and PlaceHolderVar nodes for the values we need to + * output from this relation. + * List is in no particular order, but all rels of an + * appendrel set must use corresponding orders. + * NOTE: in an appendrel child relation, may contain + * arbitrary expressions pulled up from a subquery! + * pathlist - List of Path nodes, one for each potentially useful + * method of generating the relation + * ppilist - ParamPathInfo nodes for parameterized Paths, if any + * cheapest_startup_path - the pathlist member with lowest startup cost + * (regardless of ordering) among the unparameterized paths; + * or NULL if there is no unparameterized path + * cheapest_total_path - the pathlist member with lowest total cost + * (regardless of ordering) among the unparameterized paths; + * or if there is no unparameterized path, the path with lowest + * total cost among the paths with minimum parameterization + * cheapest_unique_path - for caching cheapest path to produce unique + * (no duplicates) output from relation; NULL if not yet requested + * cheapest_parameterized_paths - best paths for their parameterizations; + * always includes cheapest_total_path, even if that's unparameterized + * direct_lateral_relids - rels this rel has direct LATERAL references to + * lateral_relids - required outer rels for LATERAL, as a Relids set + * (includes both direct and indirect lateral references) + * + * If the relation is a base relation it will have these fields set: + * + * relid - RTE index (this is redundant with the relids field, but + * is provided for convenience of access) + * rtekind - copy of RTE's rtekind field + * min_attr, max_attr - range of valid AttrNumbers for rel + * attr_needed - array of bitmapsets indicating the highest joinrel + * in which each attribute is needed; if bit 0 is set then + * the attribute is needed as part of final targetlist + * attr_widths - cache space for per-attribute width estimates; + * zero means not computed yet + * lateral_vars - lateral cross-references of rel, if any (list of + * Vars and PlaceHolderVars) + * lateral_referencers - relids of rels that reference this one laterally + * (includes both direct and indirect lateral references) + * indexlist - list of IndexOptInfo nodes for relation's indexes + * (always NIL if it's not a table) + * pages - number of disk pages in relation (zero if not a table) + * tuples - number of tuples in relation (not considering restrictions) + * allvisfrac - fraction of disk pages that are marked all-visible + * eclass_indexes - EquivalenceClasses that mention this rel (filled + * only after EC merging is complete) + * subroot - PlannerInfo for subquery (NULL if it's not a subquery) + * subplan_params - list of PlannerParamItems to be passed to subquery + * + * Note: for a subquery, tuples and subroot are not set immediately + * upon creation of the RelOptInfo object; they are filled in when + * set_subquery_pathlist processes the object. + * + * For otherrels that are appendrel members, these fields are filled + * in just as for a baserel, except we don't bother with lateral_vars. + * + * If the relation is either a foreign table or a join of foreign tables that + * all belong to the same foreign server and are assigned to the same user to + * check access permissions as (cf checkAsUser), these fields will be set: + * + * serverid - OID of foreign server, if foreign table (else InvalidOid) + * userid - OID of user to check access as (InvalidOid means current user) + * useridiscurrent - we've assumed that userid equals current user + * fdwroutine - function hooks for FDW, if foreign table (else NULL) + * fdw_private - private state for FDW, if foreign table (else NULL) + * + * Two fields are used to cache knowledge acquired during the join search + * about whether this rel is provably unique when being joined to given other + * relation(s), ie, it can have at most one row matching any given row from + * that join relation. Currently we only attempt such proofs, and thus only + * populate these fields, for base rels; but someday they might be used for + * join rels too: + * + * unique_for_rels - list of Relid sets, each one being a set of other + * rels for which this one has been proven unique + * non_unique_for_rels - list of Relid sets, each one being a set of + * other rels for which we have tried and failed to prove + * this one unique + * + * The presence of the following fields depends on the restrictions + * and joins that the relation participates in: + * + * baserestrictinfo - List of RestrictInfo nodes, containing info about + * each non-join qualification clause in which this relation + * participates (only used for base rels) + * baserestrictcost - Estimated cost of evaluating the baserestrictinfo + * clauses at a single tuple (only used for base rels) + * baserestrict_min_security - Smallest security_level found among + * clauses in baserestrictinfo + * joininfo - List of RestrictInfo nodes, containing info about each + * join clause in which this relation participates (but + * note this excludes clauses that might be derivable from + * EquivalenceClasses) + * has_eclass_joins - flag that EquivalenceClass joins are possible + * + * Note: Keeping a restrictinfo list in the RelOptInfo is useful only for + * base rels, because for a join rel the set of clauses that are treated as + * restrict clauses varies depending on which sub-relations we choose to join. + * (For example, in a 3-base-rel join, a clause relating rels 1 and 2 must be + * treated as a restrictclause if we join {1} and {2 3} to make {1 2 3}; but + * if we join {1 2} and {3} then that clause will be a restrictclause in {1 2} + * and should not be processed again at the level of {1 2 3}.) Therefore, + * the restrictinfo list in the join case appears in individual JoinPaths + * (field joinrestrictinfo), not in the parent relation. But it's OK for + * the RelOptInfo to store the joininfo list, because that is the same + * for a given rel no matter how we form it. + * + * We store baserestrictcost in the RelOptInfo (for base relations) because + * we know we will need it at least once (to price the sequential scan) + * and may need it multiple times to price index scans. + * + * A join relation is considered to be partitioned if it is formed from a + * join of two relations that are partitioned, have matching partitioning + * schemes, and are joined on an equijoin of the partitioning columns. + * Under those conditions we can consider the join relation to be partitioned + * by either relation's partitioning keys, though some care is needed if + * either relation can be forced to null by outer-joining. For example, an + * outer join like (A LEFT JOIN B ON A.a = B.b) may produce rows with B.b + * NULL. These rows may not fit the partitioning conditions imposed on B. + * Hence, strictly speaking, the join is not partitioned by B.b and thus + * partition keys of an outer join should include partition key expressions + * from the non-nullable side only. However, if a subsequent join uses + * strict comparison operators (and all commonly-used equijoin operators are + * strict), the presence of nulls doesn't cause a problem: such rows couldn't + * match anything on the other side and thus they don't create a need to do + * any cross-partition sub-joins. Hence we can treat such values as still + * partitioning the join output for the purpose of additional partitionwise + * joining, so long as a strict join operator is used by the next join. + * + * If the relation is partitioned, these fields will be set: + * + * part_scheme - Partitioning scheme of the relation + * nparts - Number of partitions + * boundinfo - Partition bounds + * partbounds_merged - true if partition bounds are merged ones + * partition_qual - Partition constraint if not the root + * part_rels - RelOptInfos for each partition + * all_partrels - Relids set of all partition relids + * partexprs, nullable_partexprs - Partition key expressions + * + * The partexprs and nullable_partexprs arrays each contain + * part_scheme->partnatts elements. Each of the elements is a list of + * partition key expressions. For partitioned base relations, there is one + * expression in each partexprs element, and nullable_partexprs is empty. + * For partitioned join relations, each base relation within the join + * contributes one partition key expression per partitioning column; + * that expression goes in the partexprs[i] list if the base relation + * is not nullable by this join or any lower outer join, or in the + * nullable_partexprs[i] list if the base relation is nullable. + * Furthermore, FULL JOINs add extra nullable_partexprs expressions + * corresponding to COALESCE expressions of the left and right join columns, + * to simplify matching join clauses to those lists. + *---------- + */ + +/* Bitmask of flags supported by table AMs */ +#define AMFLAG_HAS_TID_RANGE (1 << 0) + +typedef enum RelOptKind +{ + RELOPT_BASEREL, + RELOPT_JOINREL, + RELOPT_OTHER_MEMBER_REL, + RELOPT_OTHER_JOINREL, + RELOPT_UPPER_REL, + RELOPT_OTHER_UPPER_REL, + RELOPT_DEADREL +} RelOptKind; + +/* + * Is the given relation a simple relation i.e a base or "other" member + * relation? + */ +#define IS_SIMPLE_REL(rel) \ + ((rel)->reloptkind == RELOPT_BASEREL || \ + (rel)->reloptkind == RELOPT_OTHER_MEMBER_REL) + +/* Is the given relation a join relation? */ +#define IS_JOIN_REL(rel) \ + ((rel)->reloptkind == RELOPT_JOINREL || \ + (rel)->reloptkind == RELOPT_OTHER_JOINREL) + +/* Is the given relation an upper relation? */ +#define IS_UPPER_REL(rel) \ + ((rel)->reloptkind == RELOPT_UPPER_REL || \ + (rel)->reloptkind == RELOPT_OTHER_UPPER_REL) + +/* Is the given relation an "other" relation? */ +#define IS_OTHER_REL(rel) \ + ((rel)->reloptkind == RELOPT_OTHER_MEMBER_REL || \ + (rel)->reloptkind == RELOPT_OTHER_JOINREL || \ + (rel)->reloptkind == RELOPT_OTHER_UPPER_REL) + +typedef struct RelOptInfo +{ + NodeTag type; + + RelOptKind reloptkind; + + /* all relations included in this RelOptInfo */ + Relids relids; /* set of base relids (rangetable indexes) */ + + /* size estimates generated by planner */ + Cardinality rows; /* estimated number of result tuples */ + + /* per-relation planner control flags */ + bool consider_startup; /* keep cheap-startup-cost paths? */ + bool consider_param_startup; /* ditto, for parameterized paths? */ + bool consider_parallel; /* consider parallel paths? */ + + /* default result targetlist for Paths scanning this relation */ + struct PathTarget *reltarget; /* list of Vars/Exprs, cost, width */ + + /* materialization information */ + List *pathlist; /* Path structures */ + List *ppilist; /* ParamPathInfos used in pathlist */ + List *partial_pathlist; /* partial Paths */ + struct Path *cheapest_startup_path; + struct Path *cheapest_total_path; + struct Path *cheapest_unique_path; + List *cheapest_parameterized_paths; + + /* parameterization information needed for both base rels and join rels */ + /* (see also lateral_vars and lateral_referencers) */ + Relids direct_lateral_relids; /* rels directly laterally referenced */ + Relids lateral_relids; /* minimum parameterization of rel */ + + /* information about a base rel (not set for join rels!) */ + Index relid; + Oid reltablespace; /* containing tablespace */ + RTEKind rtekind; /* RELATION, SUBQUERY, FUNCTION, etc */ + AttrNumber min_attr; /* smallest attrno of rel (often <0) */ + AttrNumber max_attr; /* largest attrno of rel */ + Relids *attr_needed; /* array indexed [min_attr .. max_attr] */ + int32 *attr_widths; /* array indexed [min_attr .. max_attr] */ + List *lateral_vars; /* LATERAL Vars and PHVs referenced by rel */ + Relids lateral_referencers; /* rels that reference me laterally */ + List *indexlist; /* list of IndexOptInfo */ + List *statlist; /* list of StatisticExtInfo */ + BlockNumber pages; /* size estimates derived from pg_class */ + Cardinality tuples; + double allvisfrac; + Bitmapset *eclass_indexes; /* Indexes in PlannerInfo's eq_classes list of + * ECs that mention this rel */ + PlannerInfo *subroot; /* if subquery */ + List *subplan_params; /* if subquery */ + int rel_parallel_workers; /* wanted number of parallel workers */ + uint32 amflags; /* Bitmask of optional features supported by + * the table AM */ + + /* Information about foreign tables and foreign joins */ + Oid serverid; /* identifies server for the table or join */ + Oid userid; /* identifies user to check access as */ + bool useridiscurrent; /* join is only valid for current user */ + /* use "struct FdwRoutine" to avoid including fdwapi.h here */ + struct FdwRoutine *fdwroutine; + void *fdw_private; + + /* cache space for remembering if we have proven this relation unique */ + List *unique_for_rels; /* known unique for these other relid + * set(s) */ + List *non_unique_for_rels; /* known not unique for these set(s) */ + + /* used by various scans and joins: */ + List *baserestrictinfo; /* RestrictInfo structures (if base rel) */ + QualCost baserestrictcost; /* cost of evaluating the above */ + Index baserestrict_min_security; /* min security_level found in + * baserestrictinfo */ + List *joininfo; /* RestrictInfo structures for join clauses + * involving this rel */ + bool has_eclass_joins; /* T means joininfo is incomplete */ + + /* used by partitionwise joins: */ + bool consider_partitionwise_join; /* consider partitionwise join + * paths? (if partitioned rel) */ + Relids top_parent_relids; /* Relids of topmost parents (if "other" + * rel) */ + + /* used for partitioned relations: */ + PartitionScheme part_scheme; /* Partitioning scheme */ + int nparts; /* Number of partitions; -1 if not yet set; in + * case of a join relation 0 means it's + * considered unpartitioned */ + struct PartitionBoundInfoData *boundinfo; /* Partition bounds */ + bool partbounds_merged; /* True if partition bounds were created + * by partition_bounds_merge() */ + List *partition_qual; /* Partition constraint, if not the root */ + struct RelOptInfo **part_rels; /* Array of RelOptInfos of partitions, + * stored in the same order as bounds */ + Bitmapset *live_parts; /* Bitmap with members acting as indexes into + * the part_rels[] array to indicate which + * partitions survived partition pruning. */ + Relids all_partrels; /* Relids set of all partition relids */ + List **partexprs; /* Non-nullable partition key expressions */ + List **nullable_partexprs; /* Nullable partition key expressions */ +} RelOptInfo; + +/* + * Is given relation partitioned? + * + * It's not enough to test whether rel->part_scheme is set, because it might + * be that the basic partitioning properties of the input relations matched + * but the partition bounds did not. Also, if we are able to prove a rel + * dummy (empty), we should henceforth treat it as unpartitioned. + */ +#define IS_PARTITIONED_REL(rel) \ + ((rel)->part_scheme && (rel)->boundinfo && (rel)->nparts > 0 && \ + (rel)->part_rels && !IS_DUMMY_REL(rel)) + +/* + * Convenience macro to make sure that a partitioned relation has all the + * required members set. + */ +#define REL_HAS_ALL_PART_PROPS(rel) \ + ((rel)->part_scheme && (rel)->boundinfo && (rel)->nparts > 0 && \ + (rel)->part_rels && (rel)->partexprs && (rel)->nullable_partexprs) + +/* + * IndexOptInfo + * Per-index information for planning/optimization + * + * indexkeys[], indexcollations[] each have ncolumns entries. + * opfamily[], and opcintype[] each have nkeycolumns entries. They do + * not contain any information about included attributes. + * + * sortopfamily[], reverse_sort[], and nulls_first[] have + * nkeycolumns entries, if the index is ordered; but if it is unordered, + * those pointers are NULL. + * + * Zeroes in the indexkeys[] array indicate index columns that are + * expressions; there is one element in indexprs for each such column. + * + * For an ordered index, reverse_sort[] and nulls_first[] describe the + * sort ordering of a forward indexscan; we can also consider a backward + * indexscan, which will generate the reverse ordering. + * + * The indexprs and indpred expressions have been run through + * prepqual.c and eval_const_expressions() for ease of matching to + * WHERE clauses. indpred is in implicit-AND form. + * + * indextlist is a TargetEntry list representing the index columns. + * It provides an equivalent base-relation Var for each simple column, + * and links to the matching indexprs element for each expression column. + * + * While most of these fields are filled when the IndexOptInfo is created + * (by plancat.c), indrestrictinfo and predOK are set later, in + * check_index_predicates(). + */ +#ifndef HAVE_INDEXOPTINFO_TYPEDEF +typedef struct IndexOptInfo IndexOptInfo; +#define HAVE_INDEXOPTINFO_TYPEDEF 1 +#endif + +struct IndexOptInfo +{ + NodeTag type; + + Oid indexoid; /* OID of the index relation */ + Oid reltablespace; /* tablespace of index (not table) */ + RelOptInfo *rel; /* back-link to index's table */ + + /* index-size statistics (from pg_class and elsewhere) */ + BlockNumber pages; /* number of disk pages in index */ + Cardinality tuples; /* number of index tuples in index */ + int tree_height; /* index tree height, or -1 if unknown */ + + /* index descriptor information */ + int ncolumns; /* number of columns in index */ + int nkeycolumns; /* number of key columns in index */ + int *indexkeys; /* column numbers of index's attributes both + * key and included columns, or 0 */ + Oid *indexcollations; /* OIDs of collations of index columns */ + Oid *opfamily; /* OIDs of operator families for columns */ + Oid *opcintype; /* OIDs of opclass declared input data types */ + Oid *sortopfamily; /* OIDs of btree opfamilies, if orderable */ + bool *reverse_sort; /* is sort order descending? */ + bool *nulls_first; /* do NULLs come first in the sort order? */ + bytea **opclassoptions; /* opclass-specific options for columns */ + bool *canreturn; /* which index cols can be returned in an + * index-only scan? */ + Oid relam; /* OID of the access method (in pg_am) */ + + List *indexprs; /* expressions for non-simple index columns */ + List *indpred; /* predicate if a partial index, else NIL */ + + List *indextlist; /* targetlist representing index columns */ + + List *indrestrictinfo; /* parent relation's baserestrictinfo + * list, less any conditions implied by + * the index's predicate (unless it's a + * target rel, see comments in + * check_index_predicates()) */ + + bool predOK; /* true if index predicate matches query */ + bool unique; /* true if a unique index */ + bool immediate; /* is uniqueness enforced immediately? */ + bool hypothetical; /* true if index doesn't really exist */ + + /* Remaining fields are copied from the index AM's API struct: */ + bool amcanorderbyop; /* does AM support order by operator result? */ + bool amoptionalkey; /* can query omit key for the first column? */ + bool amsearcharray; /* can AM handle ScalarArrayOpExpr quals? */ + bool amsearchnulls; /* can AM search for NULL/NOT NULL entries? */ + bool amhasgettuple; /* does AM have amgettuple interface? */ + bool amhasgetbitmap; /* does AM have amgetbitmap interface? */ + bool amcanparallel; /* does AM support parallel scan? */ + bool amcanmarkpos; /* does AM support mark/restore? */ + /* Rather than include amapi.h here, we declare amcostestimate like this */ + void (*amcostestimate) (); /* AM's cost estimator */ +}; + +/* + * ForeignKeyOptInfo + * Per-foreign-key information for planning/optimization + * + * The per-FK-column arrays can be fixed-size because we allow at most + * INDEX_MAX_KEYS columns in a foreign key constraint. Each array has + * nkeys valid entries. + */ +typedef struct ForeignKeyOptInfo +{ + NodeTag type; + + /* Basic data about the foreign key (fetched from catalogs): */ + Index con_relid; /* RT index of the referencing table */ + Index ref_relid; /* RT index of the referenced table */ + int nkeys; /* number of columns in the foreign key */ + AttrNumber conkey[INDEX_MAX_KEYS]; /* cols in referencing table */ + AttrNumber confkey[INDEX_MAX_KEYS]; /* cols in referenced table */ + Oid conpfeqop[INDEX_MAX_KEYS]; /* PK = FK operator OIDs */ + + /* Derived info about whether FK's equality conditions match the query: */ + int nmatched_ec; /* # of FK cols matched by ECs */ + int nconst_ec; /* # of these ECs that are ec_has_const */ + int nmatched_rcols; /* # of FK cols matched by non-EC rinfos */ + int nmatched_ri; /* total # of non-EC rinfos matched to FK */ + /* Pointer to eclass matching each column's condition, if there is one */ + struct EquivalenceClass *eclass[INDEX_MAX_KEYS]; + /* Pointer to eclass member for the referencing Var, if there is one */ + struct EquivalenceMember *fk_eclass_member[INDEX_MAX_KEYS]; + /* List of non-EC RestrictInfos matching each column's condition */ + List *rinfos[INDEX_MAX_KEYS]; +} ForeignKeyOptInfo; + +/* + * StatisticExtInfo + * Information about extended statistics for planning/optimization + * + * Each pg_statistic_ext row is represented by one or more nodes of this + * type, or even zero if ANALYZE has not computed them. + */ +typedef struct StatisticExtInfo +{ + NodeTag type; + + Oid statOid; /* OID of the statistics row */ + bool inherit; /* includes child relations */ + RelOptInfo *rel; /* back-link to statistic's table */ + char kind; /* statistics kind of this entry */ + Bitmapset *keys; /* attnums of the columns covered */ + List *exprs; /* expressions */ +} StatisticExtInfo; + +/* + * EquivalenceClasses + * + * Whenever we can determine that a mergejoinable equality clause A = B is + * not delayed by any outer join, we create an EquivalenceClass containing + * the expressions A and B to record this knowledge. If we later find another + * equivalence B = C, we add C to the existing EquivalenceClass; this may + * require merging two existing EquivalenceClasses. At the end of the qual + * distribution process, we have sets of values that are known all transitively + * equal to each other, where "equal" is according to the rules of the btree + * operator family(s) shown in ec_opfamilies, as well as the collation shown + * by ec_collation. (We restrict an EC to contain only equalities whose + * operators belong to the same set of opfamilies. This could probably be + * relaxed, but for now it's not worth the trouble, since nearly all equality + * operators belong to only one btree opclass anyway. Similarly, we suppose + * that all or none of the input datatypes are collatable, so that a single + * collation value is sufficient.) + * + * We also use EquivalenceClasses as the base structure for PathKeys, letting + * us represent knowledge about different sort orderings being equivalent. + * Since every PathKey must reference an EquivalenceClass, we will end up + * with single-member EquivalenceClasses whenever a sort key expression has + * not been equivalenced to anything else. It is also possible that such an + * EquivalenceClass will contain a volatile expression ("ORDER BY random()"), + * which is a case that can't arise otherwise since clauses containing + * volatile functions are never considered mergejoinable. We mark such + * EquivalenceClasses specially to prevent them from being merged with + * ordinary EquivalenceClasses. Also, for volatile expressions we have + * to be careful to match the EquivalenceClass to the correct targetlist + * entry: consider SELECT random() AS a, random() AS b ... ORDER BY b,a. + * So we record the SortGroupRef of the originating sort clause. + * + * We allow equality clauses appearing below the nullable side of an outer join + * to form EquivalenceClasses, but these have a slightly different meaning: + * the included values might be all NULL rather than all the same non-null + * values. See src/backend/optimizer/README for more on that point. + * + * NB: if ec_merged isn't NULL, this class has been merged into another, and + * should be ignored in favor of using the pointed-to class. + */ +typedef struct EquivalenceClass +{ + NodeTag type; + + List *ec_opfamilies; /* btree operator family OIDs */ + Oid ec_collation; /* collation, if datatypes are collatable */ + List *ec_members; /* list of EquivalenceMembers */ + List *ec_sources; /* list of generating RestrictInfos */ + List *ec_derives; /* list of derived RestrictInfos */ + Relids ec_relids; /* all relids appearing in ec_members, except + * for child members (see below) */ + bool ec_has_const; /* any pseudoconstants in ec_members? */ + bool ec_has_volatile; /* the (sole) member is a volatile expr */ + bool ec_below_outer_join; /* equivalence applies below an OJ */ + bool ec_broken; /* failed to generate needed clauses? */ + Index ec_sortref; /* originating sortclause label, or 0 */ + Index ec_min_security; /* minimum security_level in ec_sources */ + Index ec_max_security; /* maximum security_level in ec_sources */ + struct EquivalenceClass *ec_merged; /* set if merged into another EC */ +} EquivalenceClass; + +/* + * If an EC contains a const and isn't below-outer-join, any PathKey depending + * on it must be redundant, since there's only one possible value of the key. + */ +#define EC_MUST_BE_REDUNDANT(eclass) \ + ((eclass)->ec_has_const && !(eclass)->ec_below_outer_join) + +/* + * EquivalenceMember - one member expression of an EquivalenceClass + * + * em_is_child signifies that this element was built by transposing a member + * for an appendrel parent relation to represent the corresponding expression + * for an appendrel child. These members are used for determining the + * pathkeys of scans on the child relation and for explicitly sorting the + * child when necessary to build a MergeAppend path for the whole appendrel + * tree. An em_is_child member has no impact on the properties of the EC as a + * whole; in particular the EC's ec_relids field does NOT include the child + * relation. An em_is_child member should never be marked em_is_const nor + * cause ec_has_const or ec_has_volatile to be set, either. Thus, em_is_child + * members are not really full-fledged members of the EC, but just reflections + * or doppelgangers of real members. Most operations on EquivalenceClasses + * should ignore em_is_child members, and those that don't should test + * em_relids to make sure they only consider relevant members. + * + * em_datatype is usually the same as exprType(em_expr), but can be + * different when dealing with a binary-compatible opfamily; in particular + * anyarray_ops would never work without this. Use em_datatype when + * looking up a specific btree operator to work with this expression. + */ +typedef struct EquivalenceMember +{ + NodeTag type; + + Expr *em_expr; /* the expression represented */ + Relids em_relids; /* all relids appearing in em_expr */ + Relids em_nullable_relids; /* nullable by lower outer joins */ + bool em_is_const; /* expression is pseudoconstant? */ + bool em_is_child; /* derived version for a child relation? */ + Oid em_datatype; /* the "nominal type" used by the opfamily */ +} EquivalenceMember; + +/* + * PathKeys + * + * The sort ordering of a path is represented by a list of PathKey nodes. + * An empty list implies no known ordering. Otherwise the first item + * represents the primary sort key, the second the first secondary sort key, + * etc. The value being sorted is represented by linking to an + * EquivalenceClass containing that value and including pk_opfamily among its + * ec_opfamilies. The EquivalenceClass tells which collation to use, too. + * This is a convenient method because it makes it trivial to detect + * equivalent and closely-related orderings. (See optimizer/README for more + * information.) + * + * Note: pk_strategy is either BTLessStrategyNumber (for ASC) or + * BTGreaterStrategyNumber (for DESC). We assume that all ordering-capable + * index types will use btree-compatible strategy numbers. + */ +typedef struct PathKey +{ + NodeTag type; + + EquivalenceClass *pk_eclass; /* the value that is ordered */ + Oid pk_opfamily; /* btree opfamily defining the ordering */ + int pk_strategy; /* sort direction (ASC or DESC) */ + bool pk_nulls_first; /* do NULLs come before normal values? */ +} PathKey; + +/* + * VolatileFunctionStatus -- allows nodes to cache their + * contain_volatile_functions properties. VOLATILITY_UNKNOWN means not yet + * determined. + */ +typedef enum VolatileFunctionStatus +{ + VOLATILITY_UNKNOWN = 0, + VOLATILITY_VOLATILE, + VOLATILITY_NOVOLATILE +} VolatileFunctionStatus; + +/* + * PathTarget + * + * This struct contains what we need to know during planning about the + * targetlist (output columns) that a Path will compute. Each RelOptInfo + * includes a default PathTarget, which its individual Paths may simply + * reference. However, in some cases a Path may compute outputs different + * from other Paths, and in that case we make a custom PathTarget for it. + * For example, an indexscan might return index expressions that would + * otherwise need to be explicitly calculated. (Note also that "upper" + * relations generally don't have useful default PathTargets.) + * + * exprs contains bare expressions; they do not have TargetEntry nodes on top, + * though those will appear in finished Plans. + * + * sortgrouprefs[] is an array of the same length as exprs, containing the + * corresponding sort/group refnos, or zeroes for expressions not referenced + * by sort/group clauses. If sortgrouprefs is NULL (which it generally is in + * RelOptInfo.reltarget targets; only upper-level Paths contain this info), + * we have not identified sort/group columns in this tlist. This allows us to + * deal with sort/group refnos when needed with less expense than including + * TargetEntry nodes in the exprs list. + */ +typedef struct PathTarget +{ + NodeTag type; + List *exprs; /* list of expressions to be computed */ + Index *sortgrouprefs; /* corresponding sort/group refnos, or 0 */ + QualCost cost; /* cost of evaluating the expressions */ + int width; /* estimated avg width of result tuples */ + VolatileFunctionStatus has_volatile_expr; /* indicates if exprs contain + * any volatile functions. */ +} PathTarget; + +/* Convenience macro to get a sort/group refno from a PathTarget */ +#define get_pathtarget_sortgroupref(target, colno) \ + ((target)->sortgrouprefs ? (target)->sortgrouprefs[colno] : (Index) 0) + + +/* + * ParamPathInfo + * + * All parameterized paths for a given relation with given required outer rels + * link to a single ParamPathInfo, which stores common information such as + * the estimated rowcount for this parameterization. We do this partly to + * avoid recalculations, but mostly to ensure that the estimated rowcount + * is in fact the same for every such path. + * + * Note: ppi_clauses is only used in ParamPathInfos for base relation paths; + * in join cases it's NIL because the set of relevant clauses varies depending + * on how the join is formed. The relevant clauses will appear in each + * parameterized join path's joinrestrictinfo list, instead. + */ +typedef struct ParamPathInfo +{ + NodeTag type; + + Relids ppi_req_outer; /* rels supplying parameters used by path */ + Cardinality ppi_rows; /* estimated number of result tuples */ + List *ppi_clauses; /* join clauses available from outer rels */ +} ParamPathInfo; + + +/* + * Type "Path" is used as-is for sequential-scan paths, as well as some other + * simple plan types that we don't need any extra information in the path for. + * For other path types it is the first component of a larger struct. + * + * "pathtype" is the NodeTag of the Plan node we could build from this Path. + * It is partially redundant with the Path's NodeTag, but allows us to use + * the same Path type for multiple Plan types when there is no need to + * distinguish the Plan type during path processing. + * + * "parent" identifies the relation this Path scans, and "pathtarget" + * describes the precise set of output columns the Path would compute. + * In simple cases all Paths for a given rel share the same targetlist, + * which we represent by having path->pathtarget equal to parent->reltarget. + * + * "param_info", if not NULL, links to a ParamPathInfo that identifies outer + * relation(s) that provide parameter values to each scan of this path. + * That means this path can only be joined to those rels by means of nestloop + * joins with this path on the inside. Also note that a parameterized path + * is responsible for testing all "movable" joinclauses involving this rel + * and the specified outer rel(s). + * + * "rows" is the same as parent->rows in simple paths, but in parameterized + * paths and UniquePaths it can be less than parent->rows, reflecting the + * fact that we've filtered by extra join conditions or removed duplicates. + * + * "pathkeys" is a List of PathKey nodes (see above), describing the sort + * ordering of the path's output rows. + */ +typedef struct Path +{ + NodeTag type; + + NodeTag pathtype; /* tag identifying scan/join method */ + + RelOptInfo *parent; /* the relation this path can build */ + PathTarget *pathtarget; /* list of Vars/Exprs, cost, width */ + + ParamPathInfo *param_info; /* parameterization info, or NULL if none */ + + bool parallel_aware; /* engage parallel-aware logic? */ + bool parallel_safe; /* OK to use as part of parallel plan? */ + int parallel_workers; /* desired # of workers; 0 = not parallel */ + + /* estimated size/costs for path (see costsize.c for more info) */ + Cardinality rows; /* estimated number of result tuples */ + Cost startup_cost; /* cost expended before fetching any tuples */ + Cost total_cost; /* total cost (assuming all tuples fetched) */ + + List *pathkeys; /* sort ordering of path's output */ + /* pathkeys is a List of PathKey nodes; see above */ +} Path; + +/* Macro for extracting a path's parameterization relids; beware double eval */ +#define PATH_REQ_OUTER(path) \ + ((path)->param_info ? (path)->param_info->ppi_req_outer : (Relids) NULL) + +/*---------- + * IndexPath represents an index scan over a single index. + * + * This struct is used for both regular indexscans and index-only scans; + * path.pathtype is T_IndexScan or T_IndexOnlyScan to show which is meant. + * + * 'indexinfo' is the index to be scanned. + * + * 'indexclauses' is a list of IndexClause nodes, each representing one + * index-checkable restriction, with implicit AND semantics across the list. + * An empty list implies a full index scan. + * + * 'indexorderbys', if not NIL, is a list of ORDER BY expressions that have + * been found to be usable as ordering operators for an amcanorderbyop index. + * The list must match the path's pathkeys, ie, one expression per pathkey + * in the same order. These are not RestrictInfos, just bare expressions, + * since they generally won't yield booleans. It's guaranteed that each + * expression has the index key on the left side of the operator. + * + * 'indexorderbycols' is an integer list of index column numbers (zero-based) + * of the same length as 'indexorderbys', showing which index column each + * ORDER BY expression is meant to be used with. (There is no restriction + * on which index column each ORDER BY can be used with.) + * + * 'indexscandir' is one of: + * ForwardScanDirection: forward scan of an ordered index + * BackwardScanDirection: backward scan of an ordered index + * NoMovementScanDirection: scan of an unordered index, or don't care + * (The executor doesn't care whether it gets ForwardScanDirection or + * NoMovementScanDirection for an indexscan, but the planner wants to + * distinguish ordered from unordered indexes for building pathkeys.) + * + * 'indextotalcost' and 'indexselectivity' are saved in the IndexPath so that + * we need not recompute them when considering using the same index in a + * bitmap index/heap scan (see BitmapHeapPath). The costs of the IndexPath + * itself represent the costs of an IndexScan or IndexOnlyScan plan type. + *---------- + */ +typedef struct IndexPath +{ + Path path; + IndexOptInfo *indexinfo; + List *indexclauses; + List *indexorderbys; + List *indexorderbycols; + ScanDirection indexscandir; + Cost indextotalcost; + Selectivity indexselectivity; +} IndexPath; + +/* + * Each IndexClause references a RestrictInfo node from the query's WHERE + * or JOIN conditions, and shows how that restriction can be applied to + * the particular index. We support both indexclauses that are directly + * usable by the index machinery, which are typically of the form + * "indexcol OP pseudoconstant", and those from which an indexable qual + * can be derived. The simplest such transformation is that a clause + * of the form "pseudoconstant OP indexcol" can be commuted to produce an + * indexable qual (the index machinery expects the indexcol to be on the + * left always). Another example is that we might be able to extract an + * indexable range condition from a LIKE condition, as in "x LIKE 'foo%bar'" + * giving rise to "x >= 'foo' AND x < 'fop'". Derivation of such lossy + * conditions is done by a planner support function attached to the + * indexclause's top-level function or operator. + * + * indexquals is a list of RestrictInfos for the directly-usable index + * conditions associated with this IndexClause. In the simplest case + * it's a one-element list whose member is iclause->rinfo. Otherwise, + * it contains one or more directly-usable indexqual conditions extracted + * from the given clause. The 'lossy' flag indicates whether the + * indexquals are semantically equivalent to the original clause, or + * represent a weaker condition. + * + * Normally, indexcol is the index of the single index column the clause + * works on, and indexcols is NIL. But if the clause is a RowCompareExpr, + * indexcol is the index of the leading column, and indexcols is a list of + * all the affected columns. (Note that indexcols matches up with the + * columns of the actual indexable RowCompareExpr in indexquals, which + * might be different from the original in rinfo.) + * + * An IndexPath's IndexClause list is required to be ordered by index + * column, i.e. the indexcol values must form a nondecreasing sequence. + * (The order of multiple clauses for the same index column is unspecified.) + */ +typedef struct IndexClause +{ + NodeTag type; + struct RestrictInfo *rinfo; /* original restriction or join clause */ + List *indexquals; /* indexqual(s) derived from it */ + bool lossy; /* are indexquals a lossy version of clause? */ + AttrNumber indexcol; /* index column the clause uses (zero-based) */ + List *indexcols; /* multiple index columns, if RowCompare */ +} IndexClause; + +/* + * BitmapHeapPath represents one or more indexscans that generate TID bitmaps + * instead of directly accessing the heap, followed by AND/OR combinations + * to produce a single bitmap, followed by a heap scan that uses the bitmap. + * Note that the output is always considered unordered, since it will come + * out in physical heap order no matter what the underlying indexes did. + * + * The individual indexscans are represented by IndexPath nodes, and any + * logic on top of them is represented by a tree of BitmapAndPath and + * BitmapOrPath nodes. Notice that we can use the same IndexPath node both + * to represent a regular (or index-only) index scan plan, and as the child + * of a BitmapHeapPath that represents scanning the same index using a + * BitmapIndexScan. The startup_cost and total_cost figures of an IndexPath + * always represent the costs to use it as a regular (or index-only) + * IndexScan. The costs of a BitmapIndexScan can be computed using the + * IndexPath's indextotalcost and indexselectivity. + */ +typedef struct BitmapHeapPath +{ + Path path; + Path *bitmapqual; /* IndexPath, BitmapAndPath, BitmapOrPath */ +} BitmapHeapPath; + +/* + * BitmapAndPath represents a BitmapAnd plan node; it can only appear as + * part of the substructure of a BitmapHeapPath. The Path structure is + * a bit more heavyweight than we really need for this, but for simplicity + * we make it a derivative of Path anyway. + */ +typedef struct BitmapAndPath +{ + Path path; + List *bitmapquals; /* IndexPaths and BitmapOrPaths */ + Selectivity bitmapselectivity; +} BitmapAndPath; + +/* + * BitmapOrPath represents a BitmapOr plan node; it can only appear as + * part of the substructure of a BitmapHeapPath. The Path structure is + * a bit more heavyweight than we really need for this, but for simplicity + * we make it a derivative of Path anyway. + */ +typedef struct BitmapOrPath +{ + Path path; + List *bitmapquals; /* IndexPaths and BitmapAndPaths */ + Selectivity bitmapselectivity; +} BitmapOrPath; + +/* + * TidPath represents a scan by TID + * + * tidquals is an implicitly OR'ed list of qual expressions of the form + * "CTID = pseudoconstant", or "CTID = ANY(pseudoconstant_array)", + * or a CurrentOfExpr for the relation. + */ +typedef struct TidPath +{ + Path path; + List *tidquals; /* qual(s) involving CTID = something */ +} TidPath; + +/* + * TidRangePath represents a scan by a contiguous range of TIDs + * + * tidrangequals is an implicitly AND'ed list of qual expressions of the form + * "CTID relop pseudoconstant", where relop is one of >,>=,<,<=. + */ +typedef struct TidRangePath +{ + Path path; + List *tidrangequals; +} TidRangePath; + +/* + * SubqueryScanPath represents a scan of an unflattened subquery-in-FROM + * + * Note that the subpath comes from a different planning domain; for example + * RTE indexes within it mean something different from those known to the + * SubqueryScanPath. path.parent->subroot is the planning context needed to + * interpret the subpath. + */ +typedef struct SubqueryScanPath +{ + Path path; + Path *subpath; /* path representing subquery execution */ +} SubqueryScanPath; + +/* + * ForeignPath represents a potential scan of a foreign table, foreign join + * or foreign upper-relation. + * + * fdw_private stores FDW private data about the scan. While fdw_private is + * not actually touched by the core code during normal operations, it's + * generally a good idea to use a representation that can be dumped by + * nodeToString(), so that you can examine the structure during debugging + * with tools like pprint(). + */ +typedef struct ForeignPath +{ + Path path; + Path *fdw_outerpath; + List *fdw_private; +} ForeignPath; + +/* + * CustomPath represents a table scan or a table join done by some out-of-core + * extension. + * + * We provide a set of hooks here - which the provider must take care to set + * up correctly - to allow extensions to supply their own methods of scanning + * a relation or joing relations. For example, a provider might provide GPU + * acceleration, a cache-based scan, or some other kind of logic we haven't + * dreamed up yet. + * + * CustomPaths can be injected into the planning process for a base or join + * relation by set_rel_pathlist_hook or set_join_pathlist_hook functions, + * respectively. + * + * Core code must avoid assuming that the CustomPath is only as large as + * the structure declared here; providers are allowed to make it the first + * element in a larger structure. (Since the planner never copies Paths, + * this doesn't add any complication.) However, for consistency with the + * FDW case, we provide a "custom_private" field in CustomPath; providers + * may prefer to use that rather than define another struct type. + */ + +struct CustomPathMethods; + +typedef struct CustomPath +{ + Path path; + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ + List *custom_paths; /* list of child Path nodes, if any */ + List *custom_private; + const struct CustomPathMethods *methods; +} CustomPath; + +/* + * AppendPath represents an Append plan, ie, successive execution of + * several member plans. + * + * For partial Append, 'subpaths' contains non-partial subpaths followed by + * partial subpaths. + * + * Note: it is possible for "subpaths" to contain only one, or even no, + * elements. These cases are optimized during create_append_plan. + * In particular, an AppendPath with no subpaths is a "dummy" path that + * is created to represent the case that a relation is provably empty. + * (This is a convenient representation because it means that when we build + * an appendrel and find that all its children have been excluded, no extra + * action is needed to recognize the relation as dummy.) + */ +typedef struct AppendPath +{ + Path path; + List *subpaths; /* list of component Paths */ + /* Index of first partial path in subpaths; list_length(subpaths) if none */ + int first_partial_path; + Cardinality limit_tuples; /* hard limit on output tuples, or -1 */ +} AppendPath; + +#define IS_DUMMY_APPEND(p) \ + (IsA((p), AppendPath) && ((AppendPath *) (p))->subpaths == NIL) + +/* + * A relation that's been proven empty will have one path that is dummy + * (but might have projection paths on top). For historical reasons, + * this is provided as a macro that wraps is_dummy_rel(). + */ +#define IS_DUMMY_REL(r) is_dummy_rel(r) +extern bool is_dummy_rel(RelOptInfo *rel); + +/* + * MergeAppendPath represents a MergeAppend plan, ie, the merging of sorted + * results from several member plans to produce similarly-sorted output. + */ +typedef struct MergeAppendPath +{ + Path path; + List *subpaths; /* list of component Paths */ + Cardinality limit_tuples; /* hard limit on output tuples, or -1 */ +} MergeAppendPath; + +/* + * GroupResultPath represents use of a Result plan node to compute the + * output of a degenerate GROUP BY case, wherein we know we should produce + * exactly one row, which might then be filtered by a HAVING qual. + * + * Note that quals is a list of bare clauses, not RestrictInfos. + */ +typedef struct GroupResultPath +{ + Path path; + List *quals; +} GroupResultPath; + +/* + * MaterialPath represents use of a Material plan node, i.e., caching of + * the output of its subpath. This is used when the subpath is expensive + * and needs to be scanned repeatedly, or when we need mark/restore ability + * and the subpath doesn't have it. + */ +typedef struct MaterialPath +{ + Path path; + Path *subpath; +} MaterialPath; + +/* + * MemoizePath represents a Memoize plan node, i.e., a cache that caches + * tuples from parameterized paths to save the underlying node from having to + * be rescanned for parameter values which are already cached. + */ +typedef struct MemoizePath +{ + Path path; + Path *subpath; /* outerpath to cache tuples from */ + List *hash_operators; /* OIDs of hash equality ops for cache keys */ + List *param_exprs; /* expressions that are cache keys */ + bool singlerow; /* true if the cache entry is to be marked as + * complete after caching the first record. */ + bool binary_mode; /* true when cache key should be compared bit + * by bit, false when using hash equality ops */ + Cardinality calls; /* expected number of rescans */ + uint32 est_entries; /* The maximum number of entries that the + * planner expects will fit in the cache, or 0 + * if unknown */ +} MemoizePath; + +/* + * UniquePath represents elimination of distinct rows from the output of + * its subpath. + * + * This can represent significantly different plans: either hash-based or + * sort-based implementation, or a no-op if the input path can be proven + * distinct already. The decision is sufficiently localized that it's not + * worth having separate Path node types. (Note: in the no-op case, we could + * eliminate the UniquePath node entirely and just return the subpath; but + * it's convenient to have a UniquePath in the path tree to signal upper-level + * routines that the input is known distinct.) + */ +typedef enum UniquePathMethod +{ + UNIQUE_PATH_NOOP, /* input is known unique already */ + UNIQUE_PATH_HASH, /* use hashing */ + UNIQUE_PATH_SORT /* use sorting */ +} UniquePathMethod; + +typedef struct UniquePath +{ + Path path; + Path *subpath; + UniquePathMethod umethod; + List *in_operators; /* equality operators of the IN clause */ + List *uniq_exprs; /* expressions to be made unique */ +} UniquePath; + +/* + * GatherPath runs several copies of a plan in parallel and collects the + * results. The parallel leader may also execute the plan, unless the + * single_copy flag is set. + */ +typedef struct GatherPath +{ + Path path; + Path *subpath; /* path for each worker */ + bool single_copy; /* don't execute path more than once */ + int num_workers; /* number of workers sought to help */ +} GatherPath; + +/* + * GatherMergePath runs several copies of a plan in parallel and collects + * the results, preserving their common sort order. + */ +typedef struct GatherMergePath +{ + Path path; + Path *subpath; /* path for each worker */ + int num_workers; /* number of workers sought to help */ +} GatherMergePath; + + +/* + * All join-type paths share these fields. + */ + +typedef struct JoinPath +{ + Path path; + + JoinType jointype; + + bool inner_unique; /* each outer tuple provably matches no more + * than one inner tuple */ + + Path *outerjoinpath; /* path for the outer side of the join */ + Path *innerjoinpath; /* path for the inner side of the join */ + + List *joinrestrictinfo; /* RestrictInfos to apply to join */ + + /* + * See the notes for RelOptInfo and ParamPathInfo to understand why + * joinrestrictinfo is needed in JoinPath, and can't be merged into the + * parent RelOptInfo. + */ +} JoinPath; + +/* + * A nested-loop path needs no special fields. + */ + +typedef struct NestPath +{ + JoinPath jpath; +} NestPath; + +/* + * A mergejoin path has these fields. + * + * Unlike other path types, a MergePath node doesn't represent just a single + * run-time plan node: it can represent up to four. Aside from the MergeJoin + * node itself, there can be a Sort node for the outer input, a Sort node + * for the inner input, and/or a Material node for the inner input. We could + * represent these nodes by separate path nodes, but considering how many + * different merge paths are investigated during a complex join problem, + * it seems better to avoid unnecessary palloc overhead. + * + * path_mergeclauses lists the clauses (in the form of RestrictInfos) + * that will be used in the merge. + * + * Note that the mergeclauses are a subset of the parent relation's + * restriction-clause list. Any join clauses that are not mergejoinable + * appear only in the parent's restrict list, and must be checked by a + * qpqual at execution time. + * + * outersortkeys (resp. innersortkeys) is NIL if the outer path + * (resp. inner path) is already ordered appropriately for the + * mergejoin. If it is not NIL then it is a PathKeys list describing + * the ordering that must be created by an explicit Sort node. + * + * skip_mark_restore is true if the executor need not do mark/restore calls. + * Mark/restore overhead is usually required, but can be skipped if we know + * that the executor need find only one match per outer tuple, and that the + * mergeclauses are sufficient to identify a match. In such cases the + * executor can immediately advance the outer relation after processing a + * match, and therefore it need never back up the inner relation. + * + * materialize_inner is true if a Material node should be placed atop the + * inner input. This may appear with or without an inner Sort step. + */ + +typedef struct MergePath +{ + JoinPath jpath; + List *path_mergeclauses; /* join clauses to be used for merge */ + List *outersortkeys; /* keys for explicit sort, if any */ + List *innersortkeys; /* keys for explicit sort, if any */ + bool skip_mark_restore; /* can executor skip mark/restore? */ + bool materialize_inner; /* add Materialize to inner? */ +} MergePath; + +/* + * A hashjoin path has these fields. + * + * The remarks above for mergeclauses apply for hashclauses as well. + * + * Hashjoin does not care what order its inputs appear in, so we have + * no need for sortkeys. + */ + +typedef struct HashPath +{ + JoinPath jpath; + List *path_hashclauses; /* join clauses used for hashing */ + int num_batches; /* number of batches expected */ + Cardinality inner_rows_total; /* total inner rows expected */ +} HashPath; + +/* + * ProjectionPath represents a projection (that is, targetlist computation) + * + * Nominally, this path node represents using a Result plan node to do a + * projection step. However, if the input plan node supports projection, + * we can just modify its output targetlist to do the required calculations + * directly, and not need a Result. In some places in the planner we can just + * jam the desired PathTarget into the input path node (and adjust its cost + * accordingly), so we don't need a ProjectionPath. But in other places + * it's necessary to not modify the input path node, so we need a separate + * ProjectionPath node, which is marked dummy to indicate that we intend to + * assign the work to the input plan node. The estimated cost for the + * ProjectionPath node will account for whether a Result will be used or not. + */ +typedef struct ProjectionPath +{ + Path path; + Path *subpath; /* path representing input source */ + bool dummypp; /* true if no separate Result is needed */ +} ProjectionPath; + +/* + * ProjectSetPath represents evaluation of a targetlist that includes + * set-returning function(s), which will need to be implemented by a + * ProjectSet plan node. + */ +typedef struct ProjectSetPath +{ + Path path; + Path *subpath; /* path representing input source */ +} ProjectSetPath; + +/* + * SortPath represents an explicit sort step + * + * The sort keys are, by definition, the same as path.pathkeys. + * + * Note: the Sort plan node cannot project, so path.pathtarget must be the + * same as the input's pathtarget. + */ +typedef struct SortPath +{ + Path path; + Path *subpath; /* path representing input source */ +} SortPath; + +/* + * IncrementalSortPath represents an incremental sort step + * + * This is like a regular sort, except some leading key columns are assumed + * to be ordered already. + */ +typedef struct IncrementalSortPath +{ + SortPath spath; + int nPresortedCols; /* number of presorted columns */ +} IncrementalSortPath; + +/* + * GroupPath represents grouping (of presorted input) + * + * groupClause represents the columns to be grouped on; the input path + * must be at least that well sorted. + * + * We can also apply a qual to the grouped rows (equivalent of HAVING) + */ +typedef struct GroupPath +{ + Path path; + Path *subpath; /* path representing input source */ + List *groupClause; /* a list of SortGroupClause's */ + List *qual; /* quals (HAVING quals), if any */ +} GroupPath; + +/* + * UpperUniquePath represents adjacent-duplicate removal (in presorted input) + * + * The columns to be compared are the first numkeys columns of the path's + * pathkeys. The input is presumed already sorted that way. + */ +typedef struct UpperUniquePath +{ + Path path; + Path *subpath; /* path representing input source */ + int numkeys; /* number of pathkey columns to compare */ +} UpperUniquePath; + +/* + * AggPath represents generic computation of aggregate functions + * + * This may involve plain grouping (but not grouping sets), using either + * sorted or hashed grouping; for the AGG_SORTED case, the input must be + * appropriately presorted. + */ +typedef struct AggPath +{ + Path path; + Path *subpath; /* path representing input source */ + AggStrategy aggstrategy; /* basic strategy, see nodes.h */ + AggSplit aggsplit; /* agg-splitting mode, see nodes.h */ + Cardinality numGroups; /* estimated number of groups in input */ + uint64 transitionSpace; /* for pass-by-ref transition data */ + List *groupClause; /* a list of SortGroupClause's */ + List *qual; /* quals (HAVING quals), if any */ +} AggPath; + +/* + * Various annotations used for grouping sets in the planner. + */ + +typedef struct GroupingSetData +{ + NodeTag type; + List *set; /* grouping set as list of sortgrouprefs */ + Cardinality numGroups; /* est. number of result groups */ +} GroupingSetData; + +typedef struct RollupData +{ + NodeTag type; + List *groupClause; /* applicable subset of parse->groupClause */ + List *gsets; /* lists of integer indexes into groupClause */ + List *gsets_data; /* list of GroupingSetData */ + Cardinality numGroups; /* est. number of result groups */ + bool hashable; /* can be hashed */ + bool is_hashed; /* to be implemented as a hashagg */ +} RollupData; + +/* + * GroupingSetsPath represents a GROUPING SETS aggregation + */ + +typedef struct GroupingSetsPath +{ + Path path; + Path *subpath; /* path representing input source */ + AggStrategy aggstrategy; /* basic strategy */ + List *rollups; /* list of RollupData */ + List *qual; /* quals (HAVING quals), if any */ + uint64 transitionSpace; /* for pass-by-ref transition data */ +} GroupingSetsPath; + +/* + * MinMaxAggPath represents computation of MIN/MAX aggregates from indexes + */ +typedef struct MinMaxAggPath +{ + Path path; + List *mmaggregates; /* list of MinMaxAggInfo */ + List *quals; /* HAVING quals, if any */ +} MinMaxAggPath; + +/* + * WindowAggPath represents generic computation of window functions + */ +typedef struct WindowAggPath +{ + Path path; + Path *subpath; /* path representing input source */ + WindowClause *winclause; /* WindowClause we'll be using */ + List *qual; /* lower-level WindowAgg runconditions */ + bool topwindow; /* false for all apart from the WindowAgg + * that's closest to the root of the plan */ +} WindowAggPath; + +/* + * SetOpPath represents a set-operation, that is INTERSECT or EXCEPT + */ +typedef struct SetOpPath +{ + Path path; + Path *subpath; /* path representing input source */ + SetOpCmd cmd; /* what to do, see nodes.h */ + SetOpStrategy strategy; /* how to do it, see nodes.h */ + List *distinctList; /* SortGroupClauses identifying target cols */ + AttrNumber flagColIdx; /* where is the flag column, if any */ + int firstFlag; /* flag value for first input relation */ + Cardinality numGroups; /* estimated number of groups in input */ +} SetOpPath; + +/* + * RecursiveUnionPath represents a recursive UNION node + */ +typedef struct RecursiveUnionPath +{ + Path path; + Path *leftpath; /* paths representing input sources */ + Path *rightpath; + List *distinctList; /* SortGroupClauses identifying target cols */ + int wtParam; /* ID of Param representing work table */ + Cardinality numGroups; /* estimated number of groups in input */ +} RecursiveUnionPath; + +/* + * LockRowsPath represents acquiring row locks for SELECT FOR UPDATE/SHARE + */ +typedef struct LockRowsPath +{ + Path path; + Path *subpath; /* path representing input source */ + List *rowMarks; /* a list of PlanRowMark's */ + int epqParam; /* ID of Param for EvalPlanQual re-eval */ +} LockRowsPath; + +/* + * ModifyTablePath represents performing INSERT/UPDATE/DELETE/MERGE + * + * We represent most things that will be in the ModifyTable plan node + * literally, except we have a child Path not Plan. But analysis of the + * OnConflictExpr is deferred to createplan.c, as is collection of FDW data. + */ +typedef struct ModifyTablePath +{ + Path path; + Path *subpath; /* Path producing source data */ + CmdType operation; /* INSERT, UPDATE, DELETE, or MERGE */ + bool canSetTag; /* do we set the command tag/es_processed? */ + Index nominalRelation; /* Parent RT index for use of EXPLAIN */ + Index rootRelation; /* Root RT index, if partitioned/inherited */ + bool partColsUpdated; /* some part key in hierarchy updated? */ + List *resultRelations; /* integer list of RT indexes */ + List *updateColnosLists; /* per-target-table update_colnos lists */ + List *withCheckOptionLists; /* per-target-table WCO lists */ + List *returningLists; /* per-target-table RETURNING tlists */ + List *rowMarks; /* PlanRowMarks (non-locking only) */ + OnConflictExpr *onconflict; /* ON CONFLICT clause, or NULL */ + int epqParam; /* ID of Param for EvalPlanQual re-eval */ + List *mergeActionLists; /* per-target-table lists of actions for + * MERGE */ +} ModifyTablePath; + +/* + * LimitPath represents applying LIMIT/OFFSET restrictions + */ +typedef struct LimitPath +{ + Path path; + Path *subpath; /* path representing input source */ + Node *limitOffset; /* OFFSET parameter, or NULL if none */ + Node *limitCount; /* COUNT parameter, or NULL if none */ + LimitOption limitOption; /* FETCH FIRST with ties or exact number */ +} LimitPath; + + +/* + * Restriction clause info. + * + * We create one of these for each AND sub-clause of a restriction condition + * (WHERE or JOIN/ON clause). Since the restriction clauses are logically + * ANDed, we can use any one of them or any subset of them to filter out + * tuples, without having to evaluate the rest. The RestrictInfo node itself + * stores data used by the optimizer while choosing the best query plan. + * + * If a restriction clause references a single base relation, it will appear + * in the baserestrictinfo list of the RelOptInfo for that base rel. + * + * If a restriction clause references more than one base rel, it will + * appear in the joininfo list of every RelOptInfo that describes a strict + * subset of the base rels mentioned in the clause. The joininfo lists are + * used to drive join tree building by selecting plausible join candidates. + * The clause cannot actually be applied until we have built a join rel + * containing all the base rels it references, however. + * + * When we construct a join rel that includes all the base rels referenced + * in a multi-relation restriction clause, we place that clause into the + * joinrestrictinfo lists of paths for the join rel, if neither left nor + * right sub-path includes all base rels referenced in the clause. The clause + * will be applied at that join level, and will not propagate any further up + * the join tree. (Note: the "predicate migration" code was once intended to + * push restriction clauses up and down the plan tree based on evaluation + * costs, but it's dead code and is unlikely to be resurrected in the + * foreseeable future.) + * + * Note that in the presence of more than two rels, a multi-rel restriction + * might reach different heights in the join tree depending on the join + * sequence we use. So, these clauses cannot be associated directly with + * the join RelOptInfo, but must be kept track of on a per-join-path basis. + * + * RestrictInfos that represent equivalence conditions (i.e., mergejoinable + * equalities that are not outerjoin-delayed) are handled a bit differently. + * Initially we attach them to the EquivalenceClasses that are derived from + * them. When we construct a scan or join path, we look through all the + * EquivalenceClasses and generate derived RestrictInfos representing the + * minimal set of conditions that need to be checked for this particular scan + * or join to enforce that all members of each EquivalenceClass are in fact + * equal in all rows emitted by the scan or join. + * + * When dealing with outer joins we have to be very careful about pushing qual + * clauses up and down the tree. An outer join's own JOIN/ON conditions must + * be evaluated exactly at that join node, unless they are "degenerate" + * conditions that reference only Vars from the nullable side of the join. + * Quals appearing in WHERE or in a JOIN above the outer join cannot be pushed + * down below the outer join, if they reference any nullable Vars. + * RestrictInfo nodes contain a flag to indicate whether a qual has been + * pushed down to a lower level than its original syntactic placement in the + * join tree would suggest. If an outer join prevents us from pushing a qual + * down to its "natural" semantic level (the level associated with just the + * base rels used in the qual) then we mark the qual with a "required_relids" + * value including more than just the base rels it actually uses. By + * pretending that the qual references all the rels required to form the outer + * join, we prevent it from being evaluated below the outer join's joinrel. + * When we do form the outer join's joinrel, we still need to distinguish + * those quals that are actually in that join's JOIN/ON condition from those + * that appeared elsewhere in the tree and were pushed down to the join rel + * because they used no other rels. That's what the is_pushed_down flag is + * for; it tells us that a qual is not an OUTER JOIN qual for the set of base + * rels listed in required_relids. A clause that originally came from WHERE + * or an INNER JOIN condition will *always* have its is_pushed_down flag set. + * It's possible for an OUTER JOIN clause to be marked is_pushed_down too, + * if we decide that it can be pushed down into the nullable side of the join. + * In that case it acts as a plain filter qual for wherever it gets evaluated. + * (In short, is_pushed_down is only false for non-degenerate outer join + * conditions. Possibly we should rename it to reflect that meaning? But + * see also the comments for RINFO_IS_PUSHED_DOWN, below.) + * + * RestrictInfo nodes also contain an outerjoin_delayed flag, which is true + * if the clause's applicability must be delayed due to any outer joins + * appearing below it (ie, it has to be postponed to some join level higher + * than the set of relations it actually references). + * + * There is also an outer_relids field, which is NULL except for outer join + * clauses; for those, it is the set of relids on the outer side of the + * clause's outer join. (These are rels that the clause cannot be applied to + * in parameterized scans, since pushing it into the join's outer side would + * lead to wrong answers.) + * + * There is also a nullable_relids field, which is the set of rels the clause + * references that can be forced null by some outer join below the clause. + * + * outerjoin_delayed = true is subtly different from nullable_relids != NULL: + * a clause might reference some nullable rels and yet not be + * outerjoin_delayed because it also references all the other rels of the + * outer join(s). A clause that is not outerjoin_delayed can be enforced + * anywhere it is computable. + * + * To handle security-barrier conditions efficiently, we mark RestrictInfo + * nodes with a security_level field, in which higher values identify clauses + * coming from less-trusted sources. The exact semantics are that a clause + * cannot be evaluated before another clause with a lower security_level value + * unless the first clause is leakproof. As with outer-join clauses, this + * creates a reason for clauses to sometimes need to be evaluated higher in + * the join tree than their contents would suggest; and even at a single plan + * node, this rule constrains the order of application of clauses. + * + * In general, the referenced clause might be arbitrarily complex. The + * kinds of clauses we can handle as indexscan quals, mergejoin clauses, + * or hashjoin clauses are limited (e.g., no volatile functions). The code + * for each kind of path is responsible for identifying the restrict clauses + * it can use and ignoring the rest. Clauses not implemented by an indexscan, + * mergejoin, or hashjoin will be placed in the plan qual or joinqual field + * of the finished Plan node, where they will be enforced by general-purpose + * qual-expression-evaluation code. (But we are still entitled to count + * their selectivity when estimating the result tuple count, if we + * can guess what it is...) + * + * When the referenced clause is an OR clause, we generate a modified copy + * in which additional RestrictInfo nodes are inserted below the top-level + * OR/AND structure. This is a convenience for OR indexscan processing: + * indexquals taken from either the top level or an OR subclause will have + * associated RestrictInfo nodes. + * + * The can_join flag is set true if the clause looks potentially useful as + * a merge or hash join clause, that is if it is a binary opclause with + * nonoverlapping sets of relids referenced in the left and right sides. + * (Whether the operator is actually merge or hash joinable isn't checked, + * however.) + * + * The pseudoconstant flag is set true if the clause contains no Vars of + * the current query level and no volatile functions. Such a clause can be + * pulled out and used as a one-time qual in a gating Result node. We keep + * pseudoconstant clauses in the same lists as other RestrictInfos so that + * the regular clause-pushing machinery can assign them to the correct join + * level, but they need to be treated specially for cost and selectivity + * estimates. Note that a pseudoconstant clause can never be an indexqual + * or merge or hash join clause, so it's of no interest to large parts of + * the planner. + * + * When join clauses are generated from EquivalenceClasses, there may be + * several equally valid ways to enforce join equivalence, of which we need + * apply only one. We mark clauses of this kind by setting parent_ec to + * point to the generating EquivalenceClass. Multiple clauses with the same + * parent_ec in the same join are redundant. + */ + +typedef struct RestrictInfo +{ + NodeTag type; + + Expr *clause; /* the represented clause of WHERE or JOIN */ + + bool is_pushed_down; /* true if clause was pushed down in level */ + + bool outerjoin_delayed; /* true if delayed by lower outer join */ + + bool can_join; /* see comment above */ + + bool pseudoconstant; /* see comment above */ + + bool leakproof; /* true if known to contain no leaked Vars */ + + VolatileFunctionStatus has_volatile; /* to indicate if clause contains + * any volatile functions. */ + + Index security_level; /* see comment above */ + + /* The set of relids (varnos) actually referenced in the clause: */ + Relids clause_relids; + + /* The set of relids required to evaluate the clause: */ + Relids required_relids; + + /* If an outer-join clause, the outer-side relations, else NULL: */ + Relids outer_relids; + + /* The relids used in the clause that are nullable by lower outer joins: */ + Relids nullable_relids; + + /* These fields are set for any binary opclause: */ + Relids left_relids; /* relids in left side of clause */ + Relids right_relids; /* relids in right side of clause */ + + /* This field is NULL unless clause is an OR clause: */ + Expr *orclause; /* modified clause with RestrictInfos */ + + /* This field is NULL unless clause is potentially redundant: */ + EquivalenceClass *parent_ec; /* generating EquivalenceClass */ + + /* cache space for cost and selectivity */ + QualCost eval_cost; /* eval cost of clause; -1 if not yet set */ + Selectivity norm_selec; /* selectivity for "normal" (JOIN_INNER) + * semantics; -1 if not yet set; >1 means a + * redundant clause */ + Selectivity outer_selec; /* selectivity for outer join semantics; -1 if + * not yet set */ + + /* valid if clause is mergejoinable, else NIL */ + List *mergeopfamilies; /* opfamilies containing clause operator */ + + /* cache space for mergeclause processing; NULL if not yet set */ + EquivalenceClass *left_ec; /* EquivalenceClass containing lefthand */ + EquivalenceClass *right_ec; /* EquivalenceClass containing righthand */ + EquivalenceMember *left_em; /* EquivalenceMember for lefthand */ + EquivalenceMember *right_em; /* EquivalenceMember for righthand */ + List *scansel_cache; /* list of MergeScanSelCache structs */ + + /* transient workspace for use while considering a specific join path */ + bool outer_is_left; /* T = outer var on left, F = on right */ + + /* valid if clause is hashjoinable, else InvalidOid: */ + Oid hashjoinoperator; /* copy of clause operator */ + + /* cache space for hashclause processing; -1 if not yet set */ + Selectivity left_bucketsize; /* avg bucketsize of left side */ + Selectivity right_bucketsize; /* avg bucketsize of right side */ + Selectivity left_mcvfreq; /* left side's most common val's freq */ + Selectivity right_mcvfreq; /* right side's most common val's freq */ + + /* hash equality operators used for memoize nodes, else InvalidOid */ + Oid left_hasheqoperator; + Oid right_hasheqoperator; +} RestrictInfo; + +/* + * This macro embodies the correct way to test whether a RestrictInfo is + * "pushed down" to a given outer join, that is, should be treated as a filter + * clause rather than a join clause at that outer join. This is certainly so + * if is_pushed_down is true; but examining that is not sufficient anymore, + * because outer-join clauses will get pushed down to lower outer joins when + * we generate a path for the lower outer join that is parameterized by the + * LHS of the upper one. We can detect such a clause by noting that its + * required_relids exceed the scope of the join. + */ +#define RINFO_IS_PUSHED_DOWN(rinfo, joinrelids) \ + ((rinfo)->is_pushed_down || \ + !bms_is_subset((rinfo)->required_relids, joinrelids)) + +/* + * Since mergejoinscansel() is a relatively expensive function, and would + * otherwise be invoked many times while planning a large join tree, + * we go out of our way to cache its results. Each mergejoinable + * RestrictInfo carries a list of the specific sort orderings that have + * been considered for use with it, and the resulting selectivities. + */ +typedef struct MergeScanSelCache +{ + /* Ordering details (cache lookup key) */ + Oid opfamily; /* btree opfamily defining the ordering */ + Oid collation; /* collation for the ordering */ + int strategy; /* sort direction (ASC or DESC) */ + bool nulls_first; /* do NULLs come before normal values? */ + /* Results */ + Selectivity leftstartsel; /* first-join fraction for clause left side */ + Selectivity leftendsel; /* last-join fraction for clause left side */ + Selectivity rightstartsel; /* first-join fraction for clause right side */ + Selectivity rightendsel; /* last-join fraction for clause right side */ +} MergeScanSelCache; + +/* + * Placeholder node for an expression to be evaluated below the top level + * of a plan tree. This is used during planning to represent the contained + * expression. At the end of the planning process it is replaced by either + * the contained expression or a Var referring to a lower-level evaluation of + * the contained expression. Typically the evaluation occurs below an outer + * join, and Var references above the outer join might thereby yield NULL + * instead of the expression value. + * + * Although the planner treats this as an expression node type, it is not + * recognized by the parser or executor, so we declare it here rather than + * in primnodes.h. + */ + +typedef struct PlaceHolderVar +{ + Expr xpr; + Expr *phexpr; /* the represented expression */ + Relids phrels; /* base relids syntactically within expr src */ + Index phid; /* ID for PHV (unique within planner run) */ + Index phlevelsup; /* > 0 if PHV belongs to outer query */ +} PlaceHolderVar; + +/* + * "Special join" info. + * + * One-sided outer joins constrain the order of joining partially but not + * completely. We flatten such joins into the planner's top-level list of + * relations to join, but record information about each outer join in a + * SpecialJoinInfo struct. These structs are kept in the PlannerInfo node's + * join_info_list. + * + * Similarly, semijoins and antijoins created by flattening IN (subselect) + * and EXISTS(subselect) clauses create partial constraints on join order. + * These are likewise recorded in SpecialJoinInfo structs. + * + * We make SpecialJoinInfos for FULL JOINs even though there is no flexibility + * of planning for them, because this simplifies make_join_rel()'s API. + * + * min_lefthand and min_righthand are the sets of base relids that must be + * available on each side when performing the special join. lhs_strict is + * true if the special join's condition cannot succeed when the LHS variables + * are all NULL (this means that an outer join can commute with upper-level + * outer joins even if it appears in their RHS). We don't bother to set + * lhs_strict for FULL JOINs, however. + * + * It is not valid for either min_lefthand or min_righthand to be empty sets; + * if they were, this would break the logic that enforces join order. + * + * syn_lefthand and syn_righthand are the sets of base relids that are + * syntactically below this special join. (These are needed to help compute + * min_lefthand and min_righthand for higher joins.) + * + * delay_upper_joins is set true if we detect a pushed-down clause that has + * to be evaluated after this join is formed (because it references the RHS). + * Any outer joins that have such a clause and this join in their RHS cannot + * commute with this join, because that would leave noplace to check the + * pushed-down clause. (We don't track this for FULL JOINs, either.) + * + * For a semijoin, we also extract the join operators and their RHS arguments + * and set semi_operators, semi_rhs_exprs, semi_can_btree, and semi_can_hash. + * This is done in support of possibly unique-ifying the RHS, so we don't + * bother unless at least one of semi_can_btree and semi_can_hash can be set + * true. (You might expect that this information would be computed during + * join planning; but it's helpful to have it available during planning of + * parameterized table scans, so we store it in the SpecialJoinInfo structs.) + * + * jointype is never JOIN_RIGHT; a RIGHT JOIN is handled by switching + * the inputs to make it a LEFT JOIN. So the allowed values of jointype + * in a join_info_list member are only LEFT, FULL, SEMI, or ANTI. + * + * For purposes of join selectivity estimation, we create transient + * SpecialJoinInfo structures for regular inner joins; so it is possible + * to have jointype == JOIN_INNER in such a structure, even though this is + * not allowed within join_info_list. We also create transient + * SpecialJoinInfos with jointype == JOIN_INNER for outer joins, since for + * cost estimation purposes it is sometimes useful to know the join size under + * plain innerjoin semantics. Note that lhs_strict, delay_upper_joins, and + * of course the semi_xxx fields are not set meaningfully within such structs. + */ +#ifndef HAVE_SPECIALJOININFO_TYPEDEF +typedef struct SpecialJoinInfo SpecialJoinInfo; +#define HAVE_SPECIALJOININFO_TYPEDEF 1 +#endif + +struct SpecialJoinInfo +{ + NodeTag type; + Relids min_lefthand; /* base relids in minimum LHS for join */ + Relids min_righthand; /* base relids in minimum RHS for join */ + Relids syn_lefthand; /* base relids syntactically within LHS */ + Relids syn_righthand; /* base relids syntactically within RHS */ + JoinType jointype; /* always INNER, LEFT, FULL, SEMI, or ANTI */ + bool lhs_strict; /* joinclause is strict for some LHS rel */ + bool delay_upper_joins; /* can't commute with upper RHS */ + /* Remaining fields are set only for JOIN_SEMI jointype: */ + bool semi_can_btree; /* true if semi_operators are all btree */ + bool semi_can_hash; /* true if semi_operators are all hash */ + List *semi_operators; /* OIDs of equality join operators */ + List *semi_rhs_exprs; /* righthand-side expressions of these ops */ +}; + +/* + * Append-relation info. + * + * When we expand an inheritable table or a UNION-ALL subselect into an + * "append relation" (essentially, a list of child RTEs), we build an + * AppendRelInfo for each child RTE. The list of AppendRelInfos indicates + * which child RTEs must be included when expanding the parent, and each node + * carries information needed to translate between columns of the parent and + * columns of the child. + * + * These structs are kept in the PlannerInfo node's append_rel_list, with + * append_rel_array[] providing a convenient lookup method for the struct + * associated with a particular child relid (there can be only one, though + * parent rels may have many entries in append_rel_list). + * + * Note: after completion of the planner prep phase, any given RTE is an + * append parent having entries in append_rel_list if and only if its + * "inh" flag is set. We clear "inh" for plain tables that turn out not + * to have inheritance children, and (in an abuse of the original meaning + * of the flag) we set "inh" for subquery RTEs that turn out to be + * flattenable UNION ALL queries. This lets us avoid useless searches + * of append_rel_list. + * + * Note: the data structure assumes that append-rel members are single + * baserels. This is OK for inheritance, but it prevents us from pulling + * up a UNION ALL member subquery if it contains a join. While that could + * be fixed with a more complex data structure, at present there's not much + * point because no improvement in the plan could result. + */ + +typedef struct AppendRelInfo +{ + NodeTag type; + + /* + * These fields uniquely identify this append relationship. There can be + * (in fact, always should be) multiple AppendRelInfos for the same + * parent_relid, but never more than one per child_relid, since a given + * RTE cannot be a child of more than one append parent. + */ + Index parent_relid; /* RT index of append parent rel */ + Index child_relid; /* RT index of append child rel */ + + /* + * For an inheritance appendrel, the parent and child are both regular + * relations, and we store their rowtype OIDs here for use in translating + * whole-row Vars. For a UNION-ALL appendrel, the parent and child are + * both subqueries with no named rowtype, and we store InvalidOid here. + */ + Oid parent_reltype; /* OID of parent's composite type */ + Oid child_reltype; /* OID of child's composite type */ + + /* + * The N'th element of this list is a Var or expression representing the + * child column corresponding to the N'th column of the parent. This is + * used to translate Vars referencing the parent rel into references to + * the child. A list element is NULL if it corresponds to a dropped + * column of the parent (this is only possible for inheritance cases, not + * UNION ALL). The list elements are always simple Vars for inheritance + * cases, but can be arbitrary expressions in UNION ALL cases. + * + * Notice we only store entries for user columns (attno > 0). Whole-row + * Vars are special-cased, and system columns (attno < 0) need no special + * translation since their attnos are the same for all tables. + * + * Caution: the Vars have varlevelsup = 0. Be careful to adjust as needed + * when copying into a subquery. + */ + List *translated_vars; /* Expressions in the child's Vars */ + + /* + * This array simplifies translations in the reverse direction, from + * child's column numbers to parent's. The entry at [ccolno - 1] is the + * 1-based parent column number for child column ccolno, or zero if that + * child column is dropped or doesn't exist in the parent. + */ + int num_child_cols; /* length of array */ + AttrNumber *parent_colnos; /* array of parent attnos, or zeroes */ + + /* + * We store the parent table's OID here for inheritance, or InvalidOid for + * UNION ALL. This is only needed to help in generating error messages if + * an attempt is made to reference a dropped parent column. + */ + Oid parent_reloid; /* OID of parent relation */ +} AppendRelInfo; + +/* + * Information about a row-identity "resjunk" column in UPDATE/DELETE/MERGE. + * + * In partitioned UPDATE/DELETE/MERGE it's important for child partitions to + * share row-identity columns whenever possible, so as not to chew up too many + * targetlist columns. We use these structs to track which identity columns + * have been requested. In the finished plan, each of these will give rise + * to one resjunk entry in the targetlist of the ModifyTable's subplan node. + * + * All the Vars stored in RowIdentityVarInfos must have varno ROWID_VAR, for + * convenience of detecting duplicate requests. We'll replace that, in the + * final plan, with the varno of the generating rel. + * + * Outside this list, a Var with varno ROWID_VAR and varattno k is a reference + * to the k-th element of the row_identity_vars list (k counting from 1). + * We add such a reference to root->processed_tlist when creating the entry, + * and it propagates into the plan tree from there. + */ +typedef struct RowIdentityVarInfo +{ + NodeTag type; + + Var *rowidvar; /* Var to be evaluated (but varno=ROWID_VAR) */ + int32 rowidwidth; /* estimated average width */ + char *rowidname; /* name of the resjunk column */ + Relids rowidrels; /* RTE indexes of target rels using this */ +} RowIdentityVarInfo; + +/* + * For each distinct placeholder expression generated during planning, we + * store a PlaceHolderInfo node in the PlannerInfo node's placeholder_list. + * This stores info that is needed centrally rather than in each copy of the + * PlaceHolderVar. The phid fields identify which PlaceHolderInfo goes with + * each PlaceHolderVar. Note that phid is unique throughout a planner run, + * not just within a query level --- this is so that we need not reassign ID's + * when pulling a subquery into its parent. + * + * The idea is to evaluate the expression at (only) the ph_eval_at join level, + * then allow it to bubble up like a Var until the ph_needed join level. + * ph_needed has the same definition as attr_needed for a regular Var. + * + * The PlaceHolderVar's expression might contain LATERAL references to vars + * coming from outside its syntactic scope. If so, those rels are *not* + * included in ph_eval_at, but they are recorded in ph_lateral. + * + * Notice that when ph_eval_at is a join rather than a single baserel, the + * PlaceHolderInfo may create constraints on join order: the ph_eval_at join + * has to be formed below any outer joins that should null the PlaceHolderVar. + * + * We create a PlaceHolderInfo only after determining that the PlaceHolderVar + * is actually referenced in the plan tree, so that unreferenced placeholders + * don't result in unnecessary constraints on join order. + */ + +typedef struct PlaceHolderInfo +{ + NodeTag type; + + Index phid; /* ID for PH (unique within planner run) */ + PlaceHolderVar *ph_var; /* copy of PlaceHolderVar tree */ + Relids ph_eval_at; /* lowest level we can evaluate value at */ + Relids ph_lateral; /* relids of contained lateral refs, if any */ + Relids ph_needed; /* highest level the value is needed at */ + int32 ph_width; /* estimated attribute width */ +} PlaceHolderInfo; + +/* + * This struct describes one potentially index-optimizable MIN/MAX aggregate + * function. MinMaxAggPath contains a list of these, and if we accept that + * path, the list is stored into root->minmax_aggs for use during setrefs.c. + */ +typedef struct MinMaxAggInfo +{ + NodeTag type; + + Oid aggfnoid; /* pg_proc Oid of the aggregate */ + Oid aggsortop; /* Oid of its sort operator */ + Expr *target; /* expression we are aggregating on */ + PlannerInfo *subroot; /* modified "root" for planning the subquery */ + Path *path; /* access path for subquery */ + Cost pathcost; /* estimated cost to fetch first row */ + Param *param; /* param for subplan's output */ +} MinMaxAggInfo; + +/* + * At runtime, PARAM_EXEC slots are used to pass values around from one plan + * node to another. They can be used to pass values down into subqueries (for + * outer references in subqueries), or up out of subqueries (for the results + * of a subplan), or from a NestLoop plan node into its inner relation (when + * the inner scan is parameterized with values from the outer relation). + * The planner is responsible for assigning nonconflicting PARAM_EXEC IDs to + * the PARAM_EXEC Params it generates. + * + * Outer references are managed via root->plan_params, which is a list of + * PlannerParamItems. While planning a subquery, each parent query level's + * plan_params contains the values required from it by the current subquery. + * During create_plan(), we use plan_params to track values that must be + * passed from outer to inner sides of NestLoop plan nodes. + * + * The item a PlannerParamItem represents can be one of three kinds: + * + * A Var: the slot represents a variable of this level that must be passed + * down because subqueries have outer references to it, or must be passed + * from a NestLoop node to its inner scan. The varlevelsup value in the Var + * will always be zero. + * + * A PlaceHolderVar: this works much like the Var case, except that the + * entry is a PlaceHolderVar node with a contained expression. The PHV + * will have phlevelsup = 0, and the contained expression is adjusted + * to match in level. + * + * An Aggref (with an expression tree representing its argument): the slot + * represents an aggregate expression that is an outer reference for some + * subquery. The Aggref itself has agglevelsup = 0, and its argument tree + * is adjusted to match in level. + * + * Note: we detect duplicate Var and PlaceHolderVar parameters and coalesce + * them into one slot, but we do not bother to do that for Aggrefs. + * The scope of duplicate-elimination only extends across the set of + * parameters passed from one query level into a single subquery, or for + * nestloop parameters across the set of nestloop parameters used in a single + * query level. So there is no possibility of a PARAM_EXEC slot being used + * for conflicting purposes. + * + * In addition, PARAM_EXEC slots are assigned for Params representing outputs + * from subplans (values that are setParam items for those subplans). These + * IDs need not be tracked via PlannerParamItems, since we do not need any + * duplicate-elimination nor later processing of the represented expressions. + * Instead, we just record the assignment of the slot number by appending to + * root->glob->paramExecTypes. + */ +typedef struct PlannerParamItem +{ + NodeTag type; + + Node *item; /* the Var, PlaceHolderVar, or Aggref */ + int paramId; /* its assigned PARAM_EXEC slot number */ +} PlannerParamItem; + +/* + * When making cost estimates for a SEMI/ANTI/inner_unique join, there are + * some correction factors that are needed in both nestloop and hash joins + * to account for the fact that the executor can stop scanning inner rows + * as soon as it finds a match to the current outer row. These numbers + * depend only on the selected outer and inner join relations, not on the + * particular paths used for them, so it's worthwhile to calculate them + * just once per relation pair not once per considered path. This struct + * is filled by compute_semi_anti_join_factors and must be passed along + * to the join cost estimation functions. + * + * outer_match_frac is the fraction of the outer tuples that are + * expected to have at least one match. + * match_count is the average number of matches expected for + * outer tuples that have at least one match. + */ +typedef struct SemiAntiJoinFactors +{ + Selectivity outer_match_frac; + Selectivity match_count; +} SemiAntiJoinFactors; + +/* + * Struct for extra information passed to subroutines of add_paths_to_joinrel + * + * restrictlist contains all of the RestrictInfo nodes for restriction + * clauses that apply to this join + * mergeclause_list is a list of RestrictInfo nodes for available + * mergejoin clauses in this join + * inner_unique is true if each outer tuple provably matches no more + * than one inner tuple + * sjinfo is extra info about special joins for selectivity estimation + * semifactors is as shown above (only valid for SEMI/ANTI/inner_unique joins) + * param_source_rels are OK targets for parameterization of result paths + */ +typedef struct JoinPathExtraData +{ + List *restrictlist; + List *mergeclause_list; + bool inner_unique; + SpecialJoinInfo *sjinfo; + SemiAntiJoinFactors semifactors; + Relids param_source_rels; +} JoinPathExtraData; + +/* + * Various flags indicating what kinds of grouping are possible. + * + * GROUPING_CAN_USE_SORT should be set if it's possible to perform + * sort-based implementations of grouping. When grouping sets are in use, + * this will be true if sorting is potentially usable for any of the grouping + * sets, even if it's not usable for all of them. + * + * GROUPING_CAN_USE_HASH should be set if it's possible to perform + * hash-based implementations of grouping. + * + * GROUPING_CAN_PARTIAL_AGG should be set if the aggregation is of a type + * for which we support partial aggregation (not, for example, grouping sets). + * It says nothing about parallel-safety or the availability of suitable paths. + */ +#define GROUPING_CAN_USE_SORT 0x0001 +#define GROUPING_CAN_USE_HASH 0x0002 +#define GROUPING_CAN_PARTIAL_AGG 0x0004 + +/* + * What kind of partitionwise aggregation is in use? + * + * PARTITIONWISE_AGGREGATE_NONE: Not used. + * + * PARTITIONWISE_AGGREGATE_FULL: Aggregate each partition separately, and + * append the results. + * + * PARTITIONWISE_AGGREGATE_PARTIAL: Partially aggregate each partition + * separately, append the results, and then finalize aggregation. + */ +typedef enum +{ + PARTITIONWISE_AGGREGATE_NONE, + PARTITIONWISE_AGGREGATE_FULL, + PARTITIONWISE_AGGREGATE_PARTIAL +} PartitionwiseAggregateType; + +/* + * Struct for extra information passed to subroutines of create_grouping_paths + * + * flags indicating what kinds of grouping are possible. + * partial_costs_set is true if the agg_partial_costs and agg_final_costs + * have been initialized. + * agg_partial_costs gives partial aggregation costs. + * agg_final_costs gives finalization costs. + * target_parallel_safe is true if target is parallel safe. + * havingQual gives list of quals to be applied after aggregation. + * targetList gives list of columns to be projected. + * patype is the type of partitionwise aggregation that is being performed. + */ +typedef struct +{ + /* Data which remains constant once set. */ + int flags; + bool partial_costs_set; + AggClauseCosts agg_partial_costs; + AggClauseCosts agg_final_costs; + + /* Data which may differ across partitions. */ + bool target_parallel_safe; + Node *havingQual; + List *targetList; + PartitionwiseAggregateType patype; +} GroupPathExtraData; + +/* + * Struct for extra information passed to subroutines of grouping_planner + * + * limit_needed is true if we actually need a Limit plan node. + * limit_tuples is an estimated bound on the number of output tuples, + * or -1 if no LIMIT or couldn't estimate. + * count_est and offset_est are the estimated values of the LIMIT and OFFSET + * expressions computed by preprocess_limit() (see comments for + * preprocess_limit() for more information). + */ +typedef struct +{ + bool limit_needed; + Cardinality limit_tuples; + int64 count_est; + int64 offset_est; +} FinalPathExtraData; + +/* + * For speed reasons, cost estimation for join paths is performed in two + * phases: the first phase tries to quickly derive a lower bound for the + * join cost, and then we check if that's sufficient to reject the path. + * If not, we come back for a more refined cost estimate. The first phase + * fills a JoinCostWorkspace struct with its preliminary cost estimates + * and possibly additional intermediate values. The second phase takes + * these values as inputs to avoid repeating work. + * + * (Ideally we'd declare this in cost.h, but it's also needed in pathnode.h, + * so seems best to put it here.) + */ +typedef struct JoinCostWorkspace +{ + /* Preliminary cost estimates --- must not be larger than final ones! */ + Cost startup_cost; /* cost expended before fetching any tuples */ + Cost total_cost; /* total cost (assuming all tuples fetched) */ + + /* Fields below here should be treated as private to costsize.c */ + Cost run_cost; /* non-startup cost components */ + + /* private for cost_nestloop code */ + Cost inner_run_cost; /* also used by cost_mergejoin code */ + Cost inner_rescan_run_cost; + + /* private for cost_mergejoin code */ + Cardinality outer_rows; + Cardinality inner_rows; + Cardinality outer_skip_rows; + Cardinality inner_skip_rows; + + /* private for cost_hashjoin code */ + int numbuckets; + int numbatches; + Cardinality inner_rows_total; +} JoinCostWorkspace; + +/* + * AggInfo holds information about an aggregate that needs to be computed. + * Multiple Aggrefs in a query can refer to the same AggInfo by having the + * same 'aggno' value, so that the aggregate is computed only once. + */ +typedef struct AggInfo +{ + /* + * Link to an Aggref expr this state value is for. + * + * There can be multiple identical Aggref's sharing the same per-agg. This + * points to the first one of them. + */ + Aggref *representative_aggref; + + int transno; + + /* + * "shareable" is false if this agg cannot share state values with other + * aggregates because the final function is read-write. + */ + bool shareable; + + /* Oid of the final function or InvalidOid */ + Oid finalfn_oid; + +} AggInfo; + +/* + * AggTransInfo holds information about transition state that is used by one + * or more aggregates in the query. Multiple aggregates can share the same + * transition state, if they have the same inputs and the same transition + * function. Aggrefs that share the same transition info have the same + * 'aggtransno' value. + */ +typedef struct AggTransInfo +{ + List *args; + Expr *aggfilter; + + /* Oid of the state transition function */ + Oid transfn_oid; + + /* Oid of the serialization function or InvalidOid */ + Oid serialfn_oid; + + /* Oid of the deserialization function or InvalidOid */ + Oid deserialfn_oid; + + /* Oid of the combine function or InvalidOid */ + Oid combinefn_oid; + + /* Oid of state value's datatype */ + Oid aggtranstype; + int32 aggtranstypmod; + int transtypeLen; + bool transtypeByVal; + int32 aggtransspace; + + /* + * initial value from pg_aggregate entry + */ + Datum initValue; + bool initValueIsNull; + +} AggTransInfo; + +#endif /* PATHNODES_H */ diff --git a/src/include/nodes/pg_list.h b/src/include/nodes/pg_list.h new file mode 100644 index 0000000..5a43290 --- /dev/null +++ b/src/include/nodes/pg_list.h @@ -0,0 +1,612 @@ +/*------------------------------------------------------------------------- + * + * pg_list.h + * interface for PostgreSQL generic list package + * + * Once upon a time, parts of Postgres were written in Lisp and used real + * cons-cell lists for major data structures. When that code was rewritten + * in C, we initially had a faithful emulation of cons-cell lists, which + * unsurprisingly was a performance bottleneck. A couple of major rewrites + * later, these data structures are actually simple expansible arrays; + * but the "List" name and a lot of the notation survives. + * + * One important concession to the original implementation is that an empty + * list is always represented by a null pointer (preferentially written NIL). + * Non-empty lists have a header, which will not be relocated as long as the + * list remains non-empty, and an expansible data array. + * + * We support three types of lists: + * + * T_List: lists of pointers + * (in practice usually pointers to Nodes, but not always; + * declared as "void *" to minimize casting annoyances) + * T_IntList: lists of integers + * T_OidList: lists of Oids + * + * (At the moment, ints and Oids are the same size, but they may not + * always be so; try to be careful to maintain the distinction.) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/pg_list.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LIST_H +#define PG_LIST_H + +#include "nodes/nodes.h" + + +typedef union ListCell +{ + void *ptr_value; + int int_value; + Oid oid_value; +} ListCell; + +typedef struct List +{ + NodeTag type; /* T_List, T_IntList, or T_OidList */ + int length; /* number of elements currently present */ + int max_length; /* allocated length of elements[] */ + ListCell *elements; /* re-allocatable array of cells */ + /* We may allocate some cells along with the List header: */ + ListCell initial_elements[FLEXIBLE_ARRAY_MEMBER]; + /* If elements == initial_elements, it's not a separate allocation */ +} List; + +/* + * The *only* valid representation of an empty list is NIL; in other + * words, a non-NIL list is guaranteed to have length >= 1. + */ +#define NIL ((List *) NULL) + +/* + * State structs for various looping macros below. + */ +typedef struct ForEachState +{ + const List *l; /* list we're looping through */ + int i; /* current element index */ +} ForEachState; + +typedef struct ForBothState +{ + const List *l1; /* lists we're looping through */ + const List *l2; + int i; /* common element index */ +} ForBothState; + +typedef struct ForBothCellState +{ + const List *l1; /* lists we're looping through */ + const List *l2; + int i1; /* current element indexes */ + int i2; +} ForBothCellState; + +typedef struct ForThreeState +{ + const List *l1; /* lists we're looping through */ + const List *l2; + const List *l3; + int i; /* common element index */ +} ForThreeState; + +typedef struct ForFourState +{ + const List *l1; /* lists we're looping through */ + const List *l2; + const List *l3; + const List *l4; + int i; /* common element index */ +} ForFourState; + +typedef struct ForFiveState +{ + const List *l1; /* lists we're looping through */ + const List *l2; + const List *l3; + const List *l4; + const List *l5; + int i; /* common element index */ +} ForFiveState; + +/* + * These routines are small enough, and used often enough, to justify being + * inline. + */ + +/* Fetch address of list's first cell; NULL if empty list */ +static inline ListCell * +list_head(const List *l) +{ + return l ? &l->elements[0] : NULL; +} + +/* Fetch address of list's last cell; NULL if empty list */ +static inline ListCell * +list_tail(const List *l) +{ + return l ? &l->elements[l->length - 1] : NULL; +} + +/* Fetch address of list's second cell, if it has one, else NULL */ +static inline ListCell * +list_second_cell(const List *l) +{ + if (l && l->length >= 2) + return &l->elements[1]; + else + return NULL; +} + +/* Fetch list's length */ +static inline int +list_length(const List *l) +{ + return l ? l->length : 0; +} + +/* + * Macros to access the data values within List cells. + * + * Note that with the exception of the "xxx_node" macros, these are + * lvalues and can be assigned to. + * + * NB: There is an unfortunate legacy from a previous incarnation of + * the List API: the macro lfirst() was used to mean "the data in this + * cons cell". To avoid changing every usage of lfirst(), that meaning + * has been kept. As a result, lfirst() takes a ListCell and returns + * the data it contains; to get the data in the first cell of a + * List, use linitial(). Worse, lsecond() is more closely related to + * linitial() than lfirst(): given a List, lsecond() returns the data + * in the second list cell. + */ +#define lfirst(lc) ((lc)->ptr_value) +#define lfirst_int(lc) ((lc)->int_value) +#define lfirst_oid(lc) ((lc)->oid_value) +#define lfirst_node(type,lc) castNode(type, lfirst(lc)) + +#define linitial(l) lfirst(list_nth_cell(l, 0)) +#define linitial_int(l) lfirst_int(list_nth_cell(l, 0)) +#define linitial_oid(l) lfirst_oid(list_nth_cell(l, 0)) +#define linitial_node(type,l) castNode(type, linitial(l)) + +#define lsecond(l) lfirst(list_nth_cell(l, 1)) +#define lsecond_int(l) lfirst_int(list_nth_cell(l, 1)) +#define lsecond_oid(l) lfirst_oid(list_nth_cell(l, 1)) +#define lsecond_node(type,l) castNode(type, lsecond(l)) + +#define lthird(l) lfirst(list_nth_cell(l, 2)) +#define lthird_int(l) lfirst_int(list_nth_cell(l, 2)) +#define lthird_oid(l) lfirst_oid(list_nth_cell(l, 2)) +#define lthird_node(type,l) castNode(type, lthird(l)) + +#define lfourth(l) lfirst(list_nth_cell(l, 3)) +#define lfourth_int(l) lfirst_int(list_nth_cell(l, 3)) +#define lfourth_oid(l) lfirst_oid(list_nth_cell(l, 3)) +#define lfourth_node(type,l) castNode(type, lfourth(l)) + +#define llast(l) lfirst(list_last_cell(l)) +#define llast_int(l) lfirst_int(list_last_cell(l)) +#define llast_oid(l) lfirst_oid(list_last_cell(l)) +#define llast_node(type,l) castNode(type, llast(l)) + +/* + * Convenience macros for building fixed-length lists + */ +#define list_make_ptr_cell(v) ((ListCell) {.ptr_value = (v)}) +#define list_make_int_cell(v) ((ListCell) {.int_value = (v)}) +#define list_make_oid_cell(v) ((ListCell) {.oid_value = (v)}) + +#define list_make1(x1) \ + list_make1_impl(T_List, list_make_ptr_cell(x1)) +#define list_make2(x1,x2) \ + list_make2_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2)) +#define list_make3(x1,x2,x3) \ + list_make3_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2), \ + list_make_ptr_cell(x3)) +#define list_make4(x1,x2,x3,x4) \ + list_make4_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2), \ + list_make_ptr_cell(x3), list_make_ptr_cell(x4)) +#define list_make5(x1,x2,x3,x4,x5) \ + list_make5_impl(T_List, list_make_ptr_cell(x1), list_make_ptr_cell(x2), \ + list_make_ptr_cell(x3), list_make_ptr_cell(x4), \ + list_make_ptr_cell(x5)) + +#define list_make1_int(x1) \ + list_make1_impl(T_IntList, list_make_int_cell(x1)) +#define list_make2_int(x1,x2) \ + list_make2_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2)) +#define list_make3_int(x1,x2,x3) \ + list_make3_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2), \ + list_make_int_cell(x3)) +#define list_make4_int(x1,x2,x3,x4) \ + list_make4_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2), \ + list_make_int_cell(x3), list_make_int_cell(x4)) +#define list_make5_int(x1,x2,x3,x4,x5) \ + list_make5_impl(T_IntList, list_make_int_cell(x1), list_make_int_cell(x2), \ + list_make_int_cell(x3), list_make_int_cell(x4), \ + list_make_int_cell(x5)) + +#define list_make1_oid(x1) \ + list_make1_impl(T_OidList, list_make_oid_cell(x1)) +#define list_make2_oid(x1,x2) \ + list_make2_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2)) +#define list_make3_oid(x1,x2,x3) \ + list_make3_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2), \ + list_make_oid_cell(x3)) +#define list_make4_oid(x1,x2,x3,x4) \ + list_make4_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2), \ + list_make_oid_cell(x3), list_make_oid_cell(x4)) +#define list_make5_oid(x1,x2,x3,x4,x5) \ + list_make5_impl(T_OidList, list_make_oid_cell(x1), list_make_oid_cell(x2), \ + list_make_oid_cell(x3), list_make_oid_cell(x4), \ + list_make_oid_cell(x5)) + +/* + * Locate the n'th cell (counting from 0) of the list. + * It is an assertion failure if there is no such cell. + */ +static inline ListCell * +list_nth_cell(const List *list, int n) +{ + Assert(list != NIL); + Assert(n >= 0 && n < list->length); + return &list->elements[n]; +} + +/* + * Return the last cell in a non-NIL List. + */ +static inline ListCell * +list_last_cell(const List *list) +{ + Assert(list != NIL); + return &list->elements[list->length - 1]; +} + +/* + * Return the pointer value contained in the n'th element of the + * specified list. (List elements begin at 0.) + */ +static inline void * +list_nth(const List *list, int n) +{ + Assert(IsA(list, List)); + return lfirst(list_nth_cell(list, n)); +} + +/* + * Return the integer value contained in the n'th element of the + * specified list. + */ +static inline int +list_nth_int(const List *list, int n) +{ + Assert(IsA(list, IntList)); + return lfirst_int(list_nth_cell(list, n)); +} + +/* + * Return the OID value contained in the n'th element of the specified + * list. + */ +static inline Oid +list_nth_oid(const List *list, int n) +{ + Assert(IsA(list, OidList)); + return lfirst_oid(list_nth_cell(list, n)); +} + +#define list_nth_node(type,list,n) castNode(type, list_nth(list, n)) + +/* + * Get the given ListCell's index (from 0) in the given List. + */ +static inline int +list_cell_number(const List *l, const ListCell *c) +{ + Assert(c >= &l->elements[0] && c < &l->elements[l->length]); + return c - l->elements; +} + +/* + * Get the address of the next cell after "c" within list "l", or NULL if none. + */ +static inline ListCell * +lnext(const List *l, const ListCell *c) +{ + Assert(c >= &l->elements[0] && c < &l->elements[l->length]); + c++; + if (c < &l->elements[l->length]) + return (ListCell *) c; + else + return NULL; +} + +/* + * foreach - + * a convenience macro for looping through a list + * + * "cell" must be the name of a "ListCell *" variable; it's made to point + * to each List element in turn. "cell" will be NULL after normal exit from + * the loop, but an early "break" will leave it pointing at the current + * List element. + * + * Beware of changing the List object while the loop is iterating. + * The current semantics are that we examine successive list indices in + * each iteration, so that insertion or deletion of list elements could + * cause elements to be re-visited or skipped unexpectedly. Previous + * implementations of foreach() behaved differently. However, it's safe + * to append elements to the List (or in general, insert them after the + * current element); such new elements are guaranteed to be visited. + * Also, the current element of the List can be deleted, if you use + * foreach_delete_current() to do so. BUT: either of these actions will + * invalidate the "cell" pointer for the remainder of the current iteration. + */ +#define foreach(cell, lst) \ + for (ForEachState cell##__state = {(lst), 0}; \ + (cell##__state.l != NIL && \ + cell##__state.i < cell##__state.l->length) ? \ + (cell = &cell##__state.l->elements[cell##__state.i], true) : \ + (cell = NULL, false); \ + cell##__state.i++) + +/* + * foreach_delete_current - + * delete the current list element from the List associated with a + * surrounding foreach() loop, returning the new List pointer. + * + * This is equivalent to list_delete_cell(), but it also adjusts the foreach + * loop's state so that no list elements will be missed. Do not delete + * elements from an active foreach loop's list in any other way! + */ +#define foreach_delete_current(lst, cell) \ + (cell##__state.i--, \ + (List *) (cell##__state.l = list_delete_cell(lst, cell))) + +/* + * foreach_current_index - + * get the zero-based list index of a surrounding foreach() loop's + * current element; pass the name of the "ListCell *" iterator variable. + * + * Beware of using this after foreach_delete_current(); the value will be + * out of sync for the rest of the current loop iteration. Anyway, since + * you just deleted the current element, the value is pretty meaningless. + */ +#define foreach_current_index(cell) (cell##__state.i) + +/* + * for_each_from - + * Like foreach(), but start from the N'th (zero-based) list element, + * not necessarily the first one. + * + * It's okay for N to exceed the list length, but not for it to be negative. + * + * The caveats for foreach() apply equally here. + */ +#define for_each_from(cell, lst, N) \ + for (ForEachState cell##__state = for_each_from_setup(lst, N); \ + (cell##__state.l != NIL && \ + cell##__state.i < cell##__state.l->length) ? \ + (cell = &cell##__state.l->elements[cell##__state.i], true) : \ + (cell = NULL, false); \ + cell##__state.i++) + +static inline ForEachState +for_each_from_setup(const List *lst, int N) +{ + ForEachState r = {lst, N}; + + Assert(N >= 0); + return r; +} + +/* + * for_each_cell - + * a convenience macro which loops through a list starting from a + * specified cell + * + * The caveats for foreach() apply equally here. + */ +#define for_each_cell(cell, lst, initcell) \ + for (ForEachState cell##__state = for_each_cell_setup(lst, initcell); \ + (cell##__state.l != NIL && \ + cell##__state.i < cell##__state.l->length) ? \ + (cell = &cell##__state.l->elements[cell##__state.i], true) : \ + (cell = NULL, false); \ + cell##__state.i++) + +static inline ForEachState +for_each_cell_setup(const List *lst, const ListCell *initcell) +{ + ForEachState r = {lst, + initcell ? list_cell_number(lst, initcell) : list_length(lst)}; + + return r; +} + +/* + * forboth - + * a convenience macro for advancing through two linked lists + * simultaneously. This macro loops through both lists at the same + * time, stopping when either list runs out of elements. Depending + * on the requirements of the call site, it may also be wise to + * assert that the lengths of the two lists are equal. (But, if they + * are not, some callers rely on the ending cell values being separately + * NULL or non-NULL as defined here; don't try to optimize that.) + * + * The caveats for foreach() apply equally here. + */ +#define forboth(cell1, list1, cell2, list2) \ + for (ForBothState cell1##__state = {(list1), (list2), 0}; \ + multi_for_advance_cell(cell1, cell1##__state, l1, i), \ + multi_for_advance_cell(cell2, cell1##__state, l2, i), \ + (cell1 != NULL && cell2 != NULL); \ + cell1##__state.i++) + +#define multi_for_advance_cell(cell, state, l, i) \ + (cell = (state.l != NIL && state.i < state.l->length) ? \ + &state.l->elements[state.i] : NULL) + +/* + * for_both_cell - + * a convenience macro which loops through two lists starting from the + * specified cells of each. This macro loops through both lists at the same + * time, stopping when either list runs out of elements. Depending on the + * requirements of the call site, it may also be wise to assert that the + * lengths of the two lists are equal, and initcell1 and initcell2 are at + * the same position in the respective lists. + * + * The caveats for foreach() apply equally here. + */ +#define for_both_cell(cell1, list1, initcell1, cell2, list2, initcell2) \ + for (ForBothCellState cell1##__state = \ + for_both_cell_setup(list1, initcell1, list2, initcell2); \ + multi_for_advance_cell(cell1, cell1##__state, l1, i1), \ + multi_for_advance_cell(cell2, cell1##__state, l2, i2), \ + (cell1 != NULL && cell2 != NULL); \ + cell1##__state.i1++, cell1##__state.i2++) + +static inline ForBothCellState +for_both_cell_setup(const List *list1, const ListCell *initcell1, + const List *list2, const ListCell *initcell2) +{ + ForBothCellState r = {list1, list2, + initcell1 ? list_cell_number(list1, initcell1) : list_length(list1), + initcell2 ? list_cell_number(list2, initcell2) : list_length(list2)}; + + return r; +} + +/* + * forthree - + * the same for three lists + */ +#define forthree(cell1, list1, cell2, list2, cell3, list3) \ + for (ForThreeState cell1##__state = {(list1), (list2), (list3), 0}; \ + multi_for_advance_cell(cell1, cell1##__state, l1, i), \ + multi_for_advance_cell(cell2, cell1##__state, l2, i), \ + multi_for_advance_cell(cell3, cell1##__state, l3, i), \ + (cell1 != NULL && cell2 != NULL && cell3 != NULL); \ + cell1##__state.i++) + +/* + * forfour - + * the same for four lists + */ +#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4) \ + for (ForFourState cell1##__state = {(list1), (list2), (list3), (list4), 0}; \ + multi_for_advance_cell(cell1, cell1##__state, l1, i), \ + multi_for_advance_cell(cell2, cell1##__state, l2, i), \ + multi_for_advance_cell(cell3, cell1##__state, l3, i), \ + multi_for_advance_cell(cell4, cell1##__state, l4, i), \ + (cell1 != NULL && cell2 != NULL && cell3 != NULL && cell4 != NULL); \ + cell1##__state.i++) + +/* + * forfive - + * the same for five lists + */ +#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5) \ + for (ForFiveState cell1##__state = {(list1), (list2), (list3), (list4), (list5), 0}; \ + multi_for_advance_cell(cell1, cell1##__state, l1, i), \ + multi_for_advance_cell(cell2, cell1##__state, l2, i), \ + multi_for_advance_cell(cell3, cell1##__state, l3, i), \ + multi_for_advance_cell(cell4, cell1##__state, l4, i), \ + multi_for_advance_cell(cell5, cell1##__state, l5, i), \ + (cell1 != NULL && cell2 != NULL && cell3 != NULL && \ + cell4 != NULL && cell5 != NULL); \ + cell1##__state.i++) + +/* Functions in src/backend/nodes/list.c */ + +extern List *list_make1_impl(NodeTag t, ListCell datum1); +extern List *list_make2_impl(NodeTag t, ListCell datum1, ListCell datum2); +extern List *list_make3_impl(NodeTag t, ListCell datum1, ListCell datum2, + ListCell datum3); +extern List *list_make4_impl(NodeTag t, ListCell datum1, ListCell datum2, + ListCell datum3, ListCell datum4); +extern List *list_make5_impl(NodeTag t, ListCell datum1, ListCell datum2, + ListCell datum3, ListCell datum4, + ListCell datum5); + +extern pg_nodiscard List *lappend(List *list, void *datum); +extern pg_nodiscard List *lappend_int(List *list, int datum); +extern pg_nodiscard List *lappend_oid(List *list, Oid datum); + +extern pg_nodiscard List *list_insert_nth(List *list, int pos, void *datum); +extern pg_nodiscard List *list_insert_nth_int(List *list, int pos, int datum); +extern pg_nodiscard List *list_insert_nth_oid(List *list, int pos, Oid datum); + +extern pg_nodiscard List *lcons(void *datum, List *list); +extern pg_nodiscard List *lcons_int(int datum, List *list); +extern pg_nodiscard List *lcons_oid(Oid datum, List *list); + +extern pg_nodiscard List *list_concat(List *list1, const List *list2); +extern pg_nodiscard List *list_concat_copy(const List *list1, const List *list2); + +extern pg_nodiscard List *list_truncate(List *list, int new_size); + +extern bool list_member(const List *list, const void *datum); +extern bool list_member_ptr(const List *list, const void *datum); +extern bool list_member_int(const List *list, int datum); +extern bool list_member_oid(const List *list, Oid datum); + +extern pg_nodiscard List *list_delete(List *list, void *datum); +extern pg_nodiscard List *list_delete_ptr(List *list, void *datum); +extern pg_nodiscard List *list_delete_int(List *list, int datum); +extern pg_nodiscard List *list_delete_oid(List *list, Oid datum); +extern pg_nodiscard List *list_delete_first(List *list); +extern pg_nodiscard List *list_delete_last(List *list); +extern pg_nodiscard List *list_delete_first_n(List *list, int n); +extern pg_nodiscard List *list_delete_nth_cell(List *list, int n); +extern pg_nodiscard List *list_delete_cell(List *list, ListCell *cell); + +extern List *list_union(const List *list1, const List *list2); +extern List *list_union_ptr(const List *list1, const List *list2); +extern List *list_union_int(const List *list1, const List *list2); +extern List *list_union_oid(const List *list1, const List *list2); + +extern List *list_intersection(const List *list1, const List *list2); +extern List *list_intersection_int(const List *list1, const List *list2); + +/* currently, there's no need for list_intersection_ptr etc */ + +extern List *list_difference(const List *list1, const List *list2); +extern List *list_difference_ptr(const List *list1, const List *list2); +extern List *list_difference_int(const List *list1, const List *list2); +extern List *list_difference_oid(const List *list1, const List *list2); + +extern pg_nodiscard List *list_append_unique(List *list, void *datum); +extern pg_nodiscard List *list_append_unique_ptr(List *list, void *datum); +extern pg_nodiscard List *list_append_unique_int(List *list, int datum); +extern pg_nodiscard List *list_append_unique_oid(List *list, Oid datum); + +extern pg_nodiscard List *list_concat_unique(List *list1, const List *list2); +extern pg_nodiscard List *list_concat_unique_ptr(List *list1, const List *list2); +extern pg_nodiscard List *list_concat_unique_int(List *list1, const List *list2); +extern pg_nodiscard List *list_concat_unique_oid(List *list1, const List *list2); + +extern void list_deduplicate_oid(List *list); + +extern void list_free(List *list); +extern void list_free_deep(List *list); + +extern pg_nodiscard List *list_copy(const List *list); +extern pg_nodiscard List *list_copy_head(const List *oldlist, int len); +extern pg_nodiscard List *list_copy_tail(const List *list, int nskip); +extern pg_nodiscard List *list_copy_deep(const List *oldlist); + +typedef int (*list_sort_comparator) (const ListCell *a, const ListCell *b); +extern void list_sort(List *list, list_sort_comparator cmp); + +extern int list_int_cmp(const ListCell *p1, const ListCell *p2); +extern int list_oid_cmp(const ListCell *p1, const ListCell *p2); + +#endif /* PG_LIST_H */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h new file mode 100644 index 0000000..b778ba9 --- /dev/null +++ b/src/include/nodes/plannodes.h @@ -0,0 +1,1350 @@ +/*------------------------------------------------------------------------- + * + * plannodes.h + * definitions for query plan nodes + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/plannodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANNODES_H +#define PLANNODES_H + +#include "access/sdir.h" +#include "access/stratnum.h" +#include "lib/stringinfo.h" +#include "nodes/bitmapset.h" +#include "nodes/lockoptions.h" +#include "nodes/parsenodes.h" +#include "nodes/primnodes.h" + + +/* ---------------------------------------------------------------- + * node definitions + * ---------------------------------------------------------------- + */ + +/* ---------------- + * PlannedStmt node + * + * The output of the planner is a Plan tree headed by a PlannedStmt node. + * PlannedStmt holds the "one time" information needed by the executor. + * + * For simplicity in APIs, we also wrap utility statements in PlannedStmt + * nodes; in such cases, commandType == CMD_UTILITY, the statement itself + * is in the utilityStmt field, and the rest of the struct is mostly dummy. + * (We do use canSetTag, stmt_location, stmt_len, and possibly queryId.) + * ---------------- + */ +typedef struct PlannedStmt +{ + NodeTag type; + + CmdType commandType; /* select|insert|update|delete|merge|utility */ + + uint64 queryId; /* query identifier (copied from Query) */ + + bool hasReturning; /* is it insert|update|delete RETURNING? */ + + bool hasModifyingCTE; /* has insert|update|delete in WITH? */ + + bool canSetTag; /* do I set the command result tag? */ + + bool transientPlan; /* redo plan when TransactionXmin changes? */ + + bool dependsOnRole; /* is plan specific to current role? */ + + bool parallelModeNeeded; /* parallel mode required to execute? */ + + int jitFlags; /* which forms of JIT should be performed */ + + struct Plan *planTree; /* tree of Plan nodes */ + + List *rtable; /* list of RangeTblEntry nodes */ + + /* rtable indexes of target relations for INSERT/UPDATE/DELETE/MERGE */ + List *resultRelations; /* integer list of RT indexes, or NIL */ + + List *appendRelations; /* list of AppendRelInfo nodes */ + + List *subplans; /* Plan trees for SubPlan expressions; note + * that some could be NULL */ + + Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */ + + List *rowMarks; /* a list of PlanRowMark's */ + + List *relationOids; /* OIDs of relations the plan depends on */ + + List *invalItems; /* other dependencies, as PlanInvalItems */ + + List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */ + + Node *utilityStmt; /* non-null if this is utility stmt */ + + /* statement location in source string (copied from Query) */ + int stmt_location; /* start location, or -1 if unknown */ + int stmt_len; /* length in bytes; 0 means "rest of string" */ +} PlannedStmt; + +/* macro for fetching the Plan associated with a SubPlan node */ +#define exec_subplan_get_plan(plannedstmt, subplan) \ + ((Plan *) list_nth((plannedstmt)->subplans, (subplan)->plan_id - 1)) + + +/* ---------------- + * Plan node + * + * All plan nodes "derive" from the Plan structure by having the + * Plan structure as the first field. This ensures that everything works + * when nodes are cast to Plan's. (node pointers are frequently cast to Plan* + * when passed around generically in the executor) + * + * We never actually instantiate any Plan nodes; this is just the common + * abstract superclass for all Plan-type nodes. + * ---------------- + */ +typedef struct Plan +{ + NodeTag type; + + /* + * estimated execution costs for plan (see costsize.c for more info) + */ + Cost startup_cost; /* cost expended before fetching any tuples */ + Cost total_cost; /* total cost (assuming all tuples fetched) */ + + /* + * planner's estimate of result size of this plan step + */ + Cardinality plan_rows; /* number of rows plan is expected to emit */ + int plan_width; /* average row width in bytes */ + + /* + * information needed for parallel query + */ + bool parallel_aware; /* engage parallel-aware logic? */ + bool parallel_safe; /* OK to use as part of parallel plan? */ + + /* + * information needed for asynchronous execution + */ + bool async_capable; /* engage asynchronous-capable logic? */ + + /* + * Common structural data for all Plan types. + */ + int plan_node_id; /* unique across entire final plan tree */ + List *targetlist; /* target list to be computed at this node */ + List *qual; /* implicitly-ANDed qual conditions */ + struct Plan *lefttree; /* input plan tree(s) */ + struct Plan *righttree; + List *initPlan; /* Init Plan nodes (un-correlated expr + * subselects) */ + + /* + * Information for management of parameter-change-driven rescanning + * + * extParam includes the paramIDs of all external PARAM_EXEC params + * affecting this plan node or its children. setParam params from the + * node's initPlans are not included, but their extParams are. + * + * allParam includes all the extParam paramIDs, plus the IDs of local + * params that affect the node (i.e., the setParams of its initplans). + * These are _all_ the PARAM_EXEC params that affect this node. + */ + Bitmapset *extParam; + Bitmapset *allParam; +} Plan; + +/* ---------------- + * these are defined to avoid confusion problems with "left" + * and "right" and "inner" and "outer". The convention is that + * the "left" plan is the "outer" plan and the "right" plan is + * the inner plan, but these make the code more readable. + * ---------------- + */ +#define innerPlan(node) (((Plan *)(node))->righttree) +#define outerPlan(node) (((Plan *)(node))->lefttree) + + +/* ---------------- + * Result node - + * If no outer plan, evaluate a variable-free targetlist. + * If outer plan, return tuples from outer plan (after a level of + * projection as shown by targetlist). + * + * If resconstantqual isn't NULL, it represents a one-time qualification + * test (i.e., one that doesn't depend on any variables from the outer plan, + * so needs to be evaluated only once). + * ---------------- + */ +typedef struct Result +{ + Plan plan; + Node *resconstantqual; +} Result; + +/* ---------------- + * ProjectSet node - + * Apply a projection that includes set-returning functions to the + * output tuples of the outer plan. + * ---------------- + */ +typedef struct ProjectSet +{ + Plan plan; +} ProjectSet; + +/* ---------------- + * ModifyTable node - + * Apply rows produced by outer plan to result table(s), + * by inserting, updating, or deleting. + * + * If the originally named target table is a partitioned table or inheritance + * tree, both nominalRelation and rootRelation contain the RT index of the + * partition root or appendrel RTE, which is not otherwise mentioned in the + * plan. Otherwise rootRelation is zero. However, nominalRelation will + * always be set, as it's the rel that EXPLAIN should claim is the + * INSERT/UPDATE/DELETE/MERGE target. + * + * Note that rowMarks and epqParam are presumed to be valid for all the + * table(s); they can't contain any info that varies across tables. + * ---------------- + */ +typedef struct ModifyTable +{ + Plan plan; + CmdType operation; /* INSERT, UPDATE, DELETE, or MERGE */ + bool canSetTag; /* do we set the command tag/es_processed? */ + Index nominalRelation; /* Parent RT index for use of EXPLAIN */ + Index rootRelation; /* Root RT index, if partitioned/inherited */ + bool partColsUpdated; /* some part key in hierarchy updated? */ + List *resultRelations; /* integer list of RT indexes */ + List *updateColnosLists; /* per-target-table update_colnos lists */ + List *withCheckOptionLists; /* per-target-table WCO lists */ + List *returningLists; /* per-target-table RETURNING tlists */ + List *fdwPrivLists; /* per-target-table FDW private data lists */ + Bitmapset *fdwDirectModifyPlans; /* indices of FDW DM plans */ + List *rowMarks; /* PlanRowMarks (non-locking only) */ + int epqParam; /* ID of Param for EvalPlanQual re-eval */ + OnConflictAction onConflictAction; /* ON CONFLICT action */ + List *arbiterIndexes; /* List of ON CONFLICT arbiter index OIDs */ + List *onConflictSet; /* INSERT ON CONFLICT DO UPDATE targetlist */ + List *onConflictCols; /* target column numbers for onConflictSet */ + Node *onConflictWhere; /* WHERE for ON CONFLICT UPDATE */ + Index exclRelRTI; /* RTI of the EXCLUDED pseudo relation */ + List *exclRelTlist; /* tlist of the EXCLUDED pseudo relation */ + List *mergeActionLists; /* per-target-table lists of actions for + * MERGE */ +} ModifyTable; + +struct PartitionPruneInfo; /* forward reference to struct below */ + +/* ---------------- + * Append node - + * Generate the concatenation of the results of sub-plans. + * ---------------- + */ +typedef struct Append +{ + Plan plan; + Bitmapset *apprelids; /* RTIs of appendrel(s) formed by this node */ + List *appendplans; + int nasyncplans; /* # of asynchronous plans */ + + /* + * All 'appendplans' preceding this index are non-partial plans. All + * 'appendplans' from this index onwards are partial plans. + */ + int first_partial_plan; + + /* Info for run-time subplan pruning; NULL if we're not doing that */ + struct PartitionPruneInfo *part_prune_info; +} Append; + +/* ---------------- + * MergeAppend node - + * Merge the results of pre-sorted sub-plans to preserve the ordering. + * ---------------- + */ +typedef struct MergeAppend +{ + Plan plan; + Bitmapset *apprelids; /* RTIs of appendrel(s) formed by this node */ + List *mergeplans; + /* these fields are just like the sort-key info in struct Sort: */ + int numCols; /* number of sort-key columns */ + AttrNumber *sortColIdx; /* their indexes in the target list */ + Oid *sortOperators; /* OIDs of operators to sort them by */ + Oid *collations; /* OIDs of collations */ + bool *nullsFirst; /* NULLS FIRST/LAST directions */ + /* Info for run-time subplan pruning; NULL if we're not doing that */ + struct PartitionPruneInfo *part_prune_info; +} MergeAppend; + +/* ---------------- + * RecursiveUnion node - + * Generate a recursive union of two subplans. + * + * The "outer" subplan is always the non-recursive term, and the "inner" + * subplan is the recursive term. + * ---------------- + */ +typedef struct RecursiveUnion +{ + Plan plan; + int wtParam; /* ID of Param representing work table */ + /* Remaining fields are zero/null in UNION ALL case */ + int numCols; /* number of columns to check for + * duplicate-ness */ + AttrNumber *dupColIdx; /* their indexes in the target list */ + Oid *dupOperators; /* equality operators to compare with */ + Oid *dupCollations; + long numGroups; /* estimated number of groups in input */ +} RecursiveUnion; + +/* ---------------- + * BitmapAnd node - + * Generate the intersection of the results of sub-plans. + * + * The subplans must be of types that yield tuple bitmaps. The targetlist + * and qual fields of the plan are unused and are always NIL. + * ---------------- + */ +typedef struct BitmapAnd +{ + Plan plan; + List *bitmapplans; +} BitmapAnd; + +/* ---------------- + * BitmapOr node - + * Generate the union of the results of sub-plans. + * + * The subplans must be of types that yield tuple bitmaps. The targetlist + * and qual fields of the plan are unused and are always NIL. + * ---------------- + */ +typedef struct BitmapOr +{ + Plan plan; + bool isshared; + List *bitmapplans; +} BitmapOr; + +/* + * ========== + * Scan nodes + * ========== + */ +typedef struct Scan +{ + Plan plan; + Index scanrelid; /* relid is index into the range table */ +} Scan; + +/* ---------------- + * sequential scan node + * ---------------- + */ +typedef struct SeqScan +{ + Scan scan; +} SeqScan; + +/* ---------------- + * table sample scan node + * ---------------- + */ +typedef struct SampleScan +{ + Scan scan; + /* use struct pointer to avoid including parsenodes.h here */ + struct TableSampleClause *tablesample; +} SampleScan; + +/* ---------------- + * index scan node + * + * indexqualorig is an implicitly-ANDed list of index qual expressions, each + * in the same form it appeared in the query WHERE condition. Each should + * be of the form (indexkey OP comparisonval) or (comparisonval OP indexkey). + * The indexkey is a Var or expression referencing column(s) of the index's + * base table. The comparisonval might be any expression, but it won't use + * any columns of the base table. The expressions are ordered by index + * column position (but items referencing the same index column can appear + * in any order). indexqualorig is used at runtime only if we have to recheck + * a lossy indexqual. + * + * indexqual has the same form, but the expressions have been commuted if + * necessary to put the indexkeys on the left, and the indexkeys are replaced + * by Var nodes identifying the index columns (their varno is INDEX_VAR and + * their varattno is the index column number). + * + * indexorderbyorig is similarly the original form of any ORDER BY expressions + * that are being implemented by the index, while indexorderby is modified to + * have index column Vars on the left-hand side. Here, multiple expressions + * must appear in exactly the ORDER BY order, and this is not necessarily the + * index column order. Only the expressions are provided, not the auxiliary + * sort-order information from the ORDER BY SortGroupClauses; it's assumed + * that the sort ordering is fully determinable from the top-level operators. + * indexorderbyorig is used at runtime to recheck the ordering, if the index + * cannot calculate an accurate ordering. It is also needed for EXPLAIN. + * + * indexorderbyops is a list of the OIDs of the operators used to sort the + * ORDER BY expressions. This is used together with indexorderbyorig to + * recheck ordering at run time. (Note that indexorderby, indexorderbyorig, + * and indexorderbyops are used for amcanorderbyop cases, not amcanorder.) + * + * indexorderdir specifies the scan ordering, for indexscans on amcanorder + * indexes (for other indexes it should be "don't care"). + * ---------------- + */ +typedef struct IndexScan +{ + Scan scan; + Oid indexid; /* OID of index to scan */ + List *indexqual; /* list of index quals (usually OpExprs) */ + List *indexqualorig; /* the same in original form */ + List *indexorderby; /* list of index ORDER BY exprs */ + List *indexorderbyorig; /* the same in original form */ + List *indexorderbyops; /* OIDs of sort ops for ORDER BY exprs */ + ScanDirection indexorderdir; /* forward or backward or don't care */ +} IndexScan; + +/* ---------------- + * index-only scan node + * + * IndexOnlyScan is very similar to IndexScan, but it specifies an + * index-only scan, in which the data comes from the index not the heap. + * Because of this, *all* Vars in the plan node's targetlist, qual, and + * index expressions reference index columns and have varno = INDEX_VAR. + * + * We could almost use indexqual directly against the index's output tuple + * when rechecking lossy index operators, but that won't work for quals on + * index columns that are not retrievable. Hence, recheckqual is needed + * for rechecks: it expresses the same condition as indexqual, but using + * only index columns that are retrievable. (We will not generate an + * index-only scan if this is not possible. An example is that if an + * index has table column "x" in a retrievable index column "ind1", plus + * an expression f(x) in a non-retrievable column "ind2", an indexable + * query on f(x) will use "ind2" in indexqual and f(ind1) in recheckqual. + * Without the "ind1" column, an index-only scan would be disallowed.) + * + * We don't currently need a recheckable equivalent of indexorderby, + * because we don't support lossy operators in index ORDER BY. + * + * To help EXPLAIN interpret the index Vars for display, we provide + * indextlist, which represents the contents of the index as a targetlist + * with one TLE per index column. Vars appearing in this list reference + * the base table, and this is the only field in the plan node that may + * contain such Vars. Also, for the convenience of setrefs.c, TLEs in + * indextlist are marked as resjunk if they correspond to columns that + * the index AM cannot reconstruct. + * ---------------- + */ +typedef struct IndexOnlyScan +{ + Scan scan; + Oid indexid; /* OID of index to scan */ + List *indexqual; /* list of index quals (usually OpExprs) */ + List *recheckqual; /* index quals in recheckable form */ + List *indexorderby; /* list of index ORDER BY exprs */ + List *indextlist; /* TargetEntry list describing index's cols */ + ScanDirection indexorderdir; /* forward or backward or don't care */ +} IndexOnlyScan; + +/* ---------------- + * bitmap index scan node + * + * BitmapIndexScan delivers a bitmap of potential tuple locations; + * it does not access the heap itself. The bitmap is used by an + * ancestor BitmapHeapScan node, possibly after passing through + * intermediate BitmapAnd and/or BitmapOr nodes to combine it with + * the results of other BitmapIndexScans. + * + * The fields have the same meanings as for IndexScan, except we don't + * store a direction flag because direction is uninteresting. + * + * In a BitmapIndexScan plan node, the targetlist and qual fields are + * not used and are always NIL. The indexqualorig field is unused at + * run time too, but is saved for the benefit of EXPLAIN. + * ---------------- + */ +typedef struct BitmapIndexScan +{ + Scan scan; + Oid indexid; /* OID of index to scan */ + bool isshared; /* Create shared bitmap if set */ + List *indexqual; /* list of index quals (OpExprs) */ + List *indexqualorig; /* the same in original form */ +} BitmapIndexScan; + +/* ---------------- + * bitmap sequential scan node + * + * This needs a copy of the qual conditions being used by the input index + * scans because there are various cases where we need to recheck the quals; + * for example, when the bitmap is lossy about the specific rows on a page + * that meet the index condition. + * ---------------- + */ +typedef struct BitmapHeapScan +{ + Scan scan; + List *bitmapqualorig; /* index quals, in standard expr form */ +} BitmapHeapScan; + +/* ---------------- + * tid scan node + * + * tidquals is an implicitly OR'ed list of qual expressions of the form + * "CTID = pseudoconstant", or "CTID = ANY(pseudoconstant_array)", + * or a CurrentOfExpr for the relation. + * ---------------- + */ +typedef struct TidScan +{ + Scan scan; + List *tidquals; /* qual(s) involving CTID = something */ +} TidScan; + +/* ---------------- + * tid range scan node + * + * tidrangequals is an implicitly AND'ed list of qual expressions of the form + * "CTID relop pseudoconstant", where relop is one of >,>=,<,<=. + * ---------------- + */ +typedef struct TidRangeScan +{ + Scan scan; + List *tidrangequals; /* qual(s) involving CTID op something */ +} TidRangeScan; + +/* ---------------- + * subquery scan node + * + * SubqueryScan is for scanning the output of a sub-query in the range table. + * We often need an extra plan node above the sub-query's plan to perform + * expression evaluations (which we can't push into the sub-query without + * risking changing its semantics). Although we are not scanning a physical + * relation, we make this a descendant of Scan anyway for code-sharing + * purposes. + * + * SubqueryScanStatus caches the trivial_subqueryscan property of the node. + * SUBQUERY_SCAN_UNKNOWN means not yet determined. This is only used during + * planning. + * + * Note: we store the sub-plan in the type-specific subplan field, not in + * the generic lefttree field as you might expect. This is because we do + * not want plan-tree-traversal routines to recurse into the subplan without + * knowing that they are changing Query contexts. + * ---------------- + */ +typedef enum SubqueryScanStatus +{ + SUBQUERY_SCAN_UNKNOWN, + SUBQUERY_SCAN_TRIVIAL, + SUBQUERY_SCAN_NONTRIVIAL +} SubqueryScanStatus; + +typedef struct SubqueryScan +{ + Scan scan; + Plan *subplan; + SubqueryScanStatus scanstatus; +} SubqueryScan; + +/* ---------------- + * FunctionScan node + * ---------------- + */ +typedef struct FunctionScan +{ + Scan scan; + List *functions; /* list of RangeTblFunction nodes */ + bool funcordinality; /* WITH ORDINALITY */ +} FunctionScan; + +/* ---------------- + * ValuesScan node + * ---------------- + */ +typedef struct ValuesScan +{ + Scan scan; + List *values_lists; /* list of expression lists */ +} ValuesScan; + +/* ---------------- + * TableFunc scan node + * ---------------- + */ +typedef struct TableFuncScan +{ + Scan scan; + TableFunc *tablefunc; /* table function node */ +} TableFuncScan; + +/* ---------------- + * CteScan node + * ---------------- + */ +typedef struct CteScan +{ + Scan scan; + int ctePlanId; /* ID of init SubPlan for CTE */ + int cteParam; /* ID of Param representing CTE output */ +} CteScan; + +/* ---------------- + * NamedTuplestoreScan node + * ---------------- + */ +typedef struct NamedTuplestoreScan +{ + Scan scan; + char *enrname; /* Name given to Ephemeral Named Relation */ +} NamedTuplestoreScan; + +/* ---------------- + * WorkTableScan node + * ---------------- + */ +typedef struct WorkTableScan +{ + Scan scan; + int wtParam; /* ID of Param representing work table */ +} WorkTableScan; + +/* ---------------- + * ForeignScan node + * + * fdw_exprs and fdw_private are both under the control of the foreign-data + * wrapper, but fdw_exprs is presumed to contain expression trees and will + * be post-processed accordingly by the planner; fdw_private won't be. + * Note that everything in both lists must be copiable by copyObject(). + * One way to store an arbitrary blob of bytes is to represent it as a bytea + * Const. Usually, though, you'll be better off choosing a representation + * that can be dumped usefully by nodeToString(). + * + * fdw_scan_tlist is a targetlist describing the contents of the scan tuple + * returned by the FDW; it can be NIL if the scan tuple matches the declared + * rowtype of the foreign table, which is the normal case for a simple foreign + * table scan. (If the plan node represents a foreign join, fdw_scan_tlist + * is required since there is no rowtype available from the system catalogs.) + * When fdw_scan_tlist is provided, Vars in the node's tlist and quals must + * have varno INDEX_VAR, and their varattnos correspond to resnos in the + * fdw_scan_tlist (which are also column numbers in the actual scan tuple). + * fdw_scan_tlist is never actually executed; it just holds expression trees + * describing what is in the scan tuple's columns. + * + * fdw_recheck_quals should contain any quals which the core system passed to + * the FDW but which were not added to scan.plan.qual; that is, it should + * contain the quals being checked remotely. This is needed for correct + * behavior during EvalPlanQual rechecks. + * + * When the plan node represents a foreign join, scan.scanrelid is zero and + * fs_relids must be consulted to identify the join relation. (fs_relids + * is valid for simple scans as well, but will always match scan.scanrelid.) + * + * If the FDW's PlanDirectModify() callback decides to repurpose a ForeignScan + * node to perform the UPDATE or DELETE operation directly in the remote + * server, it sets 'operation' and 'resultRelation' to identify the operation + * type and target relation. Note that these fields are only set if the + * modification is performed *fully* remotely; otherwise, the modification is + * driven by a local ModifyTable node and 'operation' is left to CMD_SELECT. + * ---------------- + */ +typedef struct ForeignScan +{ + Scan scan; + CmdType operation; /* SELECT/INSERT/UPDATE/DELETE */ + Index resultRelation; /* direct modification target's RT index */ + Oid fs_server; /* OID of foreign server */ + List *fdw_exprs; /* expressions that FDW may evaluate */ + List *fdw_private; /* private data for FDW */ + List *fdw_scan_tlist; /* optional tlist describing scan tuple */ + List *fdw_recheck_quals; /* original quals not in scan.plan.qual */ + Bitmapset *fs_relids; /* RTIs generated by this scan */ + bool fsSystemCol; /* true if any "system column" is needed */ +} ForeignScan; + +/* ---------------- + * CustomScan node + * + * The comments for ForeignScan's fdw_exprs, fdw_private, fdw_scan_tlist, + * and fs_relids fields apply equally to CustomScan's custom_exprs, + * custom_private, custom_scan_tlist, and custom_relids fields. The + * convention of setting scan.scanrelid to zero for joins applies as well. + * + * Note that since Plan trees can be copied, custom scan providers *must* + * fit all plan data they need into those fields; embedding CustomScan in + * a larger struct will not work. + * ---------------- + */ +struct CustomScanMethods; + +typedef struct CustomScan +{ + Scan scan; + uint32 flags; /* mask of CUSTOMPATH_* flags, see + * nodes/extensible.h */ + List *custom_plans; /* list of Plan nodes, if any */ + List *custom_exprs; /* expressions that custom code may evaluate */ + List *custom_private; /* private data for custom code */ + List *custom_scan_tlist; /* optional tlist describing scan tuple */ + Bitmapset *custom_relids; /* RTIs generated by this scan */ + const struct CustomScanMethods *methods; +} CustomScan; + +/* + * ========== + * Join nodes + * ========== + */ + +/* ---------------- + * Join node + * + * jointype: rule for joining tuples from left and right subtrees + * inner_unique each outer tuple can match to no more than one inner tuple + * joinqual: qual conditions that came from JOIN/ON or JOIN/USING + * (plan.qual contains conditions that came from WHERE) + * + * When jointype is INNER, joinqual and plan.qual are semantically + * interchangeable. For OUTER jointypes, the two are *not* interchangeable; + * only joinqual is used to determine whether a match has been found for + * the purpose of deciding whether to generate null-extended tuples. + * (But plan.qual is still applied before actually returning a tuple.) + * For an outer join, only joinquals are allowed to be used as the merge + * or hash condition of a merge or hash join. + * + * inner_unique is set if the joinquals are such that no more than one inner + * tuple could match any given outer tuple. This allows the executor to + * skip searching for additional matches. (This must be provable from just + * the joinquals, ignoring plan.qual, due to where the executor tests it.) + * ---------------- + */ +typedef struct Join +{ + Plan plan; + JoinType jointype; + bool inner_unique; + List *joinqual; /* JOIN quals (in addition to plan.qual) */ +} Join; + +/* ---------------- + * nest loop join node + * + * The nestParams list identifies any executor Params that must be passed + * into execution of the inner subplan carrying values from the current row + * of the outer subplan. Currently we restrict these values to be simple + * Vars, but perhaps someday that'd be worth relaxing. (Note: during plan + * creation, the paramval can actually be a PlaceHolderVar expression; but it + * must be a Var with varno OUTER_VAR by the time it gets to the executor.) + * ---------------- + */ +typedef struct NestLoop +{ + Join join; + List *nestParams; /* list of NestLoopParam nodes */ +} NestLoop; + +typedef struct NestLoopParam +{ + NodeTag type; + int paramno; /* number of the PARAM_EXEC Param to set */ + Var *paramval; /* outer-relation Var to assign to Param */ +} NestLoopParam; + +/* ---------------- + * merge join node + * + * The expected ordering of each mergeable column is described by a btree + * opfamily OID, a collation OID, a direction (BTLessStrategyNumber or + * BTGreaterStrategyNumber) and a nulls-first flag. Note that the two sides + * of each mergeclause may be of different datatypes, but they are ordered the + * same way according to the common opfamily and collation. The operator in + * each mergeclause must be an equality operator of the indicated opfamily. + * ---------------- + */ +typedef struct MergeJoin +{ + Join join; + bool skip_mark_restore; /* Can we skip mark/restore calls? */ + List *mergeclauses; /* mergeclauses as expression trees */ + /* these are arrays, but have the same length as the mergeclauses list: */ + Oid *mergeFamilies; /* per-clause OIDs of btree opfamilies */ + Oid *mergeCollations; /* per-clause OIDs of collations */ + int *mergeStrategies; /* per-clause ordering (ASC or DESC) */ + bool *mergeNullsFirst; /* per-clause nulls ordering */ +} MergeJoin; + +/* ---------------- + * hash join node + * ---------------- + */ +typedef struct HashJoin +{ + Join join; + List *hashclauses; + List *hashoperators; + List *hashcollations; + + /* + * List of expressions to be hashed for tuples from the outer plan, to + * perform lookups in the hashtable over the inner plan. + */ + List *hashkeys; +} HashJoin; + +/* ---------------- + * materialization node + * ---------------- + */ +typedef struct Material +{ + Plan plan; +} Material; + +/* ---------------- + * memoize node + * ---------------- + */ +typedef struct Memoize +{ + Plan plan; + + int numKeys; /* size of the two arrays below */ + + Oid *hashOperators; /* hash operators for each key */ + Oid *collations; /* collations for each key */ + List *param_exprs; /* cache keys in the form of exprs containing + * parameters */ + bool singlerow; /* true if the cache entry should be marked as + * complete after we store the first tuple in + * it. */ + bool binary_mode; /* true when cache key should be compared bit + * by bit, false when using hash equality ops */ + uint32 est_entries; /* The maximum number of entries that the + * planner expects will fit in the cache, or 0 + * if unknown */ + Bitmapset *keyparamids; /* paramids from param_exprs */ +} Memoize; + +/* ---------------- + * sort node + * ---------------- + */ +typedef struct Sort +{ + Plan plan; + int numCols; /* number of sort-key columns */ + AttrNumber *sortColIdx; /* their indexes in the target list */ + Oid *sortOperators; /* OIDs of operators to sort them by */ + Oid *collations; /* OIDs of collations */ + bool *nullsFirst; /* NULLS FIRST/LAST directions */ +} Sort; + +/* ---------------- + * incremental sort node + * ---------------- + */ +typedef struct IncrementalSort +{ + Sort sort; + int nPresortedCols; /* number of presorted columns */ +} IncrementalSort; + +/* --------------- + * group node - + * Used for queries with GROUP BY (but no aggregates) specified. + * The input must be presorted according to the grouping columns. + * --------------- + */ +typedef struct Group +{ + Plan plan; + int numCols; /* number of grouping columns */ + AttrNumber *grpColIdx; /* their indexes in the target list */ + Oid *grpOperators; /* equality operators to compare with */ + Oid *grpCollations; +} Group; + +/* --------------- + * aggregate node + * + * An Agg node implements plain or grouped aggregation. For grouped + * aggregation, we can work with presorted input or unsorted input; + * the latter strategy uses an internal hashtable. + * + * Notice the lack of any direct info about the aggregate functions to be + * computed. They are found by scanning the node's tlist and quals during + * executor startup. (It is possible that there are no aggregate functions; + * this could happen if they get optimized away by constant-folding, or if + * we are using the Agg node to implement hash-based grouping.) + * --------------- + */ +typedef struct Agg +{ + Plan plan; + AggStrategy aggstrategy; /* basic strategy, see nodes.h */ + AggSplit aggsplit; /* agg-splitting mode, see nodes.h */ + int numCols; /* number of grouping columns */ + AttrNumber *grpColIdx; /* their indexes in the target list */ + Oid *grpOperators; /* equality operators to compare with */ + Oid *grpCollations; + long numGroups; /* estimated number of groups in input */ + uint64 transitionSpace; /* for pass-by-ref transition data */ + Bitmapset *aggParams; /* IDs of Params used in Aggref inputs */ + /* Note: planner provides numGroups & aggParams only in HASHED/MIXED case */ + List *groupingSets; /* grouping sets to use */ + List *chain; /* chained Agg/Sort nodes */ +} Agg; + +/* ---------------- + * window aggregate node + * ---------------- + */ +typedef struct WindowAgg +{ + Plan plan; + Index winref; /* ID referenced by window functions */ + int partNumCols; /* number of columns in partition clause */ + AttrNumber *partColIdx; /* their indexes in the target list */ + Oid *partOperators; /* equality operators for partition columns */ + Oid *partCollations; /* collations for partition columns */ + int ordNumCols; /* number of columns in ordering clause */ + AttrNumber *ordColIdx; /* their indexes in the target list */ + Oid *ordOperators; /* equality operators for ordering columns */ + Oid *ordCollations; /* collations for ordering columns */ + int frameOptions; /* frame_clause options, see WindowDef */ + Node *startOffset; /* expression for starting bound, if any */ + Node *endOffset; /* expression for ending bound, if any */ + List *runCondition; /* qual to help short-circuit execution */ + List *runConditionOrig; /* runCondition for display in EXPLAIN */ + /* these fields are used with RANGE offset PRECEDING/FOLLOWING: */ + Oid startInRangeFunc; /* in_range function for startOffset */ + Oid endInRangeFunc; /* in_range function for endOffset */ + Oid inRangeColl; /* collation for in_range tests */ + bool inRangeAsc; /* use ASC sort order for in_range tests? */ + bool inRangeNullsFirst; /* nulls sort first for in_range tests? */ + bool topWindow; /* false for all apart from the WindowAgg + * that's closest to the root of the plan */ +} WindowAgg; + +/* ---------------- + * unique node + * ---------------- + */ +typedef struct Unique +{ + Plan plan; + int numCols; /* number of columns to check for uniqueness */ + AttrNumber *uniqColIdx; /* their indexes in the target list */ + Oid *uniqOperators; /* equality operators to compare with */ + Oid *uniqCollations; /* collations for equality comparisons */ +} Unique; + +/* ------------ + * gather node + * + * Note: rescan_param is the ID of a PARAM_EXEC parameter slot. That slot + * will never actually contain a value, but the Gather node must flag it as + * having changed whenever it is rescanned. The child parallel-aware scan + * nodes are marked as depending on that parameter, so that the rescan + * machinery is aware that their output is likely to change across rescans. + * In some cases we don't need a rescan Param, so rescan_param is set to -1. + * ------------ + */ +typedef struct Gather +{ + Plan plan; + int num_workers; /* planned number of worker processes */ + int rescan_param; /* ID of Param that signals a rescan, or -1 */ + bool single_copy; /* don't execute plan more than once */ + bool invisible; /* suppress EXPLAIN display (for testing)? */ + Bitmapset *initParam; /* param id's of initplans which are referred + * at gather or one of it's child node */ +} Gather; + +/* ------------ + * gather merge node + * ------------ + */ +typedef struct GatherMerge +{ + Plan plan; + int num_workers; /* planned number of worker processes */ + int rescan_param; /* ID of Param that signals a rescan, or -1 */ + /* remaining fields are just like the sort-key info in struct Sort */ + int numCols; /* number of sort-key columns */ + AttrNumber *sortColIdx; /* their indexes in the target list */ + Oid *sortOperators; /* OIDs of operators to sort them by */ + Oid *collations; /* OIDs of collations */ + bool *nullsFirst; /* NULLS FIRST/LAST directions */ + Bitmapset *initParam; /* param id's of initplans which are referred + * at gather merge or one of it's child node */ +} GatherMerge; + +/* ---------------- + * hash build node + * + * If the executor is supposed to try to apply skew join optimization, then + * skewTable/skewColumn/skewInherit identify the outer relation's join key + * column, from which the relevant MCV statistics can be fetched. + * ---------------- + */ +typedef struct Hash +{ + Plan plan; + + /* + * List of expressions to be hashed for tuples from Hash's outer plan, + * needed to put them into the hashtable. + */ + List *hashkeys; /* hash keys for the hashjoin condition */ + Oid skewTable; /* outer join key's table OID, or InvalidOid */ + AttrNumber skewColumn; /* outer join key's column #, or zero */ + bool skewInherit; /* is outer join rel an inheritance tree? */ + /* all other info is in the parent HashJoin node */ + Cardinality rows_total; /* estimate total rows if parallel_aware */ +} Hash; + +/* ---------------- + * setop node + * ---------------- + */ +typedef struct SetOp +{ + Plan plan; + SetOpCmd cmd; /* what to do, see nodes.h */ + SetOpStrategy strategy; /* how to do it, see nodes.h */ + int numCols; /* number of columns to check for + * duplicate-ness */ + AttrNumber *dupColIdx; /* their indexes in the target list */ + Oid *dupOperators; /* equality operators to compare with */ + Oid *dupCollations; + AttrNumber flagColIdx; /* where is the flag column, if any */ + int firstFlag; /* flag value for first input relation */ + long numGroups; /* estimated number of groups in input */ +} SetOp; + +/* ---------------- + * lock-rows node + * + * rowMarks identifies the rels to be locked by this node; it should be + * a subset of the rowMarks listed in the top-level PlannedStmt. + * epqParam is a Param that all scan nodes below this one must depend on. + * It is used to force re-evaluation of the plan during EvalPlanQual. + * ---------------- + */ +typedef struct LockRows +{ + Plan plan; + List *rowMarks; /* a list of PlanRowMark's */ + int epqParam; /* ID of Param for EvalPlanQual re-eval */ +} LockRows; + +/* ---------------- + * limit node + * + * Note: as of Postgres 8.2, the offset and count expressions are expected + * to yield int8, rather than int4 as before. + * ---------------- + */ +typedef struct Limit +{ + Plan plan; + Node *limitOffset; /* OFFSET parameter, or NULL if none */ + Node *limitCount; /* COUNT parameter, or NULL if none */ + LimitOption limitOption; /* limit type */ + int uniqNumCols; /* number of columns to check for similarity */ + AttrNumber *uniqColIdx; /* their indexes in the target list */ + Oid *uniqOperators; /* equality operators to compare with */ + Oid *uniqCollations; /* collations for equality comparisons */ +} Limit; + + +/* + * RowMarkType - + * enums for types of row-marking operations + * + * The first four of these values represent different lock strengths that + * we can take on tuples according to SELECT FOR [KEY] UPDATE/SHARE requests. + * We support these on regular tables, as well as on foreign tables whose FDWs + * report support for late locking. For other foreign tables, any locking + * that might be done for such requests must happen during the initial row + * fetch; their FDWs provide no mechanism for going back to lock a row later. + * This means that the semantics will be a bit different than for a local + * table; in particular we are likely to lock more rows than would be locked + * locally, since remote rows will be locked even if they then fail + * locally-checked restriction or join quals. However, the prospect of + * doing a separate remote query to lock each selected row is usually pretty + * unappealing, so early locking remains a credible design choice for FDWs. + * + * When doing UPDATE/DELETE/MERGE/SELECT FOR UPDATE/SHARE, we have to uniquely + * identify all the source rows, not only those from the target relations, so + * that we can perform EvalPlanQual rechecking at need. For plain tables we + * can just fetch the TID, much as for a target relation; this case is + * represented by ROW_MARK_REFERENCE. Otherwise (for example for VALUES or + * FUNCTION scans) we have to copy the whole row value. ROW_MARK_COPY is + * pretty inefficient, since most of the time we'll never need the data; but + * fortunately the overhead is usually not performance-critical in practice. + * By default we use ROW_MARK_COPY for foreign tables, but if the FDW has + * a concept of rowid it can request to use ROW_MARK_REFERENCE instead. + * (Again, this probably doesn't make sense if a physical remote fetch is + * needed, but for FDWs that map to local storage it might be credible.) + */ +typedef enum RowMarkType +{ + ROW_MARK_EXCLUSIVE, /* obtain exclusive tuple lock */ + ROW_MARK_NOKEYEXCLUSIVE, /* obtain no-key exclusive tuple lock */ + ROW_MARK_SHARE, /* obtain shared tuple lock */ + ROW_MARK_KEYSHARE, /* obtain keyshare tuple lock */ + ROW_MARK_REFERENCE, /* just fetch the TID, don't lock it */ + ROW_MARK_COPY /* physically copy the row value */ +} RowMarkType; + +#define RowMarkRequiresRowShareLock(marktype) ((marktype) <= ROW_MARK_KEYSHARE) + +/* + * PlanRowMark - + * plan-time representation of FOR [KEY] UPDATE/SHARE clauses + * + * When doing UPDATE/DELETE/MERGE/SELECT FOR UPDATE/SHARE, we create a separate + * PlanRowMark node for each non-target relation in the query. Relations that + * are not specified as FOR UPDATE/SHARE are marked ROW_MARK_REFERENCE (if + * regular tables or supported foreign tables) or ROW_MARK_COPY (if not). + * + * Initially all PlanRowMarks have rti == prti and isParent == false. + * When the planner discovers that a relation is the root of an inheritance + * tree, it sets isParent true, and adds an additional PlanRowMark to the + * list for each child relation (including the target rel itself in its role + * as a child, if it is not a partitioned table). Any non-leaf partitioned + * child relations will also have entries with isParent = true. The child + * entries have rti == child rel's RT index and prti == top parent's RT index, + * and can therefore be recognized as children by the fact that prti != rti. + * The parent's allMarkTypes field gets the OR of (1<<markType) across all + * its children (this definition allows children to use different markTypes). + * + * The planner also adds resjunk output columns to the plan that carry + * information sufficient to identify the locked or fetched rows. When + * markType != ROW_MARK_COPY, these columns are named + * tableoid%u OID of table + * ctid%u TID of row + * The tableoid column is only present for an inheritance hierarchy. + * When markType == ROW_MARK_COPY, there is instead a single column named + * wholerow%u whole-row value of relation + * (An inheritance hierarchy could have all three resjunk output columns, + * if some children use a different markType than others.) + * In all three cases, %u represents the rowmark ID number (rowmarkId). + * This number is unique within a plan tree, except that child relation + * entries copy their parent's rowmarkId. (Assigning unique numbers + * means we needn't renumber rowmarkIds when flattening subqueries, which + * would require finding and renaming the resjunk columns as well.) + * Note this means that all tables in an inheritance hierarchy share the + * same resjunk column names. + */ +typedef struct PlanRowMark +{ + NodeTag type; + Index rti; /* range table index of markable relation */ + Index prti; /* range table index of parent relation */ + Index rowmarkId; /* unique identifier for resjunk columns */ + RowMarkType markType; /* see enum above */ + int allMarkTypes; /* OR of (1<<markType) for all children */ + LockClauseStrength strength; /* LockingClause's strength, or LCS_NONE */ + LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED options */ + bool isParent; /* true if this is a "dummy" parent entry */ +} PlanRowMark; + + +/* + * Node types to represent partition pruning information. + */ + +/* + * PartitionPruneInfo - Details required to allow the executor to prune + * partitions. + * + * Here we store mapping details to allow translation of a partitioned table's + * index as returned by the partition pruning code into subplan indexes for + * plan types which support arbitrary numbers of subplans, such as Append. + * We also store various details to tell the executor when it should be + * performing partition pruning. + * + * Each PartitionedRelPruneInfo describes the partitioning rules for a single + * partitioned table (a/k/a level of partitioning). Since a partitioning + * hierarchy could contain multiple levels, we represent it by a List of + * PartitionedRelPruneInfos, where the first entry represents the topmost + * partitioned table and additional entries represent non-leaf child + * partitions, ordered such that parents appear before their children. + * Then, since an Append-type node could have multiple partitioning + * hierarchies among its children, we have an unordered List of those Lists. + * + * prune_infos List of Lists containing PartitionedRelPruneInfo nodes, + * one sublist per run-time-prunable partition hierarchy + * appearing in the parent plan node's subplans. + * other_subplans Indexes of any subplans that are not accounted for + * by any of the PartitionedRelPruneInfo nodes in + * "prune_infos". These subplans must not be pruned. + */ +typedef struct PartitionPruneInfo +{ + NodeTag type; + List *prune_infos; + Bitmapset *other_subplans; +} PartitionPruneInfo; + +/* + * PartitionedRelPruneInfo - Details required to allow the executor to prune + * partitions for a single partitioned table. + * + * subplan_map[] and subpart_map[] are indexed by partition index of the + * partitioned table referenced by 'rtindex', the partition index being the + * order that the partitions are defined in the table's PartitionDesc. For a + * leaf partition p, subplan_map[p] contains the zero-based index of the + * partition's subplan in the parent plan's subplan list; it is -1 if the + * partition is non-leaf or has been pruned. For a non-leaf partition p, + * subpart_map[p] contains the zero-based index of that sub-partition's + * PartitionedRelPruneInfo in the hierarchy's PartitionedRelPruneInfo list; + * it is -1 if the partition is a leaf or has been pruned. Note that subplan + * indexes, as stored in 'subplan_map', are global across the parent plan + * node, but partition indexes are valid only within a particular hierarchy. + * relid_map[p] contains the partition's OID, or 0 if the partition was pruned. + */ +typedef struct PartitionedRelPruneInfo +{ + NodeTag type; + Index rtindex; /* RT index of partition rel for this level */ + Bitmapset *present_parts; /* Indexes of all partitions which subplans or + * subparts are present for */ + int nparts; /* Length of the following arrays: */ + int *subplan_map; /* subplan index by partition index, or -1 */ + int *subpart_map; /* subpart index by partition index, or -1 */ + Oid *relid_map; /* relation OID by partition index, or 0 */ + + /* + * initial_pruning_steps shows how to prune during executor startup (i.e., + * without use of any PARAM_EXEC Params); it is NIL if no startup pruning + * is required. exec_pruning_steps shows how to prune with PARAM_EXEC + * Params; it is NIL if no per-scan pruning is required. + */ + List *initial_pruning_steps; /* List of PartitionPruneStep */ + List *exec_pruning_steps; /* List of PartitionPruneStep */ + Bitmapset *execparamids; /* All PARAM_EXEC Param IDs in + * exec_pruning_steps */ +} PartitionedRelPruneInfo; + +/* + * Abstract Node type for partition pruning steps (there are no concrete + * Nodes of this type). + * + * step_id is the global identifier of the step within its pruning context. + */ +typedef struct PartitionPruneStep +{ + NodeTag type; + int step_id; +} PartitionPruneStep; + +/* + * PartitionPruneStepOp - Information to prune using a set of mutually ANDed + * OpExpr clauses + * + * This contains information extracted from up to partnatts OpExpr clauses, + * where partnatts is the number of partition key columns. 'opstrategy' is the + * strategy of the operator in the clause matched to the last partition key. + * 'exprs' contains expressions which comprise the lookup key to be passed to + * the partition bound search function. 'cmpfns' contains the OIDs of + * comparison functions used to compare aforementioned expressions with + * partition bounds. Both 'exprs' and 'cmpfns' contain the same number of + * items, up to partnatts items. + * + * Once we find the offset of a partition bound using the lookup key, we + * determine which partitions to include in the result based on the value of + * 'opstrategy'. For example, if it were equality, we'd return just the + * partition that would contain that key or a set of partitions if the key + * didn't consist of all partitioning columns. For non-equality strategies, + * we'd need to include other partitions as appropriate. + * + * 'nullkeys' is the set containing the offset of the partition keys (0 to + * partnatts - 1) that were matched to an IS NULL clause. This is only + * considered for hash partitioning as we need to pass which keys are null + * to the hash partition bound search function. It is never possible to + * have an expression be present in 'exprs' for a given partition key and + * the corresponding bit set in 'nullkeys'. + */ +typedef struct PartitionPruneStepOp +{ + PartitionPruneStep step; + + StrategyNumber opstrategy; + List *exprs; + List *cmpfns; + Bitmapset *nullkeys; +} PartitionPruneStepOp; + +/* + * PartitionPruneStepCombine - Information to prune using a BoolExpr clause + * + * For BoolExpr clauses, we combine the set of partitions determined for each + * of the argument clauses. + */ +typedef enum PartitionPruneCombineOp +{ + PARTPRUNE_COMBINE_UNION, + PARTPRUNE_COMBINE_INTERSECT +} PartitionPruneCombineOp; + +typedef struct PartitionPruneStepCombine +{ + PartitionPruneStep step; + + PartitionPruneCombineOp combineOp; + List *source_stepids; +} PartitionPruneStepCombine; + + +/* + * Plan invalidation info + * + * We track the objects on which a PlannedStmt depends in two ways: + * relations are recorded as a simple list of OIDs, and everything else + * is represented as a list of PlanInvalItems. A PlanInvalItem is designed + * to be used with the syscache invalidation mechanism, so it identifies a + * system catalog entry by cache ID and hash value. + */ +typedef struct PlanInvalItem +{ + NodeTag type; + int cacheId; /* a syscache ID, see utils/syscache.h */ + uint32 hashValue; /* hash value of object's cache lookup key */ +} PlanInvalItem; + +/* + * MonotonicFunction + * + * Allows the planner to track monotonic properties of functions. A function + * is monotonically increasing if a subsequent call cannot yield a lower value + * than the previous call. A monotonically decreasing function cannot yield a + * higher value on subsequent calls, and a function which is both must return + * the same value on each call. + */ +typedef enum MonotonicFunction +{ + MONOTONICFUNC_NONE = 0, + MONOTONICFUNC_INCREASING = (1 << 0), + MONOTONICFUNC_DECREASING = (1 << 1), + MONOTONICFUNC_BOTH = MONOTONICFUNC_INCREASING | MONOTONICFUNC_DECREASING +} MonotonicFunction; + +#endif /* PLANNODES_H */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h new file mode 100644 index 0000000..80ecf6c --- /dev/null +++ b/src/include/nodes/primnodes.h @@ -0,0 +1,1593 @@ +/*------------------------------------------------------------------------- + * + * primnodes.h + * Definitions for "primitive" node types, those that are used in more + * than one of the parse/plan/execute stages of the query pipeline. + * Currently, these are mostly nodes for executable expressions + * and join trees. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/primnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef PRIMNODES_H +#define PRIMNODES_H + +#include "access/attnum.h" +#include "nodes/bitmapset.h" +#include "nodes/pg_list.h" + + +/* ---------------------------------------------------------------- + * node definitions + * ---------------------------------------------------------------- + */ + +/* + * Alias - + * specifies an alias for a range variable; the alias might also + * specify renaming of columns within the table. + * + * Note: colnames is a list of String nodes. In Alias structs + * associated with RTEs, there may be entries corresponding to dropped + * columns; these are normally empty strings (""). See parsenodes.h for info. + */ +typedef struct Alias +{ + NodeTag type; + char *aliasname; /* aliased rel name (never qualified) */ + List *colnames; /* optional list of column aliases */ +} Alias; + +/* What to do at commit time for temporary relations */ +typedef enum OnCommitAction +{ + ONCOMMIT_NOOP, /* No ON COMMIT clause (do nothing) */ + ONCOMMIT_PRESERVE_ROWS, /* ON COMMIT PRESERVE ROWS (do nothing) */ + ONCOMMIT_DELETE_ROWS, /* ON COMMIT DELETE ROWS */ + ONCOMMIT_DROP /* ON COMMIT DROP */ +} OnCommitAction; + +/* + * RangeVar - range variable, used in FROM clauses + * + * Also used to represent table names in utility statements; there, the alias + * field is not used, and inh tells whether to apply the operation + * recursively to child tables. In some contexts it is also useful to carry + * a TEMP table indication here. + */ +typedef struct RangeVar +{ + NodeTag type; + char *catalogname; /* the catalog (database) name, or NULL */ + char *schemaname; /* the schema name, or NULL */ + char *relname; /* the relation/sequence name */ + bool inh; /* expand rel by inheritance? recursively act + * on children? */ + char relpersistence; /* see RELPERSISTENCE_* in pg_class.h */ + Alias *alias; /* table alias & optional column aliases */ + int location; /* token location, or -1 if unknown */ +} RangeVar; + +/* + * TableFunc - node for a table function, such as XMLTABLE. + * + * Entries in the ns_names list are either String nodes containing + * literal namespace names, or NULL pointers to represent DEFAULT. + */ +typedef struct TableFunc +{ + NodeTag type; + List *ns_uris; /* list of namespace URI expressions */ + List *ns_names; /* list of namespace names or NULL */ + Node *docexpr; /* input document expression */ + Node *rowexpr; /* row filter expression */ + List *colnames; /* column names (list of String) */ + List *coltypes; /* OID list of column type OIDs */ + List *coltypmods; /* integer list of column typmods */ + List *colcollations; /* OID list of column collation OIDs */ + List *colexprs; /* list of column filter expressions */ + List *coldefexprs; /* list of column default expressions */ + Bitmapset *notnulls; /* nullability flag for each output column */ + int ordinalitycol; /* counts from 0; -1 if none specified */ + int location; /* token location, or -1 if unknown */ +} TableFunc; + +/* + * IntoClause - target information for SELECT INTO, CREATE TABLE AS, and + * CREATE MATERIALIZED VIEW + * + * For CREATE MATERIALIZED VIEW, viewQuery is the parsed-but-not-rewritten + * SELECT Query for the view; otherwise it's NULL. (Although it's actually + * Query*, we declare it as Node* to avoid a forward reference.) + */ +typedef struct IntoClause +{ + NodeTag type; + + RangeVar *rel; /* target relation name */ + List *colNames; /* column names to assign, or NIL */ + char *accessMethod; /* table access method */ + List *options; /* options from WITH clause */ + OnCommitAction onCommit; /* what do we do at COMMIT? */ + char *tableSpaceName; /* table space to use, or NULL */ + Node *viewQuery; /* materialized view's SELECT query */ + bool skipData; /* true for WITH NO DATA */ +} IntoClause; + + +/* ---------------------------------------------------------------- + * node types for executable expressions + * ---------------------------------------------------------------- + */ + +/* + * Expr - generic superclass for executable-expression nodes + * + * All node types that are used in executable expression trees should derive + * from Expr (that is, have Expr as their first field). Since Expr only + * contains NodeTag, this is a formality, but it is an easy form of + * documentation. See also the ExprState node types in execnodes.h. + */ +typedef struct Expr +{ + NodeTag type; +} Expr; + +/* + * Var - expression node representing a variable (ie, a table column) + * + * In the parser and planner, varno and varattno identify the semantic + * referent, which is a base-relation column unless the reference is to a join + * USING column that isn't semantically equivalent to either join input column + * (because it is a FULL join or the input column requires a type coercion). + * In those cases varno and varattno refer to the JOIN RTE. (Early in the + * planner, we replace such join references by the implied expression; but up + * till then we want join reference Vars to keep their original identity for + * query-printing purposes.) + * + * At the end of planning, Var nodes appearing in upper-level plan nodes are + * reassigned to point to the outputs of their subplans; for example, in a + * join node varno becomes INNER_VAR or OUTER_VAR and varattno becomes the + * index of the proper element of that subplan's target list. Similarly, + * INDEX_VAR is used to identify Vars that reference an index column rather + * than a heap column. (In ForeignScan and CustomScan plan nodes, INDEX_VAR + * is abused to signify references to columns of a custom scan tuple type.) + * + * ROWID_VAR is used in the planner to identify nonce variables that carry + * row identity information during UPDATE/DELETE/MERGE. This value should + * never be seen outside the planner. + * + * In the parser, varnosyn and varattnosyn are either identical to + * varno/varattno, or they specify the column's position in an aliased JOIN + * RTE that hides the semantic referent RTE's refname. This is a syntactic + * identifier as opposed to the semantic identifier; it tells ruleutils.c + * how to print the Var properly. varnosyn/varattnosyn retain their values + * throughout planning and execution, so they are particularly helpful to + * identify Vars when debugging. Note, however, that a Var that is generated + * in the planner and doesn't correspond to any simple relation column may + * have varnosyn = varattnosyn = 0. + */ +#define INNER_VAR (-1) /* reference to inner subplan */ +#define OUTER_VAR (-2) /* reference to outer subplan */ +#define INDEX_VAR (-3) /* reference to index column */ +#define ROWID_VAR (-4) /* row identity column during planning */ + +#define IS_SPECIAL_VARNO(varno) ((int) (varno) < 0) + +/* Symbols for the indexes of the special RTE entries in rules */ +#define PRS2_OLD_VARNO 1 +#define PRS2_NEW_VARNO 2 + +typedef struct Var +{ + Expr xpr; + int varno; /* index of this var's relation in the range + * table, or INNER_VAR/OUTER_VAR/etc */ + AttrNumber varattno; /* attribute number of this var, or zero for + * all attrs ("whole-row Var") */ + Oid vartype; /* pg_type OID for the type of this var */ + int32 vartypmod; /* pg_attribute typmod value */ + Oid varcollid; /* OID of collation, or InvalidOid if none */ + Index varlevelsup; /* for subquery variables referencing outer + * relations; 0 in a normal var, >0 means N + * levels up */ + Index varnosyn; /* syntactic relation index (0 if unknown) */ + AttrNumber varattnosyn; /* syntactic attribute number */ + int location; /* token location, or -1 if unknown */ +} Var; + +/* + * Const + * + * Note: for varlena data types, we make a rule that a Const node's value + * must be in non-extended form (4-byte header, no compression or external + * references). This ensures that the Const node is self-contained and makes + * it more likely that equal() will see logically identical values as equal. + */ +typedef struct Const +{ + Expr xpr; + Oid consttype; /* pg_type OID of the constant's datatype */ + int32 consttypmod; /* typmod value, if any */ + Oid constcollid; /* OID of collation, or InvalidOid if none */ + int constlen; /* typlen of the constant's datatype */ + Datum constvalue; /* the constant's value */ + bool constisnull; /* whether the constant is null (if true, + * constvalue is undefined) */ + bool constbyval; /* whether this datatype is passed by value. + * If true, then all the information is stored + * in the Datum. If false, then the Datum + * contains a pointer to the information. */ + int location; /* token location, or -1 if unknown */ +} Const; + +/* + * Param + * + * paramkind specifies the kind of parameter. The possible values + * for this field are: + * + * PARAM_EXTERN: The parameter value is supplied from outside the plan. + * Such parameters are numbered from 1 to n. + * + * PARAM_EXEC: The parameter is an internal executor parameter, used + * for passing values into and out of sub-queries or from + * nestloop joins to their inner scans. + * For historical reasons, such parameters are numbered from 0. + * These numbers are independent of PARAM_EXTERN numbers. + * + * PARAM_SUBLINK: The parameter represents an output column of a SubLink + * node's sub-select. The column number is contained in the + * `paramid' field. (This type of Param is converted to + * PARAM_EXEC during planning.) + * + * PARAM_MULTIEXPR: Like PARAM_SUBLINK, the parameter represents an + * output column of a SubLink node's sub-select, but here, the + * SubLink is always a MULTIEXPR SubLink. The high-order 16 bits + * of the `paramid' field contain the SubLink's subLinkId, and + * the low-order 16 bits contain the column number. (This type + * of Param is also converted to PARAM_EXEC during planning.) + */ +typedef enum ParamKind +{ + PARAM_EXTERN, + PARAM_EXEC, + PARAM_SUBLINK, + PARAM_MULTIEXPR +} ParamKind; + +typedef struct Param +{ + Expr xpr; + ParamKind paramkind; /* kind of parameter. See above */ + int paramid; /* numeric ID for parameter */ + Oid paramtype; /* pg_type OID of parameter's datatype */ + int32 paramtypmod; /* typmod value, if known */ + Oid paramcollid; /* OID of collation, or InvalidOid if none */ + int location; /* token location, or -1 if unknown */ +} Param; + +/* + * Aggref + * + * The aggregate's args list is a targetlist, ie, a list of TargetEntry nodes. + * + * For a normal (non-ordered-set) aggregate, the non-resjunk TargetEntries + * represent the aggregate's regular arguments (if any) and resjunk TLEs can + * be added at the end to represent ORDER BY expressions that are not also + * arguments. As in a top-level Query, the TLEs can be marked with + * ressortgroupref indexes to let them be referenced by SortGroupClause + * entries in the aggorder and/or aggdistinct lists. This represents ORDER BY + * and DISTINCT operations to be applied to the aggregate input rows before + * they are passed to the transition function. The grammar only allows a + * simple "DISTINCT" specifier for the arguments, but we use the full + * query-level representation to allow more code sharing. + * + * For an ordered-set aggregate, the args list represents the WITHIN GROUP + * (aggregated) arguments, all of which will be listed in the aggorder list. + * DISTINCT is not supported in this case, so aggdistinct will be NIL. + * The direct arguments appear in aggdirectargs (as a list of plain + * expressions, not TargetEntry nodes). + * + * aggtranstype is the data type of the state transition values for this + * aggregate (resolved to an actual type, if agg's transtype is polymorphic). + * This is determined during planning and is InvalidOid before that. + * + * aggargtypes is an OID list of the data types of the direct and regular + * arguments. Normally it's redundant with the aggdirectargs and args lists, + * but in a combining aggregate, it's not because the args list has been + * replaced with a single argument representing the partial-aggregate + * transition values. + * + * aggsplit indicates the expected partial-aggregation mode for the Aggref's + * parent plan node. It's always set to AGGSPLIT_SIMPLE in the parser, but + * the planner might change it to something else. We use this mainly as + * a crosscheck that the Aggrefs match the plan; but note that when aggsplit + * indicates a non-final mode, aggtype reflects the transition data type + * not the SQL-level output type of the aggregate. + * + * aggno and aggtransno are -1 in the parse stage, and are set in planning. + * Aggregates with the same 'aggno' represent the same aggregate expression, + * and can share the result. Aggregates with same 'transno' but different + * 'aggno' can share the same transition state, only the final function needs + * to be called separately. + */ +typedef struct Aggref +{ + Expr xpr; + Oid aggfnoid; /* pg_proc Oid of the aggregate */ + Oid aggtype; /* type Oid of result of the aggregate */ + Oid aggcollid; /* OID of collation of result */ + Oid inputcollid; /* OID of collation that function should use */ + Oid aggtranstype; /* type Oid of aggregate's transition value */ + List *aggargtypes; /* type Oids of direct and aggregated args */ + List *aggdirectargs; /* direct arguments, if an ordered-set agg */ + List *args; /* aggregated arguments and sort expressions */ + List *aggorder; /* ORDER BY (list of SortGroupClause) */ + List *aggdistinct; /* DISTINCT (list of SortGroupClause) */ + Expr *aggfilter; /* FILTER expression, if any */ + bool aggstar; /* true if argument list was really '*' */ + bool aggvariadic; /* true if variadic arguments have been + * combined into an array last argument */ + char aggkind; /* aggregate kind (see pg_aggregate.h) */ + Index agglevelsup; /* > 0 if agg belongs to outer query */ + AggSplit aggsplit; /* expected agg-splitting mode of parent Agg */ + int aggno; /* unique ID within the Agg node */ + int aggtransno; /* unique ID of transition state in the Agg */ + int location; /* token location, or -1 if unknown */ +} Aggref; + +/* + * GroupingFunc + * + * A GroupingFunc is a GROUPING(...) expression, which behaves in many ways + * like an aggregate function (e.g. it "belongs" to a specific query level, + * which might not be the one immediately containing it), but also differs in + * an important respect: it never evaluates its arguments, they merely + * designate expressions from the GROUP BY clause of the query level to which + * it belongs. + * + * The spec defines the evaluation of GROUPING() purely by syntactic + * replacement, but we make it a real expression for optimization purposes so + * that one Agg node can handle multiple grouping sets at once. Evaluating the + * result only needs the column positions to check against the grouping set + * being projected. However, for EXPLAIN to produce meaningful output, we have + * to keep the original expressions around, since expression deparse does not + * give us any feasible way to get at the GROUP BY clause. + * + * Also, we treat two GroupingFunc nodes as equal if they have equal arguments + * lists and agglevelsup, without comparing the refs and cols annotations. + * + * In raw parse output we have only the args list; parse analysis fills in the + * refs list, and the planner fills in the cols list. + */ +typedef struct GroupingFunc +{ + Expr xpr; + List *args; /* arguments, not evaluated but kept for + * benefit of EXPLAIN etc. */ + List *refs; /* ressortgrouprefs of arguments */ + List *cols; /* actual column positions set by planner */ + Index agglevelsup; /* same as Aggref.agglevelsup */ + int location; /* token location */ +} GroupingFunc; + +/* + * WindowFunc + */ +typedef struct WindowFunc +{ + Expr xpr; + Oid winfnoid; /* pg_proc Oid of the function */ + Oid wintype; /* type Oid of result of the window function */ + Oid wincollid; /* OID of collation of result */ + Oid inputcollid; /* OID of collation that function should use */ + List *args; /* arguments to the window function */ + Expr *aggfilter; /* FILTER expression, if any */ + Index winref; /* index of associated WindowClause */ + bool winstar; /* true if argument list was really '*' */ + bool winagg; /* is function a simple aggregate? */ + int location; /* token location, or -1 if unknown */ +} WindowFunc; + +/* + * SubscriptingRef: describes a subscripting operation over a container + * (array, etc). + * + * A SubscriptingRef can describe fetching a single element from a container, + * fetching a part of a container (e.g. an array slice), storing a single + * element into a container, or storing a slice. The "store" cases work with + * an initial container value and a source value that is inserted into the + * appropriate part of the container; the result of the operation is an + * entire new modified container value. + * + * If reflowerindexpr = NIL, then we are fetching or storing a single container + * element at the subscripts given by refupperindexpr. Otherwise we are + * fetching or storing a container slice, that is a rectangular subcontainer + * with lower and upper bounds given by the index expressions. + * reflowerindexpr must be the same length as refupperindexpr when it + * is not NIL. + * + * In the slice case, individual expressions in the subscript lists can be + * NULL, meaning "substitute the array's current lower or upper bound". + * (Non-array containers may or may not support this.) + * + * refcontainertype is the actual container type that determines the + * subscripting semantics. (This will generally be either the exposed type of + * refexpr, or the base type if that is a domain.) refelemtype is the type of + * the container's elements; this is saved for the use of the subscripting + * functions, but is not used by the core code. refrestype, reftypmod, and + * refcollid describe the type of the SubscriptingRef's result. In a store + * expression, refrestype will always match refcontainertype; in a fetch, + * it could be refelemtype for an element fetch, or refcontainertype for a + * slice fetch, or possibly something else as determined by type-specific + * subscripting logic. Likewise, reftypmod and refcollid will match the + * container's properties in a store, but could be different in a fetch. + * + * Note: for the cases where a container is returned, if refexpr yields a R/W + * expanded container, then the implementation is allowed to modify that + * object in-place and return the same object. + */ +typedef struct SubscriptingRef +{ + Expr xpr; + Oid refcontainertype; /* type of the container proper */ + Oid refelemtype; /* the container type's pg_type.typelem */ + Oid refrestype; /* type of the SubscriptingRef's result */ + int32 reftypmod; /* typmod of the result */ + Oid refcollid; /* collation of result, or InvalidOid if none */ + List *refupperindexpr; /* expressions that evaluate to upper + * container indexes */ + List *reflowerindexpr; /* expressions that evaluate to lower + * container indexes, or NIL for single + * container element */ + Expr *refexpr; /* the expression that evaluates to a + * container value */ + Expr *refassgnexpr; /* expression for the source value, or NULL if + * fetch */ +} SubscriptingRef; + +/* + * CoercionContext - distinguishes the allowed set of type casts + * + * NB: ordering of the alternatives is significant; later (larger) values + * allow more casts than earlier ones. + */ +typedef enum CoercionContext +{ + COERCION_IMPLICIT, /* coercion in context of expression */ + COERCION_ASSIGNMENT, /* coercion in context of assignment */ + COERCION_PLPGSQL, /* if no assignment cast, use CoerceViaIO */ + COERCION_EXPLICIT /* explicit cast operation */ +} CoercionContext; + +/* + * CoercionForm - how to display a FuncExpr or related node + * + * "Coercion" is a bit of a misnomer, since this value records other + * special syntaxes besides casts, but for now we'll keep this naming. + * + * NB: equal() ignores CoercionForm fields, therefore this *must* not carry + * any semantically significant information. We need that behavior so that + * the planner will consider equivalent implicit and explicit casts to be + * equivalent. In cases where those actually behave differently, the coercion + * function's arguments will be different. + */ +typedef enum CoercionForm +{ + COERCE_EXPLICIT_CALL, /* display as a function call */ + COERCE_EXPLICIT_CAST, /* display as an explicit cast */ + COERCE_IMPLICIT_CAST, /* implicit cast, so hide it */ + COERCE_SQL_SYNTAX /* display with SQL-mandated special syntax */ +} CoercionForm; + +/* + * FuncExpr - expression node for a function call + */ +typedef struct FuncExpr +{ + Expr xpr; + Oid funcid; /* PG_PROC OID of the function */ + Oid funcresulttype; /* PG_TYPE OID of result value */ + bool funcretset; /* true if function returns set */ + bool funcvariadic; /* true if variadic arguments have been + * combined into an array last argument */ + CoercionForm funcformat; /* how to display this function call */ + Oid funccollid; /* OID of collation of result */ + Oid inputcollid; /* OID of collation that function should use */ + List *args; /* arguments to the function */ + int location; /* token location, or -1 if unknown */ +} FuncExpr; + +/* + * NamedArgExpr - a named argument of a function + * + * This node type can only appear in the args list of a FuncCall or FuncExpr + * node. We support pure positional call notation (no named arguments), + * named notation (all arguments are named), and mixed notation (unnamed + * arguments followed by named ones). + * + * Parse analysis sets argnumber to the positional index of the argument, + * but doesn't rearrange the argument list. + * + * The planner will convert argument lists to pure positional notation + * during expression preprocessing, so execution never sees a NamedArgExpr. + */ +typedef struct NamedArgExpr +{ + Expr xpr; + Expr *arg; /* the argument expression */ + char *name; /* the name */ + int argnumber; /* argument's number in positional notation */ + int location; /* argument name location, or -1 if unknown */ +} NamedArgExpr; + +/* + * OpExpr - expression node for an operator invocation + * + * Semantically, this is essentially the same as a function call. + * + * Note that opfuncid is not necessarily filled in immediately on creation + * of the node. The planner makes sure it is valid before passing the node + * tree to the executor, but during parsing/planning opfuncid can be 0. + */ +typedef struct OpExpr +{ + Expr xpr; + Oid opno; /* PG_OPERATOR OID of the operator */ + Oid opfuncid; /* PG_PROC OID of underlying function */ + Oid opresulttype; /* PG_TYPE OID of result value */ + bool opretset; /* true if operator returns set */ + Oid opcollid; /* OID of collation of result */ + Oid inputcollid; /* OID of collation that operator should use */ + List *args; /* arguments to the operator (1 or 2) */ + int location; /* token location, or -1 if unknown */ +} OpExpr; + +/* + * DistinctExpr - expression node for "x IS DISTINCT FROM y" + * + * Except for the nodetag, this is represented identically to an OpExpr + * referencing the "=" operator for x and y. + * We use "=", not the more obvious "<>", because more datatypes have "=" + * than "<>". This means the executor must invert the operator result. + * Note that the operator function won't be called at all if either input + * is NULL, since then the result can be determined directly. + */ +typedef OpExpr DistinctExpr; + +/* + * NullIfExpr - a NULLIF expression + * + * Like DistinctExpr, this is represented the same as an OpExpr referencing + * the "=" operator for x and y. + */ +typedef OpExpr NullIfExpr; + +/* + * ScalarArrayOpExpr - expression node for "scalar op ANY/ALL (array)" + * + * The operator must yield boolean. It is applied to the left operand + * and each element of the righthand array, and the results are combined + * with OR or AND (for ANY or ALL respectively). The node representation + * is almost the same as for the underlying operator, but we need a useOr + * flag to remember whether it's ANY or ALL, and we don't have to store + * the result type (or the collation) because it must be boolean. + * + * A ScalarArrayOpExpr with a valid hashfuncid is evaluated during execution + * by building a hash table containing the Const values from the RHS arg. + * This table is probed during expression evaluation. The planner will set + * hashfuncid to the hash function which must be used to build and probe the + * hash table. The executor determines if it should use hash-based checks or + * the more traditional means based on if the hashfuncid is set or not. + * + * When performing hashed NOT IN, the negfuncid will also be set to the + * equality function which the hash table must use to build and probe the hash + * table. opno and opfuncid will remain set to the <> operator and its + * corresponding function and won't be used during execution. For + * non-hashtable based NOT INs, negfuncid will be set to InvalidOid. See + * convert_saop_to_hashed_saop(). + */ +typedef struct ScalarArrayOpExpr +{ + Expr xpr; + Oid opno; /* PG_OPERATOR OID of the operator */ + Oid opfuncid; /* PG_PROC OID of comparison function */ + Oid hashfuncid; /* PG_PROC OID of hash func or InvalidOid */ + Oid negfuncid; /* PG_PROC OID of negator of opfuncid function + * or InvalidOid. See above */ + bool useOr; /* true for ANY, false for ALL */ + Oid inputcollid; /* OID of collation that operator should use */ + List *args; /* the scalar and array operands */ + int location; /* token location, or -1 if unknown */ +} ScalarArrayOpExpr; + +/* + * BoolExpr - expression node for the basic Boolean operators AND, OR, NOT + * + * Notice the arguments are given as a List. For NOT, of course the list + * must always have exactly one element. For AND and OR, there can be two + * or more arguments. + */ +typedef enum BoolExprType +{ + AND_EXPR, OR_EXPR, NOT_EXPR +} BoolExprType; + +typedef struct BoolExpr +{ + Expr xpr; + BoolExprType boolop; + List *args; /* arguments to this expression */ + int location; /* token location, or -1 if unknown */ +} BoolExpr; + +/* + * SubLink + * + * A SubLink represents a subselect appearing in an expression, and in some + * cases also the combining operator(s) just above it. The subLinkType + * indicates the form of the expression represented: + * EXISTS_SUBLINK EXISTS(SELECT ...) + * ALL_SUBLINK (lefthand) op ALL (SELECT ...) + * ANY_SUBLINK (lefthand) op ANY (SELECT ...) + * ROWCOMPARE_SUBLINK (lefthand) op (SELECT ...) + * EXPR_SUBLINK (SELECT with single targetlist item ...) + * MULTIEXPR_SUBLINK (SELECT with multiple targetlist items ...) + * ARRAY_SUBLINK ARRAY(SELECT with single targetlist item ...) + * CTE_SUBLINK WITH query (never actually part of an expression) + * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the + * same length as the subselect's targetlist. ROWCOMPARE will *always* have + * a list with more than one entry; if the subselect has just one target + * then the parser will create an EXPR_SUBLINK instead (and any operator + * above the subselect will be represented separately). + * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most + * one row (if it returns no rows, the result is NULL). + * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean + * results. ALL and ANY combine the per-row results using AND and OR + * semantics respectively. + * ARRAY requires just one target column, and creates an array of the target + * column's type using any number of rows resulting from the subselect. + * + * SubLink is classed as an Expr node, but it is not actually executable; + * it must be replaced in the expression tree by a SubPlan node during + * planning. + * + * NOTE: in the raw output of gram.y, testexpr contains just the raw form + * of the lefthand expression (if any), and operName is the String name of + * the combining operator. Also, subselect is a raw parsetree. During parse + * analysis, the parser transforms testexpr into a complete boolean expression + * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the + * output columns of the subselect. And subselect is transformed to a Query. + * This is the representation seen in saved rules and in the rewriter. + * + * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName + * are unused and are always null. + * + * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in + * other SubLinks. This number identifies different multiple-assignment + * subqueries within an UPDATE statement's SET list. It is unique only + * within a particular targetlist. The output column(s) of the MULTIEXPR + * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist. + * + * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used + * in SubPlans generated for WITH subqueries. + */ +typedef enum SubLinkType +{ + EXISTS_SUBLINK, + ALL_SUBLINK, + ANY_SUBLINK, + ROWCOMPARE_SUBLINK, + EXPR_SUBLINK, + MULTIEXPR_SUBLINK, + ARRAY_SUBLINK, + CTE_SUBLINK /* for SubPlans only */ +} SubLinkType; + + +typedef struct SubLink +{ + Expr xpr; + SubLinkType subLinkType; /* see above */ + int subLinkId; /* ID (1..n); 0 if not MULTIEXPR */ + Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */ + List *operName; /* originally specified operator name */ + Node *subselect; /* subselect as Query* or raw parsetree */ + int location; /* token location, or -1 if unknown */ +} SubLink; + +/* + * SubPlan - executable expression node for a subplan (sub-SELECT) + * + * The planner replaces SubLink nodes in expression trees with SubPlan + * nodes after it has finished planning the subquery. SubPlan references + * a sub-plantree stored in the subplans list of the toplevel PlannedStmt. + * (We avoid a direct link to make it easier to copy expression trees + * without causing multiple processing of the subplan.) + * + * In an ordinary subplan, testexpr points to an executable expression + * (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining + * operator(s); the left-hand arguments are the original lefthand expressions, + * and the right-hand arguments are PARAM_EXEC Param nodes representing the + * outputs of the sub-select. (NOTE: runtime coercion functions may be + * inserted as well.) This is just the same expression tree as testexpr in + * the original SubLink node, but the PARAM_SUBLINK nodes are replaced by + * suitably numbered PARAM_EXEC nodes. + * + * If the sub-select becomes an initplan rather than a subplan, the executable + * expression is part of the outer plan's expression tree (and the SubPlan + * node itself is not, but rather is found in the outer plan's initPlan + * list). In this case testexpr is NULL to avoid duplication. + * + * The planner also derives lists of the values that need to be passed into + * and out of the subplan. Input values are represented as a list "args" of + * expressions to be evaluated in the outer-query context (currently these + * args are always just Vars, but in principle they could be any expression). + * The values are assigned to the global PARAM_EXEC params indexed by parParam + * (the parParam and args lists must have the same ordering). setParam is a + * list of the PARAM_EXEC params that are computed by the sub-select, if it + * is an initplan or MULTIEXPR plan; they are listed in order by sub-select + * output column position. (parParam and setParam are integer Lists, not + * Bitmapsets, because their ordering is significant.) + * + * Also, the planner computes startup and per-call costs for use of the + * SubPlan. Note that these include the cost of the subquery proper, + * evaluation of the testexpr if any, and any hashtable management overhead. + */ +typedef struct SubPlan +{ + Expr xpr; + /* Fields copied from original SubLink: */ + SubLinkType subLinkType; /* see above */ + /* The combining operators, transformed to an executable expression: */ + Node *testexpr; /* OpExpr or RowCompareExpr expression tree */ + List *paramIds; /* IDs of Params embedded in the above */ + /* Identification of the Plan tree to use: */ + int plan_id; /* Index (from 1) in PlannedStmt.subplans */ + /* Identification of the SubPlan for EXPLAIN and debugging purposes: */ + char *plan_name; /* A name assigned during planning */ + /* Extra data useful for determining subplan's output type: */ + Oid firstColType; /* Type of first column of subplan result */ + int32 firstColTypmod; /* Typmod of first column of subplan result */ + Oid firstColCollation; /* Collation of first column of subplan + * result */ + /* Information about execution strategy: */ + bool useHashTable; /* true to store subselect output in a hash + * table (implies we are doing "IN") */ + bool unknownEqFalse; /* true if it's okay to return FALSE when the + * spec result is UNKNOWN; this allows much + * simpler handling of null values */ + bool parallel_safe; /* is the subplan parallel-safe? */ + /* Note: parallel_safe does not consider contents of testexpr or args */ + /* Information for passing params into and out of the subselect: */ + /* setParam and parParam are lists of integers (param IDs) */ + List *setParam; /* initplan and MULTIEXPR subqueries have to + * set these Params for parent plan */ + List *parParam; /* indices of input Params from parent plan */ + List *args; /* exprs to pass as parParam values */ + /* Estimated execution costs: */ + Cost startup_cost; /* one-time setup cost */ + Cost per_call_cost; /* cost for each subplan evaluation */ +} SubPlan; + +/* + * AlternativeSubPlan - expression node for a choice among SubPlans + * + * This is used only transiently during planning: by the time the plan + * reaches the executor, all AlternativeSubPlan nodes have been removed. + * + * The subplans are given as a List so that the node definition need not + * change if there's ever more than two alternatives. For the moment, + * though, there are always exactly two; and the first one is the fast-start + * plan. + */ +typedef struct AlternativeSubPlan +{ + Expr xpr; + List *subplans; /* SubPlan(s) with equivalent results */ +} AlternativeSubPlan; + +/* ---------------- + * FieldSelect + * + * FieldSelect represents the operation of extracting one field from a tuple + * value. At runtime, the input expression is expected to yield a rowtype + * Datum. The specified field number is extracted and returned as a Datum. + * ---------------- + */ + +typedef struct FieldSelect +{ + Expr xpr; + Expr *arg; /* input expression */ + AttrNumber fieldnum; /* attribute number of field to extract */ + Oid resulttype; /* type of the field (result type of this + * node) */ + int32 resulttypmod; /* output typmod (usually -1) */ + Oid resultcollid; /* OID of collation of the field */ +} FieldSelect; + +/* ---------------- + * FieldStore + * + * FieldStore represents the operation of modifying one field in a tuple + * value, yielding a new tuple value (the input is not touched!). Like + * the assign case of SubscriptingRef, this is used to implement UPDATE of a + * portion of a column. + * + * resulttype is always a named composite type (not a domain). To update + * a composite domain value, apply CoerceToDomain to the FieldStore. + * + * A single FieldStore can actually represent updates of several different + * fields. The parser only generates FieldStores with single-element lists, + * but the planner will collapse multiple updates of the same base column + * into one FieldStore. + * ---------------- + */ + +typedef struct FieldStore +{ + Expr xpr; + Expr *arg; /* input tuple value */ + List *newvals; /* new value(s) for field(s) */ + List *fieldnums; /* integer list of field attnums */ + Oid resulttype; /* type of result (same as type of arg) */ + /* Like RowExpr, we deliberately omit a typmod and collation here */ +} FieldStore; + +/* ---------------- + * RelabelType + * + * RelabelType represents a "dummy" type coercion between two binary- + * compatible datatypes, such as reinterpreting the result of an OID + * expression as an int4. It is a no-op at runtime; we only need it + * to provide a place to store the correct type to be attributed to + * the expression result during type resolution. (We can't get away + * with just overwriting the type field of the input expression node, + * so we need a separate node to show the coercion's result type.) + * ---------------- + */ + +typedef struct RelabelType +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid resulttype; /* output type of coercion expression */ + int32 resulttypmod; /* output typmod (usually -1) */ + Oid resultcollid; /* OID of collation, or InvalidOid if none */ + CoercionForm relabelformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} RelabelType; + +/* ---------------- + * CoerceViaIO + * + * CoerceViaIO represents a type coercion between two types whose textual + * representations are compatible, implemented by invoking the source type's + * typoutput function then the destination type's typinput function. + * ---------------- + */ + +typedef struct CoerceViaIO +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid resulttype; /* output type of coercion */ + /* output typmod is not stored, but is presumed -1 */ + Oid resultcollid; /* OID of collation, or InvalidOid if none */ + CoercionForm coerceformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} CoerceViaIO; + +/* ---------------- + * ArrayCoerceExpr + * + * ArrayCoerceExpr represents a type coercion from one array type to another, + * which is implemented by applying the per-element coercion expression + * "elemexpr" to each element of the source array. Within elemexpr, the + * source element is represented by a CaseTestExpr node. Note that even if + * elemexpr is a no-op (that is, just CaseTestExpr + RelabelType), the + * coercion still requires some effort: we have to fix the element type OID + * stored in the array header. + * ---------------- + */ + +typedef struct ArrayCoerceExpr +{ + Expr xpr; + Expr *arg; /* input expression (yields an array) */ + Expr *elemexpr; /* expression representing per-element work */ + Oid resulttype; /* output type of coercion (an array type) */ + int32 resulttypmod; /* output typmod (also element typmod) */ + Oid resultcollid; /* OID of collation, or InvalidOid if none */ + CoercionForm coerceformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} ArrayCoerceExpr; + +/* ---------------- + * ConvertRowtypeExpr + * + * ConvertRowtypeExpr represents a type coercion from one composite type + * to another, where the source type is guaranteed to contain all the columns + * needed for the destination type plus possibly others; the columns need not + * be in the same positions, but are matched up by name. This is primarily + * used to convert a whole-row value of an inheritance child table into a + * valid whole-row value of its parent table's rowtype. Both resulttype + * and the exposed type of "arg" must be named composite types (not domains). + * ---------------- + */ + +typedef struct ConvertRowtypeExpr +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid resulttype; /* output type (always a composite type) */ + /* Like RowExpr, we deliberately omit a typmod and collation here */ + CoercionForm convertformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} ConvertRowtypeExpr; + +/*---------- + * CollateExpr - COLLATE + * + * The planner replaces CollateExpr with RelabelType during expression + * preprocessing, so execution never sees a CollateExpr. + *---------- + */ +typedef struct CollateExpr +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid collOid; /* collation's OID */ + int location; /* token location, or -1 if unknown */ +} CollateExpr; + +/*---------- + * CaseExpr - a CASE expression + * + * We support two distinct forms of CASE expression: + * CASE WHEN boolexpr THEN expr [ WHEN boolexpr THEN expr ... ] + * CASE testexpr WHEN compexpr THEN expr [ WHEN compexpr THEN expr ... ] + * These are distinguishable by the "arg" field being NULL in the first case + * and the testexpr in the second case. + * + * In the raw grammar output for the second form, the condition expressions + * of the WHEN clauses are just the comparison values. Parse analysis + * converts these to valid boolean expressions of the form + * CaseTestExpr '=' compexpr + * where the CaseTestExpr node is a placeholder that emits the correct + * value at runtime. This structure is used so that the testexpr need be + * evaluated only once. Note that after parse analysis, the condition + * expressions always yield boolean. + * + * Note: we can test whether a CaseExpr has been through parse analysis + * yet by checking whether casetype is InvalidOid or not. + *---------- + */ +typedef struct CaseExpr +{ + Expr xpr; + Oid casetype; /* type of expression result */ + Oid casecollid; /* OID of collation, or InvalidOid if none */ + Expr *arg; /* implicit equality comparison argument */ + List *args; /* the arguments (list of WHEN clauses) */ + Expr *defresult; /* the default result (ELSE clause) */ + int location; /* token location, or -1 if unknown */ +} CaseExpr; + +/* + * CaseWhen - one arm of a CASE expression + */ +typedef struct CaseWhen +{ + Expr xpr; + Expr *expr; /* condition expression */ + Expr *result; /* substitution result */ + int location; /* token location, or -1 if unknown */ +} CaseWhen; + +/* + * Placeholder node for the test value to be processed by a CASE expression. + * This is effectively like a Param, but can be implemented more simply + * since we need only one replacement value at a time. + * + * We also abuse this node type for some other purposes, including: + * * Placeholder for the current array element value in ArrayCoerceExpr; + * see build_coercion_expression(). + * * Nested FieldStore/SubscriptingRef assignment expressions in INSERT/UPDATE; + * see transformAssignmentIndirection(). + * + * The uses in CaseExpr and ArrayCoerceExpr are safe only to the extent that + * there is not any other CaseExpr or ArrayCoerceExpr between the value source + * node and its child CaseTestExpr(s). This is true in the parse analysis + * output, but the planner's function-inlining logic has to be careful not to + * break it. + * + * The nested-assignment-expression case is safe because the only node types + * that can be above such CaseTestExprs are FieldStore and SubscriptingRef. + */ +typedef struct CaseTestExpr +{ + Expr xpr; + Oid typeId; /* type for substituted value */ + int32 typeMod; /* typemod for substituted value */ + Oid collation; /* collation for the substituted value */ +} CaseTestExpr; + +/* + * ArrayExpr - an ARRAY[] expression + * + * Note: if multidims is false, the constituent expressions all yield the + * scalar type identified by element_typeid. If multidims is true, the + * constituent expressions all yield arrays of element_typeid (ie, the same + * type as array_typeid); at runtime we must check for compatible subscripts. + */ +typedef struct ArrayExpr +{ + Expr xpr; + Oid array_typeid; /* type of expression result */ + Oid array_collid; /* OID of collation, or InvalidOid if none */ + Oid element_typeid; /* common type of array elements */ + List *elements; /* the array elements or sub-arrays */ + bool multidims; /* true if elements are sub-arrays */ + int location; /* token location, or -1 if unknown */ +} ArrayExpr; + +/* + * RowExpr - a ROW() expression + * + * Note: the list of fields must have a one-for-one correspondence with + * physical fields of the associated rowtype, although it is okay for it + * to be shorter than the rowtype. That is, the N'th list element must + * match up with the N'th physical field. When the N'th physical field + * is a dropped column (attisdropped) then the N'th list element can just + * be a NULL constant. (This case can only occur for named composite types, + * not RECORD types, since those are built from the RowExpr itself rather + * than vice versa.) It is important not to assume that length(args) is + * the same as the number of columns logically present in the rowtype. + * + * colnames provides field names if the ROW() result is of type RECORD. + * Names *must* be provided if row_typeid is RECORDOID; but if it is a + * named composite type, colnames will be ignored in favor of using the + * type's cataloged field names, so colnames should be NIL. Like the + * args list, colnames is defined to be one-for-one with physical fields + * of the rowtype (although dropped columns shouldn't appear in the + * RECORD case, so this fine point is currently moot). + */ +typedef struct RowExpr +{ + Expr xpr; + List *args; /* the fields */ + Oid row_typeid; /* RECORDOID or a composite type's ID */ + + /* + * row_typeid cannot be a domain over composite, only plain composite. To + * create a composite domain value, apply CoerceToDomain to the RowExpr. + * + * Note: we deliberately do NOT store a typmod. Although a typmod will be + * associated with specific RECORD types at runtime, it will differ for + * different backends, and so cannot safely be stored in stored + * parsetrees. We must assume typmod -1 for a RowExpr node. + * + * We don't need to store a collation either. The result type is + * necessarily composite, and composite types never have a collation. + */ + CoercionForm row_format; /* how to display this node */ + List *colnames; /* list of String, or NIL */ + int location; /* token location, or -1 if unknown */ +} RowExpr; + +/* + * RowCompareExpr - row-wise comparison, such as (a, b) <= (1, 2) + * + * We support row comparison for any operator that can be determined to + * act like =, <>, <, <=, >, or >= (we determine this by looking for the + * operator in btree opfamilies). Note that the same operator name might + * map to a different operator for each pair of row elements, since the + * element datatypes can vary. + * + * A RowCompareExpr node is only generated for the < <= > >= cases; + * the = and <> cases are translated to simple AND or OR combinations + * of the pairwise comparisons. However, we include = and <> in the + * RowCompareType enum for the convenience of parser logic. + */ +typedef enum RowCompareType +{ + /* Values of this enum are chosen to match btree strategy numbers */ + ROWCOMPARE_LT = 1, /* BTLessStrategyNumber */ + ROWCOMPARE_LE = 2, /* BTLessEqualStrategyNumber */ + ROWCOMPARE_EQ = 3, /* BTEqualStrategyNumber */ + ROWCOMPARE_GE = 4, /* BTGreaterEqualStrategyNumber */ + ROWCOMPARE_GT = 5, /* BTGreaterStrategyNumber */ + ROWCOMPARE_NE = 6 /* no such btree strategy */ +} RowCompareType; + +typedef struct RowCompareExpr +{ + Expr xpr; + RowCompareType rctype; /* LT LE GE or GT, never EQ or NE */ + List *opnos; /* OID list of pairwise comparison ops */ + List *opfamilies; /* OID list of containing operator families */ + List *inputcollids; /* OID list of collations for comparisons */ + List *largs; /* the left-hand input arguments */ + List *rargs; /* the right-hand input arguments */ +} RowCompareExpr; + +/* + * CoalesceExpr - a COALESCE expression + */ +typedef struct CoalesceExpr +{ + Expr xpr; + Oid coalescetype; /* type of expression result */ + Oid coalescecollid; /* OID of collation, or InvalidOid if none */ + List *args; /* the arguments */ + int location; /* token location, or -1 if unknown */ +} CoalesceExpr; + +/* + * MinMaxExpr - a GREATEST or LEAST function + */ +typedef enum MinMaxOp +{ + IS_GREATEST, + IS_LEAST +} MinMaxOp; + +typedef struct MinMaxExpr +{ + Expr xpr; + Oid minmaxtype; /* common type of arguments and result */ + Oid minmaxcollid; /* OID of collation of result */ + Oid inputcollid; /* OID of collation that function should use */ + MinMaxOp op; /* function to execute */ + List *args; /* the arguments */ + int location; /* token location, or -1 if unknown */ +} MinMaxExpr; + +/* + * SQLValueFunction - parameterless functions with special grammar productions + * + * The SQL standard categorizes some of these as <datetime value function> + * and others as <general value specification>. We call 'em SQLValueFunctions + * for lack of a better term. We store type and typmod of the result so that + * some code doesn't need to know each function individually, and because + * we would need to store typmod anyway for some of the datetime functions. + * Note that currently, all variants return non-collating datatypes, so we do + * not need a collation field; also, all these functions are stable. + */ +typedef enum SQLValueFunctionOp +{ + SVFOP_CURRENT_DATE, + SVFOP_CURRENT_TIME, + SVFOP_CURRENT_TIME_N, + SVFOP_CURRENT_TIMESTAMP, + SVFOP_CURRENT_TIMESTAMP_N, + SVFOP_LOCALTIME, + SVFOP_LOCALTIME_N, + SVFOP_LOCALTIMESTAMP, + SVFOP_LOCALTIMESTAMP_N, + SVFOP_CURRENT_ROLE, + SVFOP_CURRENT_USER, + SVFOP_USER, + SVFOP_SESSION_USER, + SVFOP_CURRENT_CATALOG, + SVFOP_CURRENT_SCHEMA +} SQLValueFunctionOp; + +typedef struct SQLValueFunction +{ + Expr xpr; + SQLValueFunctionOp op; /* which function this is */ + Oid type; /* result type/typmod */ + int32 typmod; + int location; /* token location, or -1 if unknown */ +} SQLValueFunction; + +/* + * XmlExpr - various SQL/XML functions requiring special grammar productions + * + * 'name' carries the "NAME foo" argument (already XML-escaped). + * 'named_args' and 'arg_names' represent an xml_attribute list. + * 'args' carries all other arguments. + * + * Note: result type/typmod/collation are not stored, but can be deduced + * from the XmlExprOp. The type/typmod fields are just used for display + * purposes, and are NOT necessarily the true result type of the node. + */ +typedef enum XmlExprOp +{ + IS_XMLCONCAT, /* XMLCONCAT(args) */ + IS_XMLELEMENT, /* XMLELEMENT(name, xml_attributes, args) */ + IS_XMLFOREST, /* XMLFOREST(xml_attributes) */ + IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */ + IS_XMLPI, /* XMLPI(name [, args]) */ + IS_XMLROOT, /* XMLROOT(xml, version, standalone) */ + IS_XMLSERIALIZE, /* XMLSERIALIZE(is_document, xmlval) */ + IS_DOCUMENT /* xmlval IS DOCUMENT */ +} XmlExprOp; + +typedef enum XmlOptionType +{ + XMLOPTION_DOCUMENT, + XMLOPTION_CONTENT +} XmlOptionType; + +typedef struct XmlExpr +{ + Expr xpr; + XmlExprOp op; /* xml function ID */ + char *name; /* name in xml(NAME foo ...) syntaxes */ + List *named_args; /* non-XML expressions for xml_attributes */ + List *arg_names; /* parallel list of String values */ + List *args; /* list of expressions */ + XmlOptionType xmloption; /* DOCUMENT or CONTENT */ + Oid type; /* target type/typmod for XMLSERIALIZE */ + int32 typmod; + int location; /* token location, or -1 if unknown */ +} XmlExpr; + +/* ---------------- + * NullTest + * + * NullTest represents the operation of testing a value for NULLness. + * The appropriate test is performed and returned as a boolean Datum. + * + * When argisrow is false, this simply represents a test for the null value. + * + * When argisrow is true, the input expression must yield a rowtype, and + * the node implements "row IS [NOT] NULL" per the SQL standard. This + * includes checking individual fields for NULLness when the row datum + * itself isn't NULL. + * + * NOTE: the combination of a rowtype input and argisrow==false does NOT + * correspond to the SQL notation "row IS [NOT] NULL"; instead, this case + * represents the SQL notation "row IS [NOT] DISTINCT FROM NULL". + * ---------------- + */ + +typedef enum NullTestType +{ + IS_NULL, IS_NOT_NULL +} NullTestType; + +typedef struct NullTest +{ + Expr xpr; + Expr *arg; /* input expression */ + NullTestType nulltesttype; /* IS NULL, IS NOT NULL */ + bool argisrow; /* T to perform field-by-field null checks */ + int location; /* token location, or -1 if unknown */ +} NullTest; + +/* + * BooleanTest + * + * BooleanTest represents the operation of determining whether a boolean + * is TRUE, FALSE, or UNKNOWN (ie, NULL). All six meaningful combinations + * are supported. Note that a NULL input does *not* cause a NULL result. + * The appropriate test is performed and returned as a boolean Datum. + */ + +typedef enum BoolTestType +{ + IS_TRUE, IS_NOT_TRUE, IS_FALSE, IS_NOT_FALSE, IS_UNKNOWN, IS_NOT_UNKNOWN +} BoolTestType; + +typedef struct BooleanTest +{ + Expr xpr; + Expr *arg; /* input expression */ + BoolTestType booltesttype; /* test type */ + int location; /* token location, or -1 if unknown */ +} BooleanTest; + +/* + * CoerceToDomain + * + * CoerceToDomain represents the operation of coercing a value to a domain + * type. At runtime (and not before) the precise set of constraints to be + * checked will be determined. If the value passes, it is returned as the + * result; if not, an error is raised. Note that this is equivalent to + * RelabelType in the scenario where no constraints are applied. + */ +typedef struct CoerceToDomain +{ + Expr xpr; + Expr *arg; /* input expression */ + Oid resulttype; /* domain type ID (result type) */ + int32 resulttypmod; /* output typmod (currently always -1) */ + Oid resultcollid; /* OID of collation, or InvalidOid if none */ + CoercionForm coercionformat; /* how to display this node */ + int location; /* token location, or -1 if unknown */ +} CoerceToDomain; + +/* + * Placeholder node for the value to be processed by a domain's check + * constraint. This is effectively like a Param, but can be implemented more + * simply since we need only one replacement value at a time. + * + * Note: the typeId/typeMod/collation will be set from the domain's base type, + * not the domain itself. This is because we shouldn't consider the value + * to be a member of the domain if we haven't yet checked its constraints. + */ +typedef struct CoerceToDomainValue +{ + Expr xpr; + Oid typeId; /* type for substituted value */ + int32 typeMod; /* typemod for substituted value */ + Oid collation; /* collation for the substituted value */ + int location; /* token location, or -1 if unknown */ +} CoerceToDomainValue; + +/* + * Placeholder node for a DEFAULT marker in an INSERT or UPDATE command. + * + * This is not an executable expression: it must be replaced by the actual + * column default expression during rewriting. But it is convenient to + * treat it as an expression node during parsing and rewriting. + */ +typedef struct SetToDefault +{ + Expr xpr; + Oid typeId; /* type for substituted value */ + int32 typeMod; /* typemod for substituted value */ + Oid collation; /* collation for the substituted value */ + int location; /* token location, or -1 if unknown */ +} SetToDefault; + +/* + * Node representing [WHERE] CURRENT OF cursor_name + * + * CURRENT OF is a bit like a Var, in that it carries the rangetable index + * of the target relation being constrained; this aids placing the expression + * correctly during planning. We can assume however that its "levelsup" is + * always zero, due to the syntactic constraints on where it can appear. + * Also, cvarno will always be a true RT index, never INNER_VAR etc. + * + * The referenced cursor can be represented either as a hardwired string + * or as a reference to a run-time parameter of type REFCURSOR. The latter + * case is for the convenience of plpgsql. + */ +typedef struct CurrentOfExpr +{ + Expr xpr; + Index cvarno; /* RT index of target relation */ + char *cursor_name; /* name of referenced cursor, or NULL */ + int cursor_param; /* refcursor parameter number, or 0 */ +} CurrentOfExpr; + +/* + * NextValueExpr - get next value from sequence + * + * This has the same effect as calling the nextval() function, but it does not + * check permissions on the sequence. This is used for identity columns, + * where the sequence is an implicit dependency without its own permissions. + */ +typedef struct NextValueExpr +{ + Expr xpr; + Oid seqid; + Oid typeId; +} NextValueExpr; + +/* + * InferenceElem - an element of a unique index inference specification + * + * This mostly matches the structure of IndexElems, but having a dedicated + * primnode allows for a clean separation between the use of index parameters + * by utility commands, and this node. + */ +typedef struct InferenceElem +{ + Expr xpr; + Node *expr; /* expression to infer from, or NULL */ + Oid infercollid; /* OID of collation, or InvalidOid */ + Oid inferopclass; /* OID of att opclass, or InvalidOid */ +} InferenceElem; + +/*-------------------- + * TargetEntry - + * a target entry (used in query target lists) + * + * Strictly speaking, a TargetEntry isn't an expression node (since it can't + * be evaluated by ExecEvalExpr). But we treat it as one anyway, since in + * very many places it's convenient to process a whole query targetlist as a + * single expression tree. + * + * In a SELECT's targetlist, resno should always be equal to the item's + * ordinal position (counting from 1). However, in an INSERT or UPDATE + * targetlist, resno represents the attribute number of the destination + * column for the item; so there may be missing or out-of-order resnos. + * It is even legal to have duplicated resnos; consider + * UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ... + * In an INSERT, the rewriter and planner will normalize the tlist by + * reordering it into physical column order and filling in default values + * for any columns not assigned values by the original query. In an UPDATE, + * after the rewriter merges multiple assignments for the same column, the + * planner extracts the target-column numbers into a separate "update_colnos" + * list, and then renumbers the tlist elements serially. Thus, tlist resnos + * match ordinal position in all tlists seen by the executor; but it is wrong + * to assume that before planning has happened. + * + * resname is required to represent the correct column name in non-resjunk + * entries of top-level SELECT targetlists, since it will be used as the + * column title sent to the frontend. In most other contexts it is only + * a debugging aid, and may be wrong or even NULL. (In particular, it may + * be wrong in a tlist from a stored rule, if the referenced column has been + * renamed by ALTER TABLE since the rule was made. Also, the planner tends + * to store NULL rather than look up a valid name for tlist entries in + * non-toplevel plan nodes.) In resjunk entries, resname should be either + * a specific system-generated name (such as "ctid") or NULL; anything else + * risks confusing ExecGetJunkAttribute! + * + * ressortgroupref is used in the representation of ORDER BY, GROUP BY, and + * DISTINCT items. Targetlist entries with ressortgroupref=0 are not + * sort/group items. If ressortgroupref>0, then this item is an ORDER BY, + * GROUP BY, and/or DISTINCT target value. No two entries in a targetlist + * may have the same nonzero ressortgroupref --- but there is no particular + * meaning to the nonzero values, except as tags. (For example, one must + * not assume that lower ressortgroupref means a more significant sort key.) + * The order of the associated SortGroupClause lists determine the semantics. + * + * resorigtbl/resorigcol identify the source of the column, if it is a + * simple reference to a column of a base table (or view). If it is not + * a simple reference, these fields are zeroes. + * + * If resjunk is true then the column is a working column (such as a sort key) + * that should be removed from the final output of the query. Resjunk columns + * must have resnos that cannot duplicate any regular column's resno. Also + * note that there are places that assume resjunk columns come after non-junk + * columns. + *-------------------- + */ +typedef struct TargetEntry +{ + Expr xpr; + Expr *expr; /* expression to evaluate */ + AttrNumber resno; /* attribute number (see notes above) */ + char *resname; /* name of the column (could be NULL) */ + Index ressortgroupref; /* nonzero if referenced by a sort/group + * clause */ + Oid resorigtbl; /* OID of column's source table */ + AttrNumber resorigcol; /* column's number in source table */ + bool resjunk; /* set to true to eliminate the attribute from + * final target list */ +} TargetEntry; + + +/* ---------------------------------------------------------------- + * node types for join trees + * + * The leaves of a join tree structure are RangeTblRef nodes. Above + * these, JoinExpr nodes can appear to denote a specific kind of join + * or qualified join. Also, FromExpr nodes can appear to denote an + * ordinary cross-product join ("FROM foo, bar, baz WHERE ..."). + * FromExpr is like a JoinExpr of jointype JOIN_INNER, except that it + * may have any number of child nodes, not just two. + * + * NOTE: the top level of a Query's jointree is always a FromExpr. + * Even if the jointree contains no rels, there will be a FromExpr. + * + * NOTE: the qualification expressions present in JoinExpr nodes are + * *in addition to* the query's main WHERE clause, which appears as the + * qual of the top-level FromExpr. The reason for associating quals with + * specific nodes in the jointree is that the position of a qual is critical + * when outer joins are present. (If we enforce a qual too soon or too late, + * that may cause the outer join to produce the wrong set of NULL-extended + * rows.) If all joins are inner joins then all the qual positions are + * semantically interchangeable. + * + * NOTE: in the raw output of gram.y, a join tree contains RangeVar, + * RangeSubselect, and RangeFunction nodes, which are all replaced by + * RangeTblRef nodes during the parse analysis phase. Also, the top-level + * FromExpr is added during parse analysis; the grammar regards FROM and + * WHERE as separate. + * ---------------------------------------------------------------- + */ + +/* + * RangeTblRef - reference to an entry in the query's rangetable + * + * We could use direct pointers to the RT entries and skip having these + * nodes, but multiple pointers to the same node in a querytree cause + * lots of headaches, so it seems better to store an index into the RT. + */ +typedef struct RangeTblRef +{ + NodeTag type; + int rtindex; +} RangeTblRef; + +/*---------- + * JoinExpr - for SQL JOIN expressions + * + * isNatural, usingClause, and quals are interdependent. The user can write + * only one of NATURAL, USING(), or ON() (this is enforced by the grammar). + * If he writes NATURAL then parse analysis generates the equivalent USING() + * list, and from that fills in "quals" with the right equality comparisons. + * If he writes USING() then "quals" is filled with equality comparisons. + * If he writes ON() then only "quals" is set. Note that NATURAL/USING + * are not equivalent to ON() since they also affect the output column list. + * + * alias is an Alias node representing the AS alias-clause attached to the + * join expression, or NULL if no clause. NB: presence or absence of the + * alias has a critical impact on semantics, because a join with an alias + * restricts visibility of the tables/columns inside it. + * + * join_using_alias is an Alias node representing the join correlation + * name that SQL:2016 and later allow to be attached to JOIN/USING. + * Its column alias list includes only the common column names from USING, + * and it does not restrict visibility of the join's input tables. + * + * During parse analysis, an RTE is created for the Join, and its index + * is filled into rtindex. This RTE is present mainly so that Vars can + * be created that refer to the outputs of the join. The planner sometimes + * generates JoinExprs internally; these can have rtindex = 0 if there are + * no join alias variables referencing such joins. + *---------- + */ +typedef struct JoinExpr +{ + NodeTag type; + JoinType jointype; /* type of join */ + bool isNatural; /* Natural join? Will need to shape table */ + Node *larg; /* left subtree */ + Node *rarg; /* right subtree */ + List *usingClause; /* USING clause, if any (list of String) */ + Alias *join_using_alias; /* alias attached to USING clause, if any */ + Node *quals; /* qualifiers on join, if any */ + Alias *alias; /* user-written alias clause, if any */ + int rtindex; /* RT index assigned for join, or 0 */ +} JoinExpr; + +/*---------- + * FromExpr - represents a FROM ... WHERE ... construct + * + * This is both more flexible than a JoinExpr (it can have any number of + * children, including zero) and less so --- we don't need to deal with + * aliases and so on. The output column set is implicitly just the union + * of the outputs of the children. + *---------- + */ +typedef struct FromExpr +{ + NodeTag type; + List *fromlist; /* List of join subtrees */ + Node *quals; /* qualifiers on join, if any */ +} FromExpr; + +/*---------- + * OnConflictExpr - represents an ON CONFLICT DO ... expression + * + * The optimizer requires a list of inference elements, and optionally a WHERE + * clause to infer a unique index. The unique index (or, occasionally, + * indexes) inferred are used to arbitrate whether or not the alternative ON + * CONFLICT path is taken. + *---------- + */ +typedef struct OnConflictExpr +{ + NodeTag type; + OnConflictAction action; /* DO NOTHING or UPDATE? */ + + /* Arbiter */ + List *arbiterElems; /* unique index arbiter list (of + * InferenceElem's) */ + Node *arbiterWhere; /* unique index arbiter WHERE clause */ + Oid constraint; /* pg_constraint OID for arbiter */ + + /* ON CONFLICT UPDATE */ + List *onConflictSet; /* List of ON CONFLICT SET TargetEntrys */ + Node *onConflictWhere; /* qualifiers to restrict UPDATE to */ + int exclRelIndex; /* RT index of 'excluded' relation */ + List *exclRelTlist; /* tlist of the EXCLUDED pseudo relation */ +} OnConflictExpr; + +#endif /* PRIMNODES_H */ diff --git a/src/include/nodes/print.h b/src/include/nodes/print.h new file mode 100644 index 0000000..be5e228 --- /dev/null +++ b/src/include/nodes/print.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * print.h + * definitions for nodes/print.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/print.h + * + *------------------------------------------------------------------------- + */ +#ifndef PRINT_H +#define PRINT_H + +#include "executor/tuptable.h" + + +#define nodeDisplay(x) pprint(x) + +extern void print(const void *obj); +extern void pprint(const void *obj); +extern void elog_node_display(int lev, const char *title, + const void *obj, bool pretty); +extern char *format_node_dump(const char *dump); +extern char *pretty_format_node_dump(const char *dump); +extern void print_rt(const List *rtable); +extern void print_expr(const Node *expr, const List *rtable); +extern void print_pathkeys(const List *pathkeys, const List *rtable); +extern void print_tl(const List *tlist, const List *rtable); +extern void print_slot(TupleTableSlot *slot); + +#endif /* PRINT_H */ diff --git a/src/include/nodes/readfuncs.h b/src/include/nodes/readfuncs.h new file mode 100644 index 0000000..66717fd --- /dev/null +++ b/src/include/nodes/readfuncs.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * readfuncs.h + * header file for read.c and readfuncs.c. These functions are internal + * to the stringToNode interface and should not be used by anyone else. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/readfuncs.h + * + *------------------------------------------------------------------------- + */ +#ifndef READFUNCS_H +#define READFUNCS_H + +#include "nodes/nodes.h" + +/* + * variable in read.c that needs to be accessible to readfuncs.c + */ +#ifdef WRITE_READ_PARSE_PLAN_TREES +extern PGDLLIMPORT bool restore_location_fields; +#endif + +/* + * prototypes for functions in read.c (the lisp token parser) + */ +extern const char *pg_strtok(int *length); +extern char *debackslash(const char *token, int length); +extern void *nodeRead(const char *token, int tok_len); + +/* + * prototypes for functions in readfuncs.c + */ +extern Node *parseNodeString(void); + +#endif /* READFUNCS_H */ diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h new file mode 100644 index 0000000..8ae9c51 --- /dev/null +++ b/src/include/nodes/replnodes.h @@ -0,0 +1,111 @@ +/*------------------------------------------------------------------------- + * + * replnodes.h + * definitions for replication grammar parse nodes + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/replnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef REPLNODES_H +#define REPLNODES_H + +#include "access/xlogdefs.h" +#include "nodes/pg_list.h" + +typedef enum ReplicationKind +{ + REPLICATION_KIND_PHYSICAL, + REPLICATION_KIND_LOGICAL +} ReplicationKind; + + +/* ---------------------- + * IDENTIFY_SYSTEM command + * ---------------------- + */ +typedef struct IdentifySystemCmd +{ + NodeTag type; +} IdentifySystemCmd; + + +/* ---------------------- + * BASE_BACKUP command + * ---------------------- + */ +typedef struct BaseBackupCmd +{ + NodeTag type; + List *options; +} BaseBackupCmd; + + +/* ---------------------- + * CREATE_REPLICATION_SLOT command + * ---------------------- + */ +typedef struct CreateReplicationSlotCmd +{ + NodeTag type; + char *slotname; + ReplicationKind kind; + char *plugin; + bool temporary; + List *options; +} CreateReplicationSlotCmd; + + +/* ---------------------- + * DROP_REPLICATION_SLOT command + * ---------------------- + */ +typedef struct DropReplicationSlotCmd +{ + NodeTag type; + char *slotname; + bool wait; +} DropReplicationSlotCmd; + + +/* ---------------------- + * START_REPLICATION command + * ---------------------- + */ +typedef struct StartReplicationCmd +{ + NodeTag type; + ReplicationKind kind; + char *slotname; + TimeLineID timeline; + XLogRecPtr startpoint; + List *options; +} StartReplicationCmd; + + +/* ---------------------- + * READ_REPLICATION_SLOT command + * ---------------------- + */ +typedef struct ReadReplicationSlotCmd +{ + NodeTag type; + char *slotname; +} ReadReplicationSlotCmd; + + +/* ---------------------- + * TIMELINE_HISTORY command + * ---------------------- + */ +typedef struct TimeLineHistoryCmd +{ + NodeTag type; + TimeLineID timeline; +} TimeLineHistoryCmd; + +#endif /* REPLNODES_H */ diff --git a/src/include/nodes/subscripting.h b/src/include/nodes/subscripting.h new file mode 100644 index 0000000..7bee44c --- /dev/null +++ b/src/include/nodes/subscripting.h @@ -0,0 +1,167 @@ +/*------------------------------------------------------------------------- + * + * subscripting.h + * API for generic type subscripting + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/subscripting.h + * + *------------------------------------------------------------------------- + */ +#ifndef SUBSCRIPTING_H +#define SUBSCRIPTING_H + +#include "nodes/primnodes.h" + +/* Forward declarations, to avoid including other headers */ +struct ParseState; +struct SubscriptingRefState; +struct SubscriptExecSteps; + +/* + * The SQL-visible function that defines a subscripting method is declared + * subscripting_function(internal) returns internal + * but it actually is not passed any parameter. It must return a pointer + * to a "struct SubscriptRoutines" that provides pointers to the individual + * subscript parsing and execution methods. Typically the pointer will point + * to a "static const" variable, but at need it can point to palloc'd space. + * The type (after domain-flattening) of the head variable or expression + * of a subscripting construct determines which subscripting function is + * called for that construct. + * + * In addition to the method pointers, struct SubscriptRoutines includes + * several bool flags that specify properties of the subscripting actions + * this data type can perform: + * + * fetch_strict indicates that a fetch SubscriptRef is strict, i.e., returns + * NULL if any input (either the container or any subscript) is NULL. + * + * fetch_leakproof indicates that a fetch SubscriptRef is leakproof, i.e., + * will not throw any data-value-dependent errors. Typically this requires + * silently returning NULL for invalid subscripts. + * + * store_leakproof similarly indicates whether an assignment SubscriptRef is + * leakproof. (It is common to prefer throwing errors for invalid subscripts + * in assignments; that's fine, but it makes the operation not leakproof. + * In current usage there is no advantage in making assignments leakproof.) + * + * There is no store_strict flag. Such behavior would generally be + * undesirable, since for example a null subscript in an assignment would + * cause the entire container to become NULL. + * + * Regardless of these flags, all SubscriptRefs are expected to be immutable, + * that is they must always give the same results for the same inputs. + * They are expected to always be parallel-safe, as well. + */ + +/* + * The transform method is called during parse analysis of a subscripting + * construct. The SubscriptingRef node has been constructed, but some of + * its fields still need to be filled in, and the subscript expression(s) + * are still in raw form. The transform method is responsible for doing + * parse analysis of each subscript expression (using transformExpr), + * coercing the subscripts to whatever type it needs, and building the + * refupperindexpr and reflowerindexpr lists from those results. The + * reflowerindexpr list must be empty for an element operation, or the + * same length as refupperindexpr for a slice operation. Insert NULLs + * (that is, an empty parse tree, not a null Const node) for any omitted + * subscripts in a slice operation. (Of course, if the transform method + * does not care to support slicing, it can just throw an error if isSlice.) + * See array_subscript_transform() for sample code. + * + * The transform method is also responsible for identifying the result type + * of the subscripting operation. At call, refcontainertype and reftypmod + * describe the container type (this will be a base type not a domain), and + * refelemtype is set to the container type's pg_type.typelem value. The + * transform method must set refrestype and reftypmod to describe the result + * of subscripting. For arrays, refrestype is set to refelemtype for an + * element operation or refcontainertype for a slice, while reftypmod stays + * the same in either case; but other types might use other rules. The + * transform method should ignore refcollid, as that's determined later on + * during parsing. + * + * At call, refassgnexpr has not been filled in, so the SubscriptingRef node + * always looks like a fetch; refrestype should be set as though for a + * fetch, too. (The isAssignment parameter is typically only useful if the + * transform method wishes to throw an error for not supporting assignment.) + * To complete processing of an assignment, the core parser will coerce the + * element/slice source expression to the returned refrestype and reftypmod + * before putting it into refassgnexpr. It will then set refrestype and + * reftypmod to again describe the container type, since that's what an + * assignment must return. + */ +typedef void (*SubscriptTransform) (SubscriptingRef *sbsref, + List *indirection, + struct ParseState *pstate, + bool isSlice, + bool isAssignment); + +/* + * The exec_setup method is called during executor-startup compilation of a + * SubscriptingRef node in an expression. It must fill *methods with pointers + * to functions that can be called for execution of the node. Optionally, + * exec_setup can initialize sbsrefstate->workspace to point to some palloc'd + * workspace for execution. (Typically, such workspace is used to hold + * looked-up catalog data and/or provide space for the check_subscripts step + * to pass data forward to the other step functions.) See executor/execExpr.h + * for the definitions of these structs and other ones used in expression + * execution. + * + * The methods to be provided are: + * + * sbs_check_subscripts: examine the just-computed subscript values available + * in sbsrefstate's arrays, and possibly convert them into another form + * (stored in sbsrefstate->workspace). Return TRUE to continue with + * evaluation of the subscripting construct, or FALSE to skip it and return an + * overall NULL result. If this is a fetch and the data type's fetch_strict + * flag is true, then sbs_check_subscripts must return FALSE if there are any + * NULL subscripts. Otherwise it can choose to throw an error, or return + * FALSE, or let sbs_fetch or sbs_assign deal with the null subscripts. + * + * sbs_fetch: perform a subscripting fetch, using the container value in + * *op->resvalue and the subscripts from sbs_check_subscripts. If + * fetch_strict is true then all these inputs can be assumed non-NULL, + * otherwise sbs_fetch must check for null inputs. Place the result in + * *op->resvalue / *op->resnull. + * + * sbs_assign: perform a subscripting assignment, using the original + * container value in *op->resvalue / *op->resnull, the subscripts from + * sbs_check_subscripts, and the new element/slice value in + * sbsrefstate->replacevalue/replacenull. Any of these inputs might be NULL + * (unless sbs_check_subscripts rejected null subscripts). Place the result + * (an entire new container value) in *op->resvalue / *op->resnull. + * + * sbs_fetch_old: this is only used in cases where an element or slice + * assignment involves an assignment to a sub-field or sub-element + * (i.e., nested containers are involved). It must fetch the existing + * value of the target element or slice. This is exactly the same as + * sbs_fetch except that (a) it must cope with a NULL container, and + * with NULL subscripts if sbs_check_subscripts allows them (typically, + * returning NULL is good enough); and (b) the result must be placed in + * sbsrefstate->prevvalue/prevnull, without overwriting *op->resvalue. + * + * Subscripting implementations that do not support assignment need not + * provide sbs_assign or sbs_fetch_old methods. It might be reasonable + * to also omit sbs_check_subscripts, in which case the sbs_fetch method must + * combine the functionality of sbs_check_subscripts and sbs_fetch. (The + * main reason to have a separate sbs_check_subscripts method is so that + * sbs_fetch_old and sbs_assign need not duplicate subscript processing.) + * Set the relevant pointers to NULL for any omitted methods. + */ +typedef void (*SubscriptExecSetup) (const SubscriptingRef *sbsref, + struct SubscriptingRefState *sbsrefstate, + struct SubscriptExecSteps *methods); + +/* Struct returned by the SQL-visible subscript handler function */ +typedef struct SubscriptRoutines +{ + SubscriptTransform transform; /* parse analysis function */ + SubscriptExecSetup exec_setup; /* expression compilation function */ + bool fetch_strict; /* is fetch SubscriptRef strict? */ + bool fetch_leakproof; /* is fetch SubscriptRef leakproof? */ + bool store_leakproof; /* is assignment SubscriptRef leakproof? */ +} SubscriptRoutines; + +#endif /* SUBSCRIPTING_H */ diff --git a/src/include/nodes/supportnodes.h b/src/include/nodes/supportnodes.h new file mode 100644 index 0000000..9fcbc39 --- /dev/null +++ b/src/include/nodes/supportnodes.h @@ -0,0 +1,302 @@ +/*------------------------------------------------------------------------- + * + * supportnodes.h + * Definitions for planner support functions. + * + * This file defines the API for "planner support functions", which + * are SQL functions (normally written in C) that can be attached to + * another "target" function to give the system additional knowledge + * about the target function. All the current capabilities have to do + * with planning queries that use the target function, though it is + * possible that future extensions will add functionality to be invoked + * by the parser or executor. + * + * A support function must have the SQL signature + * supportfn(internal) returns internal + * The argument is a pointer to one of the Node types defined in this file. + * The result is usually also a Node pointer, though its type depends on + * which capability is being invoked. In all cases, a NULL pointer result + * (that's PG_RETURN_POINTER(NULL), not PG_RETURN_NULL()) indicates that + * the support function cannot do anything useful for the given request. + * Support functions must return a NULL pointer, not fail, if they do not + * recognize the request node type or cannot handle the given case; this + * allows for future extensions of the set of request cases. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/nodes/supportnodes.h + * + *------------------------------------------------------------------------- + */ +#ifndef SUPPORTNODES_H +#define SUPPORTNODES_H + +#include "nodes/plannodes.h" + +struct PlannerInfo; /* avoid including pathnodes.h here */ +struct IndexOptInfo; +struct SpecialJoinInfo; +struct WindowClause; + +/* + * The Simplify request allows the support function to perform plan-time + * simplification of a call to its target function. For example, a varchar + * length coercion that does not decrease the allowed length of its argument + * could be replaced by a RelabelType node, or "x + 0" could be replaced by + * "x". This is invoked during the planner's constant-folding pass, so the + * function's arguments can be presumed already simplified. + * + * The planner's PlannerInfo "root" is typically not needed, but can be + * consulted if it's necessary to obtain info about Vars present in + * the given node tree. Beware that root could be NULL in some usages. + * + * "fcall" will be a FuncExpr invoking the support function's target + * function. (This is true even if the original parsetree node was an + * operator call; a FuncExpr is synthesized for this purpose.) + * + * The result should be a semantically-equivalent transformed node tree, + * or NULL if no simplification could be performed. Do *not* return or + * modify *fcall, as it isn't really a separately allocated Node. But + * it's okay to use fcall->args, or parts of it, in the result tree. + */ +typedef struct SupportRequestSimplify +{ + NodeTag type; + + struct PlannerInfo *root; /* Planner's infrastructure */ + FuncExpr *fcall; /* Function call to be simplified */ +} SupportRequestSimplify; + +/* + * The Selectivity request allows the support function to provide a + * selectivity estimate for a function appearing at top level of a WHERE + * clause (so it applies only to functions returning boolean). + * + * The input arguments are the same as are supplied to operator restriction + * and join estimators, except that we unify those two APIs into just one + * request type. See clause_selectivity() for the details. + * + * If an estimate can be made, store it into the "selectivity" field and + * return the address of the SupportRequestSelectivity node; the estimate + * must be between 0 and 1 inclusive. Return NULL if no estimate can be + * made (in which case the planner will fall back to a default estimate, + * traditionally 1/3). + * + * If the target function is being used as the implementation of an operator, + * the support function will not be used for this purpose; the operator's + * restriction or join estimator is consulted instead. + */ +typedef struct SupportRequestSelectivity +{ + NodeTag type; + + /* Input fields: */ + struct PlannerInfo *root; /* Planner's infrastructure */ + Oid funcid; /* function we are inquiring about */ + List *args; /* pre-simplified arguments to function */ + Oid inputcollid; /* function's input collation */ + bool is_join; /* is this a join or restriction case? */ + int varRelid; /* if restriction, RTI of target relation */ + JoinType jointype; /* if join, outer join type */ + struct SpecialJoinInfo *sjinfo; /* if outer join, info about join */ + + /* Output fields: */ + Selectivity selectivity; /* returned selectivity estimate */ +} SupportRequestSelectivity; + +/* + * The Cost request allows the support function to provide an execution + * cost estimate for its target function. The cost estimate can include + * both a one-time (query startup) component and a per-execution component. + * The estimate should *not* include the costs of evaluating the target + * function's arguments, only the target function itself. + * + * The "node" argument is normally the parse node that is invoking the + * target function. This is a FuncExpr in the simplest case, but it could + * also be an OpExpr, DistinctExpr, NullIfExpr, or WindowFunc, or possibly + * other cases in future. NULL is passed if the function cannot presume + * its arguments to be equivalent to what the calling node presents as + * arguments; that happens for, e.g., aggregate support functions and + * per-column comparison operators used by RowExprs. + * + * If an estimate can be made, store it into the cost fields and return the + * address of the SupportRequestCost node. Return NULL if no estimate can be + * made, in which case the planner will rely on the target function's procost + * field. (Note: while procost is automatically scaled by cpu_operator_cost, + * this is not the case for the outputs of the Cost request; the support + * function must scale its results appropriately on its own.) + */ +typedef struct SupportRequestCost +{ + NodeTag type; + + /* Input fields: */ + struct PlannerInfo *root; /* Planner's infrastructure (could be NULL) */ + Oid funcid; /* function we are inquiring about */ + Node *node; /* parse node invoking function, or NULL */ + + /* Output fields: */ + Cost startup; /* one-time cost */ + Cost per_tuple; /* per-evaluation cost */ +} SupportRequestCost; + +/* + * The Rows request allows the support function to provide an output rowcount + * estimate for its target function (so it applies only to set-returning + * functions). + * + * The "node" argument is the parse node that is invoking the target function; + * currently this will always be a FuncExpr or OpExpr. + * + * If an estimate can be made, store it into the rows field and return the + * address of the SupportRequestRows node. Return NULL if no estimate can be + * made, in which case the planner will rely on the target function's prorows + * field. + */ +typedef struct SupportRequestRows +{ + NodeTag type; + + /* Input fields: */ + struct PlannerInfo *root; /* Planner's infrastructure (could be NULL) */ + Oid funcid; /* function we are inquiring about */ + Node *node; /* parse node invoking function */ + + /* Output fields: */ + double rows; /* number of rows expected to be returned */ +} SupportRequestRows; + +/* + * The IndexCondition request allows the support function to generate + * a directly-indexable condition based on a target function call that is + * not itself indexable. The target function call must appear at the top + * level of WHERE or JOIN/ON, so this applies only to functions returning + * boolean. + * + * The "node" argument is the parse node that is invoking the target function; + * currently this will always be a FuncExpr or OpExpr. The call is made + * only if at least one function argument matches an index column's variable + * or expression. "indexarg" identifies the matching argument (it's the + * argument's zero-based index in the node's args list). + * + * If the transformation is possible, return a List of directly-indexable + * condition expressions, else return NULL. (A List is used because it's + * sometimes useful to generate more than one indexable condition, such as + * when a LIKE with constant prefix gives rise to both >= and < conditions.) + * + * "Directly indexable" means that the condition must be directly executable + * by the index machinery. Typically this means that it is a binary OpExpr + * with the index column value on the left, a pseudo-constant on the right, + * and an operator that is in the index column's operator family. Other + * possibilities include RowCompareExpr, ScalarArrayOpExpr, and NullTest, + * depending on the index type; but those seem less likely to be useful for + * derived index conditions. "Pseudo-constant" means that the right-hand + * expression must not contain any volatile functions, nor any Vars of the + * table the index is for; use is_pseudo_constant_for_index() to check this. + * (Note: if the passed "node" is an OpExpr, the core planner already verified + * that the non-indexkey operand is pseudo-constant; but when the "node" + * is a FuncExpr, it does not check, since it doesn't know which of the + * function's arguments you might need to use in an index comparison value.) + * + * In many cases, an index condition can be generated but it is weaker than + * the function condition itself; for example, a LIKE with a constant prefix + * can produce an index range check based on the prefix, but we still need + * to execute the LIKE operator to verify the rest of the pattern. We say + * that such an index condition is "lossy". When returning an index condition, + * you should set the "lossy" request field to true if the condition is lossy, + * or false if it is an exact equivalent of the function's result. The core + * code will initialize that field to true, which is the common case. + * + * It is important to verify that the index operator family is the correct + * one for the condition you want to generate. Core support functions tend + * to use the known OID of a built-in opfamily for this, but extensions need + * to work harder, since their OIDs aren't fixed. A possibly workable + * answer for an index on an extension datatype is to verify the index AM's + * OID instead, and then assume that there's only one relevant opclass for + * your datatype so the opfamily must be the right one. Generating OpExpr + * nodes may also require knowing extension datatype OIDs (often you can + * find these out by applying exprType() to a function argument) and + * operator OIDs (which you can look up using get_opfamily_member). + */ +typedef struct SupportRequestIndexCondition +{ + NodeTag type; + + /* Input fields: */ + struct PlannerInfo *root; /* Planner's infrastructure */ + Oid funcid; /* function we are inquiring about */ + Node *node; /* parse node invoking function */ + int indexarg; /* index of function arg matching indexcol */ + struct IndexOptInfo *index; /* planner's info about target index */ + int indexcol; /* index of target index column (0-based) */ + Oid opfamily; /* index column's operator family */ + Oid indexcollation; /* index column's collation */ + + /* Output fields: */ + bool lossy; /* set to false if index condition is an exact + * equivalent of the function call */ +} SupportRequestIndexCondition; + +/* ---------- + * To support more efficient query execution of any monotonically increasing + * and/or monotonically decreasing window functions, we support calling the + * window function's prosupport function passing along this struct whenever + * the planner sees an OpExpr qual directly reference a window function in a + * subquery. When the planner encounters this, we populate this struct and + * pass it along to the window function's prosupport function so that it can + * evaluate if the given WindowFunc is; + * + * a) monotonically increasing, or + * b) monotonically decreasing, or + * c) both monotonically increasing and decreasing, or + * d) none of the above. + * + * A function that is monotonically increasing can never return a value that + * is lower than a value returned in a "previous call". A monotonically + * decreasing function can never return a value higher than a value returned + * in a previous call. A function that is both must return the same value + * each time. + * + * We define "previous call" to mean a previous call to the same WindowFunc + * struct in the same window partition. + * + * row_number() is an example of a monotonically increasing function. The + * return value will be reset back to 1 in each new partition. An example of + * a monotonically increasing and decreasing function is COUNT(*) OVER (). + * Since there is no ORDER BY clause in this example, all rows in the + * partition are peers and all rows within the partition will be within the + * frame bound. Likewise for COUNT(*) OVER(ORDER BY a ROWS BETWEEN UNBOUNDED + * PRECEDING AND UNBOUNDED FOLLOWING). + * + * COUNT(*) OVER (ORDER BY a ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) + * is an example of a monotonically decreasing function. + * + * Implementations must only concern themselves with the given WindowFunc + * being monotonic in a single partition. + * + * Inputs: + * 'window_func' is the pointer to the window function being called. + * + * 'window_clause' pointer to the WindowClause data. Support functions can + * use this to check frame bounds, etc. + * + * Outputs: + * 'monotonic' the resulting MonotonicFunction value for the given input + * window function and window clause. + * ---------- + */ +typedef struct SupportRequestWFuncMonotonic +{ + NodeTag type; + + /* Input fields: */ + WindowFunc *window_func; /* Pointer to the window function data */ + struct WindowClause *window_clause; /* Pointer to the window clause data */ + + /* Output fields: */ + MonotonicFunction monotonic; +} SupportRequestWFuncMonotonic; + +#endif /* SUPPORTNODES_H */ diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h new file mode 100644 index 0000000..64ed8d1 --- /dev/null +++ b/src/include/nodes/tidbitmap.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * tidbitmap.h + * PostgreSQL tuple-id (TID) bitmap package + * + * This module provides bitmap data structures that are spiritually + * similar to Bitmapsets, but are specially adapted to store sets of + * tuple identifiers (TIDs), or ItemPointers. In particular, the division + * of an ItemPointer into BlockNumber and OffsetNumber is catered for. + * Also, since we wish to be able to store very large tuple sets in + * memory with this data structure, we support "lossy" storage, in which + * we no longer remember individual tuple offsets on a page but only the + * fact that a particular page needs to be visited. + * + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/nodes/tidbitmap.h + * + *------------------------------------------------------------------------- + */ +#ifndef TIDBITMAP_H +#define TIDBITMAP_H + +#include "storage/itemptr.h" +#include "utils/dsa.h" + + +/* + * Actual bitmap representation is private to tidbitmap.c. Callers can + * do IsA(x, TIDBitmap) on it, but nothing else. + */ +typedef struct TIDBitmap TIDBitmap; + +/* Likewise, TBMIterator is private */ +typedef struct TBMIterator TBMIterator; +typedef struct TBMSharedIterator TBMSharedIterator; + +/* Result structure for tbm_iterate */ +typedef struct TBMIterateResult +{ + BlockNumber blockno; /* page number containing tuples */ + int ntuples; /* -1 indicates lossy result */ + bool recheck; /* should the tuples be rechecked? */ + /* Note: recheck is always true if ntuples < 0 */ + OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; +} TBMIterateResult; + +/* function prototypes in nodes/tidbitmap.c */ + +extern TIDBitmap *tbm_create(long maxbytes, dsa_area *dsa); +extern void tbm_free(TIDBitmap *tbm); +extern void tbm_free_shared_area(dsa_area *dsa, dsa_pointer dp); + +extern void tbm_add_tuples(TIDBitmap *tbm, + const ItemPointer tids, int ntids, + bool recheck); +extern void tbm_add_page(TIDBitmap *tbm, BlockNumber pageno); + +extern void tbm_union(TIDBitmap *a, const TIDBitmap *b); +extern void tbm_intersect(TIDBitmap *a, const TIDBitmap *b); + +extern bool tbm_is_empty(const TIDBitmap *tbm); + +extern TBMIterator *tbm_begin_iterate(TIDBitmap *tbm); +extern dsa_pointer tbm_prepare_shared_iterate(TIDBitmap *tbm); +extern TBMIterateResult *tbm_iterate(TBMIterator *iterator); +extern TBMIterateResult *tbm_shared_iterate(TBMSharedIterator *iterator); +extern void tbm_end_iterate(TBMIterator *iterator); +extern void tbm_end_shared_iterate(TBMSharedIterator *iterator); +extern TBMSharedIterator *tbm_attach_shared_iterate(dsa_area *dsa, + dsa_pointer dp); +extern long tbm_calculate_entries(double maxbytes); + +#endif /* TIDBITMAP_H */ diff --git a/src/include/nodes/value.h b/src/include/nodes/value.h new file mode 100644 index 0000000..eaf9370 --- /dev/null +++ b/src/include/nodes/value.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- + * + * value.h + * interface for value nodes + * + * + * Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/nodes/value.h + * + *------------------------------------------------------------------------- + */ + +#ifndef VALUE_H +#define VALUE_H + +#include "nodes/nodes.h" + +/* + * The node types Integer, Float, String, and BitString are used to represent + * literals in the lexer and are also used to pass constants around in the + * parser. One difference between these node types and, say, a plain int or + * char * is that the nodes can be put into a List. + * + * (There used to be a Value node, which encompassed all these different node types. Hence the name of this file.) + */ + +typedef struct Integer +{ + NodeTag type; + int ival; +} Integer; + +/* + * Float is internally represented as string. Using T_Float as the node type + * simply indicates that the contents of the string look like a valid numeric + * literal. The value might end up being converted to NUMERIC, so we can't + * store it internally as a C double, since that could lose precision. Since + * these nodes are generally only used in the parsing process, not for runtime + * data, it's better to use the more general representation. + * + * Note that an integer-looking string will get lexed as T_Float if the value + * is too large to fit in an 'int'. + */ +typedef struct Float +{ + NodeTag type; + char *fval; +} Float; + +typedef struct Boolean +{ + NodeTag type; + bool boolval; +} Boolean; + +typedef struct String +{ + NodeTag type; + char *sval; +} String; + +typedef struct BitString +{ + NodeTag type; + char *bsval; +} BitString; + +#define intVal(v) (castNode(Integer, v)->ival) +#define floatVal(v) atof(castNode(Float, v)->fval) +#define boolVal(v) (castNode(Boolean, v)->boolval) +#define strVal(v) (castNode(String, v)->sval) + +extern Integer *makeInteger(int i); +extern Float *makeFloat(char *numericStr); +extern Boolean *makeBoolean(bool var); +extern String *makeString(char *str); +extern BitString *makeBitString(char *str); + +#endif /* VALUE_H */ diff --git a/src/include/optimizer/appendinfo.h b/src/include/optimizer/appendinfo.h new file mode 100644 index 0000000..fc808dc --- /dev/null +++ b/src/include/optimizer/appendinfo.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * appendinfo.h + * Routines for mapping expressions between append rel parent(s) and + * children + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/appendinfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef APPENDINFO_H +#define APPENDINFO_H + +#include "nodes/pathnodes.h" +#include "utils/relcache.h" + +extern AppendRelInfo *make_append_rel_info(Relation parentrel, + Relation childrel, + Index parentRTindex, Index childRTindex); +extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node, + int nappinfos, AppendRelInfo **appinfos); +extern Node *adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, + Relids child_relids, + Relids top_parent_relids); +extern Relids adjust_child_relids(Relids relids, int nappinfos, + AppendRelInfo **appinfos); +extern Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, + Relids child_relids, + Relids top_parent_relids); +extern List *adjust_inherited_attnums(List *attnums, AppendRelInfo *context); +extern List *adjust_inherited_attnums_multilevel(PlannerInfo *root, + List *attnums, + Index child_relid, + Index top_parent_relid); +extern void get_translated_update_targetlist(PlannerInfo *root, Index relid, + List **processed_tlist, + List **update_colnos); +extern AppendRelInfo **find_appinfos_by_relids(PlannerInfo *root, + Relids relids, int *nappinfos); +extern void add_row_identity_var(PlannerInfo *root, Var *rowid_var, + Index rtindex, const char *rowid_name); +extern void add_row_identity_columns(PlannerInfo *root, Index rtindex, + RangeTblEntry *target_rte, + Relation target_relation); +extern void distribute_row_identity_vars(PlannerInfo *root); + +#endif /* APPENDINFO_H */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h new file mode 100644 index 0000000..6c5203d --- /dev/null +++ b/src/include/optimizer/clauses.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * clauses.h + * prototypes for clauses.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/clauses.h + * + *------------------------------------------------------------------------- + */ +#ifndef CLAUSES_H +#define CLAUSES_H + +#include "nodes/pathnodes.h" + +typedef struct +{ + int numWindowFuncs; /* total number of WindowFuncs found */ + Index maxWinRef; /* windowFuncs[] is indexed 0 .. maxWinRef */ + List **windowFuncs; /* lists of WindowFuncs for each winref */ +} WindowFuncLists; + +extern bool contain_agg_clause(Node *clause); + +extern bool contain_window_function(Node *clause); +extern WindowFuncLists *find_window_functions(Node *clause, Index maxWinRef); + +extern double expression_returns_set_rows(PlannerInfo *root, Node *clause); + +extern bool contain_subplans(Node *clause); + +extern char max_parallel_hazard(Query *parse); +extern bool is_parallel_safe(PlannerInfo *root, Node *node); +extern bool contain_nonstrict_functions(Node *clause); +extern bool contain_exec_param(Node *clause, List *param_ids); +extern bool contain_leaked_vars(Node *clause); + +extern Relids find_nonnullable_rels(Node *clause); +extern List *find_nonnullable_vars(Node *clause); +extern List *find_forced_null_vars(Node *clause); +extern Var *find_forced_null_var(Node *clause); + +extern bool is_pseudo_constant_clause(Node *clause); +extern bool is_pseudo_constant_clause_relids(Node *clause, Relids relids); + +extern int NumRelids(PlannerInfo *root, Node *clause); + +extern void CommuteOpExpr(OpExpr *clause); + +extern Query *inline_set_returning_function(PlannerInfo *root, + RangeTblEntry *rte); + +extern Bitmapset *pull_paramids(Expr *expr); + +#endif /* CLAUSES_H */ diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h new file mode 100644 index 0000000..bc12071 --- /dev/null +++ b/src/include/optimizer/cost.h @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------- + * + * cost.h + * prototypes for costsize.c and clausesel.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/cost.h + * + *------------------------------------------------------------------------- + */ +#ifndef COST_H +#define COST_H + +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + + +/* defaults for costsize.c's Cost parameters */ +/* NB: cost-estimation code should use the variables, not these constants! */ +/* If you change these, update backend/utils/misc/postgresql.conf.sample */ +#define DEFAULT_SEQ_PAGE_COST 1.0 +#define DEFAULT_RANDOM_PAGE_COST 4.0 +#define DEFAULT_CPU_TUPLE_COST 0.01 +#define DEFAULT_CPU_INDEX_TUPLE_COST 0.005 +#define DEFAULT_CPU_OPERATOR_COST 0.0025 +#define DEFAULT_PARALLEL_TUPLE_COST 0.1 +#define DEFAULT_PARALLEL_SETUP_COST 1000.0 + +/* defaults for non-Cost parameters */ +#define DEFAULT_RECURSIVE_WORKTABLE_FACTOR 10.0 +#define DEFAULT_EFFECTIVE_CACHE_SIZE 524288 /* measured in pages */ + +typedef enum +{ + CONSTRAINT_EXCLUSION_OFF, /* do not use c_e */ + CONSTRAINT_EXCLUSION_ON, /* apply c_e to all rels */ + CONSTRAINT_EXCLUSION_PARTITION /* apply c_e to otherrels only */ +} ConstraintExclusionType; + + +/* + * prototypes for costsize.c + * routines to compute costs and sizes + */ + +/* parameter variables and flags (see also optimizer.h) */ +extern PGDLLIMPORT Cost disable_cost; +extern PGDLLIMPORT int max_parallel_workers_per_gather; +extern PGDLLIMPORT bool enable_seqscan; +extern PGDLLIMPORT bool enable_indexscan; +extern PGDLLIMPORT bool enable_indexonlyscan; +extern PGDLLIMPORT bool enable_bitmapscan; +extern PGDLLIMPORT bool enable_tidscan; +extern PGDLLIMPORT bool enable_sort; +extern PGDLLIMPORT bool enable_incremental_sort; +extern PGDLLIMPORT bool enable_hashagg; +extern PGDLLIMPORT bool enable_nestloop; +extern PGDLLIMPORT bool enable_material; +extern PGDLLIMPORT bool enable_memoize; +extern PGDLLIMPORT bool enable_mergejoin; +extern PGDLLIMPORT bool enable_hashjoin; +extern PGDLLIMPORT bool enable_gathermerge; +extern PGDLLIMPORT bool enable_partitionwise_join; +extern PGDLLIMPORT bool enable_partitionwise_aggregate; +extern PGDLLIMPORT bool enable_parallel_append; +extern PGDLLIMPORT bool enable_parallel_hash; +extern PGDLLIMPORT bool enable_partition_pruning; +extern PGDLLIMPORT bool enable_async_append; +extern PGDLLIMPORT int constraint_exclusion; + +extern double index_pages_fetched(double tuples_fetched, BlockNumber pages, + double index_pages, PlannerInfo *root); +extern void cost_seqscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, + ParamPathInfo *param_info); +extern void cost_samplescan(Path *path, PlannerInfo *root, RelOptInfo *baserel, + ParamPathInfo *param_info); +extern void cost_index(IndexPath *path, PlannerInfo *root, + double loop_count, bool partial_path); +extern void cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, + ParamPathInfo *param_info, + Path *bitmapqual, double loop_count); +extern void cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root); +extern void cost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root); +extern void cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec); +extern void cost_tidscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, List *tidquals, ParamPathInfo *param_info); +extern void cost_tidrangescan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, List *tidrangequals, + ParamPathInfo *param_info); +extern void cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_functionscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_valuesscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_tablefuncscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_ctescan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_namedtuplestorescan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_resultscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info); +extern void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm); +extern void cost_sort(Path *path, PlannerInfo *root, + List *pathkeys, Cost input_cost, double tuples, int width, + Cost comparison_cost, int sort_mem, + double limit_tuples); +extern void cost_incremental_sort(Path *path, + PlannerInfo *root, List *pathkeys, int presorted_keys, + Cost input_startup_cost, Cost input_total_cost, + double input_tuples, int width, Cost comparison_cost, int sort_mem, + double limit_tuples); +extern void cost_append(AppendPath *path); +extern void cost_merge_append(Path *path, PlannerInfo *root, + List *pathkeys, int n_streams, + Cost input_startup_cost, Cost input_total_cost, + double tuples); +extern void cost_material(Path *path, + Cost input_startup_cost, Cost input_total_cost, + double tuples, int width); +extern void cost_agg(Path *path, PlannerInfo *root, + AggStrategy aggstrategy, const AggClauseCosts *aggcosts, + int numGroupCols, double numGroups, + List *quals, + Cost input_startup_cost, Cost input_total_cost, + double input_tuples, double input_width); +extern void cost_windowagg(Path *path, PlannerInfo *root, + List *windowFuncs, int numPartCols, int numOrderCols, + Cost input_startup_cost, Cost input_total_cost, + double input_tuples); +extern void cost_group(Path *path, PlannerInfo *root, + int numGroupCols, double numGroups, + List *quals, + Cost input_startup_cost, Cost input_total_cost, + double input_tuples); +extern void initial_cost_nestloop(PlannerInfo *root, + JoinCostWorkspace *workspace, + JoinType jointype, + Path *outer_path, Path *inner_path, + JoinPathExtraData *extra); +extern void final_cost_nestloop(PlannerInfo *root, NestPath *path, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra); +extern void initial_cost_mergejoin(PlannerInfo *root, + JoinCostWorkspace *workspace, + JoinType jointype, + List *mergeclauses, + Path *outer_path, Path *inner_path, + List *outersortkeys, List *innersortkeys, + JoinPathExtraData *extra); +extern void final_cost_mergejoin(PlannerInfo *root, MergePath *path, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra); +extern void initial_cost_hashjoin(PlannerInfo *root, + JoinCostWorkspace *workspace, + JoinType jointype, + List *hashclauses, + Path *outer_path, Path *inner_path, + JoinPathExtraData *extra, + bool parallel_hash); +extern void final_cost_hashjoin(PlannerInfo *root, HashPath *path, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra); +extern void cost_gather(GatherPath *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info, double *rows); +extern void cost_gather_merge(GatherMergePath *path, PlannerInfo *root, + RelOptInfo *rel, ParamPathInfo *param_info, + Cost input_startup_cost, Cost input_total_cost, + double *rows); +extern void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan); +extern void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root); +extern void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root); +extern void compute_semi_anti_join_factors(PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + JoinType jointype, + SpecialJoinInfo *sjinfo, + List *restrictlist, + SemiAntiJoinFactors *semifactors); +extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern double get_parameterized_baserel_size(PlannerInfo *root, + RelOptInfo *rel, + List *param_clauses); +extern double get_parameterized_joinrel_size(PlannerInfo *root, + RelOptInfo *rel, + Path *outer_path, + Path *inner_path, + SpecialJoinInfo *sjinfo, + List *restrict_clauses); +extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, + RelOptInfo *outer_rel, + RelOptInfo *inner_rel, + SpecialJoinInfo *sjinfo, + List *restrictlist); +extern void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel, + double cte_rows); +extern void set_tablefunc_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_namedtuplestore_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_result_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern void set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel); +extern PathTarget *set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target); +extern double compute_bitmap_pages(PlannerInfo *root, RelOptInfo *baserel, + Path *bitmapqual, int loop_count, Cost *cost, double *tuple); + +#endif /* COST_H */ diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h new file mode 100644 index 0000000..d399323 --- /dev/null +++ b/src/include/optimizer/geqo.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * geqo.h + * prototypes for various files in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +#ifndef GEQO_H +#define GEQO_H + +#include "common/pg_prng.h" +#include "nodes/pathnodes.h" +#include "optimizer/geqo_gene.h" + + +/* GEQO debug flag */ +/* + #define GEQO_DEBUG + */ + +/* choose one recombination mechanism here */ +/* + #define ERX + #define PMX + #define CX + #define PX + #define OX1 + #define OX2 + */ +#define ERX + + +/* + * Configuration options + * + * If you change these, update backend/utils/misc/postgresql.conf.sample + */ +extern PGDLLIMPORT int Geqo_effort; /* 1 .. 10, knob for adjustment of + * defaults */ + +#define DEFAULT_GEQO_EFFORT 5 +#define MIN_GEQO_EFFORT 1 +#define MAX_GEQO_EFFORT 10 + +extern PGDLLIMPORT int Geqo_pool_size; /* 2 .. inf, or 0 to use default */ + +extern PGDLLIMPORT int Geqo_generations; /* 1 .. inf, or 0 to use default */ + +extern PGDLLIMPORT double Geqo_selection_bias; + +#define DEFAULT_GEQO_SELECTION_BIAS 2.0 +#define MIN_GEQO_SELECTION_BIAS 1.5 +#define MAX_GEQO_SELECTION_BIAS 2.0 + +extern PGDLLIMPORT double Geqo_seed; /* 0 .. 1 */ + + +/* + * Private state for a GEQO run --- accessible via root->join_search_private + */ +typedef struct +{ + List *initial_rels; /* the base relations we are joining */ + pg_prng_state random_state; /* PRNG state */ +} GeqoPrivateData; + + +/* routines in geqo_main.c */ +extern RelOptInfo *geqo(PlannerInfo *root, + int number_of_rels, List *initial_rels); + +/* routines in geqo_eval.c */ +extern Cost geqo_eval(PlannerInfo *root, Gene *tour, int num_gene); +extern RelOptInfo *gimme_tree(PlannerInfo *root, Gene *tour, int num_gene); + +#endif /* GEQO_H */ diff --git a/src/include/optimizer/geqo_copy.h b/src/include/optimizer/geqo_copy.h new file mode 100644 index 0000000..4905f71 --- /dev/null +++ b/src/include/optimizer/geqo_copy.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * geqo_copy.h + * prototypes for copy functions in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_copy.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +#ifndef GEQO_COPY_H +#define GEQO_COPY_H + +#include "optimizer/geqo.h" + + +extern void geqo_copy(PlannerInfo *root, Chromosome *chromo1, Chromosome *chromo2, int string_length); + +#endif /* GEQO_COPY_H */ diff --git a/src/include/optimizer/geqo_gene.h b/src/include/optimizer/geqo_gene.h new file mode 100644 index 0000000..414f54d --- /dev/null +++ b/src/include/optimizer/geqo_gene.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * geqo_gene.h + * genome representation in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_gene.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + + +#ifndef GEQO_GENE_H +#define GEQO_GENE_H + +#include "nodes/nodes.h" + +/* we presume that int instead of Relid + is o.k. for Gene; so don't change it! */ +typedef int Gene; + +typedef struct Chromosome +{ + Gene *string; + Cost worth; +} Chromosome; + +typedef struct Pool +{ + Chromosome *data; + int size; + int string_length; +} Pool; + +#endif /* GEQO_GENE_H */ diff --git a/src/include/optimizer/geqo_misc.h b/src/include/optimizer/geqo_misc.h new file mode 100644 index 0000000..205a89f --- /dev/null +++ b/src/include/optimizer/geqo_misc.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * geqo_misc.h + * prototypes for printout routines in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_misc.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +#ifndef GEQO_MISC_H +#define GEQO_MISC_H + +#include "optimizer/geqo_recombination.h" + +#ifdef GEQO_DEBUG + +extern void print_pool(FILE *fp, Pool *pool, int start, int stop); +extern void print_gen(FILE *fp, Pool *pool, int generation); +extern void print_edge_table(FILE *fp, Edge *edge_table, int num_gene); +#endif /* GEQO_DEBUG */ + +#endif /* GEQO_MISC_H */ diff --git a/src/include/optimizer/geqo_mutation.h b/src/include/optimizer/geqo_mutation.h new file mode 100644 index 0000000..89ee330 --- /dev/null +++ b/src/include/optimizer/geqo_mutation.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * geqo_mutation.h + * prototypes for mutation functions in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_mutation.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +#ifndef GEQO_MUTATION_H +#define GEQO_MUTATION_H + +#include "optimizer/geqo.h" + + +extern void geqo_mutation(PlannerInfo *root, Gene *tour, int num_gene); + +#endif /* GEQO_MUTATION_H */ diff --git a/src/include/optimizer/geqo_pool.h b/src/include/optimizer/geqo_pool.h new file mode 100644 index 0000000..c98abd7 --- /dev/null +++ b/src/include/optimizer/geqo_pool.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * geqo_pool.h + * pool representation in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_pool.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + + +#ifndef GEQO_POOL_H +#define GEQO_POOL_H + +#include "optimizer/geqo.h" + + +extern Pool *alloc_pool(PlannerInfo *root, int pool_size, int string_length); +extern void free_pool(PlannerInfo *root, Pool *pool); + +extern void random_init_pool(PlannerInfo *root, Pool *pool); +extern Chromosome *alloc_chromo(PlannerInfo *root, int string_length); +extern void free_chromo(PlannerInfo *root, Chromosome *chromo); + +extern void spread_chromo(PlannerInfo *root, Chromosome *chromo, Pool *pool); + +extern void sort_pool(PlannerInfo *root, Pool *pool); + +#endif /* GEQO_POOL_H */ diff --git a/src/include/optimizer/geqo_random.h b/src/include/optimizer/geqo_random.h new file mode 100644 index 0000000..56d0670 --- /dev/null +++ b/src/include/optimizer/geqo_random.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * geqo_random.h + * random number generator + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_random.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +/* -- parts of this are adapted from D. Whitley's Genitor algorithm -- */ + +#ifndef GEQO_RANDOM_H +#define GEQO_RANDOM_H + +#include <math.h> + +#include "optimizer/geqo.h" + + +extern void geqo_set_seed(PlannerInfo *root, double seed); + +/* geqo_rand returns a random float value in the range [0.0, 1.0) */ +extern double geqo_rand(PlannerInfo *root); + +/* geqo_randint returns integer value between lower and upper inclusive */ +extern int geqo_randint(PlannerInfo *root, int upper, int lower); + +#endif /* GEQO_RANDOM_H */ diff --git a/src/include/optimizer/geqo_recombination.h b/src/include/optimizer/geqo_recombination.h new file mode 100644 index 0000000..4c0acfa --- /dev/null +++ b/src/include/optimizer/geqo_recombination.h @@ -0,0 +1,89 @@ +/*------------------------------------------------------------------------- + * + * geqo_recombination.h + * prototypes for recombination in the genetic query optimizer + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_recombination.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + +/* -- parts of this are adapted from D. Whitley's Genitor algorithm -- */ + +#ifndef GEQO_RECOMBINATION_H +#define GEQO_RECOMBINATION_H + +#include "optimizer/geqo.h" + + +extern void init_tour(PlannerInfo *root, Gene *tour, int num_gene); + + +/* edge recombination crossover [ERX] */ + +typedef struct Edge +{ + Gene edge_list[4]; /* list of edges */ + int total_edges; + int unused_edges; +} Edge; + +extern Edge *alloc_edge_table(PlannerInfo *root, int num_gene); +extern void free_edge_table(PlannerInfo *root, Edge *edge_table); + +extern float gimme_edge_table(PlannerInfo *root, Gene *tour1, Gene *tour2, + int num_gene, Edge *edge_table); + +extern int gimme_tour(PlannerInfo *root, Edge *edge_table, Gene *new_gene, + int num_gene); + + +/* partially matched crossover [PMX] */ + +#define DAD 1 /* indicator for gene from dad */ +#define MOM 0 /* indicator for gene from mom */ + +extern void pmx(PlannerInfo *root, + Gene *tour1, Gene *tour2, + Gene *offspring, int num_gene); + + +typedef struct City +{ + int tour2_position; + int tour1_position; + int used; + int select_list; +} City; + +extern City * alloc_city_table(PlannerInfo *root, int num_gene); +extern void free_city_table(PlannerInfo *root, City * city_table); + +/* cycle crossover [CX] */ +extern int cx(PlannerInfo *root, Gene *tour1, Gene *tour2, + Gene *offspring, int num_gene, City * city_table); + +/* position crossover [PX] */ +extern void px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, + int num_gene, City * city_table); + +/* order crossover [OX1] according to Davis */ +extern void ox1(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring, + int num_gene, City * city_table); + +/* order crossover [OX2] according to Syswerda */ +extern void ox2(PlannerInfo *root, Gene *mom, Gene *dad, Gene *offspring, + int num_gene, City * city_table); + +#endif /* GEQO_RECOMBINATION_H */ diff --git a/src/include/optimizer/geqo_selection.h b/src/include/optimizer/geqo_selection.h new file mode 100644 index 0000000..4e50ae0 --- /dev/null +++ b/src/include/optimizer/geqo_selection.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * geqo_selection.h + * prototypes for selection routines in optimizer/geqo + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/geqo_selection.h + * + *------------------------------------------------------------------------- + */ + +/* contributed by: + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + * Martin Utesch * Institute of Automatic Control * + = = University of Mining and Technology = + * utesch@aut.tu-freiberg.de * Freiberg, Germany * + =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= + */ + + +#ifndef GEQO_SELECTION_H +#define GEQO_SELECTION_H + +#include "optimizer/geqo.h" + + +extern void geqo_selection(PlannerInfo *root, + Chromosome *momma, Chromosome *daddy, + Pool *pool, double bias); + +#endif /* GEQO_SELECTION_H */ diff --git a/src/include/optimizer/inherit.h b/src/include/optimizer/inherit.h new file mode 100644 index 0000000..8ebd42b --- /dev/null +++ b/src/include/optimizer/inherit.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * inherit.h + * prototypes for inherit.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/inherit.h + * + *------------------------------------------------------------------------- + */ +#ifndef INHERIT_H +#define INHERIT_H + +#include "nodes/pathnodes.h" + + +extern void expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte, Index rti); + +extern Bitmapset *get_rel_all_updated_cols(PlannerInfo *root, RelOptInfo *rel); + +extern bool apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel, + RelOptInfo *childrel, RangeTblEntry *childRTE, + AppendRelInfo *appinfo); + +#endif /* INHERIT_H */ diff --git a/src/include/optimizer/joininfo.h b/src/include/optimizer/joininfo.h new file mode 100644 index 0000000..f86e5c0 --- /dev/null +++ b/src/include/optimizer/joininfo.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------- + * + * joininfo.h + * prototypes for joininfo.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/joininfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef JOININFO_H +#define JOININFO_H + +#include "nodes/pathnodes.h" + + +extern bool have_relevant_joinclause(PlannerInfo *root, + RelOptInfo *rel1, RelOptInfo *rel2); + +extern void add_join_clause_to_rels(PlannerInfo *root, + RestrictInfo *restrictinfo, + Relids join_relids); +extern void remove_join_clause_from_rels(PlannerInfo *root, + RestrictInfo *restrictinfo, + Relids join_relids); + +#endif /* JOININFO_H */ diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h new file mode 100644 index 0000000..409005b --- /dev/null +++ b/src/include/optimizer/optimizer.h @@ -0,0 +1,202 @@ +/*------------------------------------------------------------------------- + * + * optimizer.h + * External API for the Postgres planner. + * + * This header is meant to define everything that the core planner + * exposes for use by non-planner modules. + * + * Note that there are files outside src/backend/optimizer/ that are + * considered planner modules, because they're too much in bed with + * planner operations to be treated otherwise. FDW planning code is an + * example. For the most part, however, code outside the core planner + * should not need to include any optimizer/ header except this one. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/optimizer.h + * + *------------------------------------------------------------------------- + */ +#ifndef OPTIMIZER_H +#define OPTIMIZER_H + +#include "nodes/parsenodes.h" + +/* + * We don't want to include nodes/pathnodes.h here, because non-planner + * code should generally treat PlannerInfo as an opaque typedef. + * But we'd like such code to use that typedef name, so define the + * typedef either here or in pathnodes.h, whichever is read first. + */ +#ifndef HAVE_PLANNERINFO_TYPEDEF +typedef struct PlannerInfo PlannerInfo; +#define HAVE_PLANNERINFO_TYPEDEF 1 +#endif + +/* Likewise for IndexOptInfo and SpecialJoinInfo. */ +#ifndef HAVE_INDEXOPTINFO_TYPEDEF +typedef struct IndexOptInfo IndexOptInfo; +#define HAVE_INDEXOPTINFO_TYPEDEF 1 +#endif +#ifndef HAVE_SPECIALJOININFO_TYPEDEF +typedef struct SpecialJoinInfo SpecialJoinInfo; +#define HAVE_SPECIALJOININFO_TYPEDEF 1 +#endif + +/* It also seems best not to include plannodes.h, params.h, or htup.h here */ +struct PlannedStmt; +struct ParamListInfoData; +struct HeapTupleData; + + +/* in path/clausesel.c: */ + +extern Selectivity clause_selectivity(PlannerInfo *root, + Node *clause, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo); +extern Selectivity clause_selectivity_ext(PlannerInfo *root, + Node *clause, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo, + bool use_extended_stats); +extern Selectivity clauselist_selectivity(PlannerInfo *root, + List *clauses, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo); +extern Selectivity clauselist_selectivity_ext(PlannerInfo *root, + List *clauses, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo, + bool use_extended_stats); + +/* in path/costsize.c: */ + +/* widely used cost parameters */ +extern PGDLLIMPORT double seq_page_cost; +extern PGDLLIMPORT double random_page_cost; +extern PGDLLIMPORT double cpu_tuple_cost; +extern PGDLLIMPORT double cpu_index_tuple_cost; +extern PGDLLIMPORT double cpu_operator_cost; +extern PGDLLIMPORT double parallel_tuple_cost; +extern PGDLLIMPORT double parallel_setup_cost; +extern PGDLLIMPORT double recursive_worktable_factor; +extern PGDLLIMPORT int effective_cache_size; + +extern double clamp_row_est(double nrows); +extern long clamp_cardinality_to_long(Cardinality x); + +/* in path/indxpath.c: */ + +extern bool is_pseudo_constant_for_index(PlannerInfo *root, Node *expr, + IndexOptInfo *index); + +/* in plan/planner.c: */ + +/* possible values for force_parallel_mode */ +typedef enum +{ + FORCE_PARALLEL_OFF, + FORCE_PARALLEL_ON, + FORCE_PARALLEL_REGRESS +} ForceParallelMode; + +/* GUC parameters */ +extern PGDLLIMPORT int force_parallel_mode; +extern PGDLLIMPORT bool parallel_leader_participation; + +extern struct PlannedStmt *planner(Query *parse, const char *query_string, + int cursorOptions, + struct ParamListInfoData *boundParams); + +extern Expr *expression_planner(Expr *expr); +extern Expr *expression_planner_with_deps(Expr *expr, + List **relationOids, + List **invalItems); + +extern bool plan_cluster_use_sort(Oid tableOid, Oid indexOid); +extern int plan_create_index_workers(Oid tableOid, Oid indexOid); + +/* in plan/setrefs.c: */ + +extern void extract_query_dependencies(Node *query, + List **relationOids, + List **invalItems, + bool *hasRowSecurity); + +/* in prep/prepqual.c: */ + +extern Node *negate_clause(Node *node); +extern Expr *canonicalize_qual(Expr *qual, bool is_check); + +/* in util/clauses.c: */ + +extern bool contain_mutable_functions(Node *clause); +extern bool contain_volatile_functions(Node *clause); +extern bool contain_volatile_functions_not_nextval(Node *clause); + +extern Node *eval_const_expressions(PlannerInfo *root, Node *node); + +extern void convert_saop_to_hashed_saop(Node *node); + +extern Node *estimate_expression_value(PlannerInfo *root, Node *node); + +extern Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, + Oid result_collation); + +extern List *expand_function_arguments(List *args, bool include_out_arguments, + Oid result_type, + struct HeapTupleData *func_tuple); + +/* in util/predtest.c: */ + +extern bool predicate_implied_by(List *predicate_list, List *clause_list, + bool weak); +extern bool predicate_refuted_by(List *predicate_list, List *clause_list, + bool weak); + +/* in util/tlist.c: */ + +extern int count_nonjunk_tlist_entries(List *tlist); +extern TargetEntry *get_sortgroupref_tle(Index sortref, + List *targetList); +extern TargetEntry *get_sortgroupclause_tle(SortGroupClause *sgClause, + List *targetList); +extern Node *get_sortgroupclause_expr(SortGroupClause *sgClause, + List *targetList); +extern List *get_sortgrouplist_exprs(List *sgClauses, + List *targetList); +extern SortGroupClause *get_sortgroupref_clause(Index sortref, + List *clauses); +extern SortGroupClause *get_sortgroupref_clause_noerr(Index sortref, + List *clauses); + +/* in util/var.c: */ + +/* Bits that can be OR'd into the flags argument of pull_var_clause() */ +#define PVC_INCLUDE_AGGREGATES 0x0001 /* include Aggrefs in output list */ +#define PVC_RECURSE_AGGREGATES 0x0002 /* recurse into Aggref arguments */ +#define PVC_INCLUDE_WINDOWFUNCS 0x0004 /* include WindowFuncs in output list */ +#define PVC_RECURSE_WINDOWFUNCS 0x0008 /* recurse into WindowFunc arguments */ +#define PVC_INCLUDE_PLACEHOLDERS 0x0010 /* include PlaceHolderVars in + * output list */ +#define PVC_RECURSE_PLACEHOLDERS 0x0020 /* recurse into PlaceHolderVar + * arguments */ + +extern Bitmapset *pull_varnos(PlannerInfo *root, Node *node); +extern Bitmapset *pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup); +extern void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos); +extern List *pull_vars_of_level(Node *node, int levelsup); +extern bool contain_var_clause(Node *node); +extern bool contain_vars_of_level(Node *node, int levelsup); +extern int locate_var_of_level(Node *node, int levelsup); +extern List *pull_var_clause(Node *node, int flags); +extern Node *flatten_join_alias_vars(Query *query, Node *node); + +#endif /* OPTIMIZER_H */ diff --git a/src/include/optimizer/orclauses.h b/src/include/optimizer/orclauses.h new file mode 100644 index 0000000..fb54fd2 --- /dev/null +++ b/src/include/optimizer/orclauses.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * orclauses.h + * prototypes for orclauses.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/orclauses.h + * + *------------------------------------------------------------------------- + */ +#ifndef ORCLAUSES_H +#define ORCLAUSES_H + +#include "nodes/pathnodes.h" + +extern void extract_restriction_or_clauses(PlannerInfo *root); + +#endif /* ORCLAUSES_H */ diff --git a/src/include/optimizer/paramassign.h b/src/include/optimizer/paramassign.h new file mode 100644 index 0000000..f3870f2 --- /dev/null +++ b/src/include/optimizer/paramassign.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * paramassign.h + * Functions for assigning PARAM_EXEC slots during planning. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/paramassign.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARAMASSIGN_H +#define PARAMASSIGN_H + +#include "nodes/pathnodes.h" + +extern Param *replace_outer_var(PlannerInfo *root, Var *var); +extern Param *replace_outer_placeholdervar(PlannerInfo *root, + PlaceHolderVar *phv); +extern Param *replace_outer_agg(PlannerInfo *root, Aggref *agg); +extern Param *replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp); +extern Param *replace_nestloop_param_var(PlannerInfo *root, Var *var); +extern Param *replace_nestloop_param_placeholdervar(PlannerInfo *root, + PlaceHolderVar *phv); +extern void process_subquery_nestloop_params(PlannerInfo *root, + List *subplan_params); +extern List *identify_current_nestloop_params(PlannerInfo *root, + Relids leftrelids); +extern Param *generate_new_exec_param(PlannerInfo *root, Oid paramtype, + int32 paramtypmod, Oid paramcollation); +extern int assign_special_exec_param(PlannerInfo *root); + +#endif /* PARAMASSIGN_H */ diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h new file mode 100644 index 0000000..d2d46b1 --- /dev/null +++ b/src/include/optimizer/pathnode.h @@ -0,0 +1,338 @@ +/*------------------------------------------------------------------------- + * + * pathnode.h + * prototypes for pathnode.c, relnode.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/pathnode.h + * + *------------------------------------------------------------------------- + */ +#ifndef PATHNODE_H +#define PATHNODE_H + +#include "nodes/bitmapset.h" +#include "nodes/pathnodes.h" + + +/* + * prototypes for pathnode.c + */ +extern int compare_path_costs(Path *path1, Path *path2, + CostSelector criterion); +extern int compare_fractional_path_costs(Path *path1, Path *path2, + double fraction); +extern void set_cheapest(RelOptInfo *parent_rel); +extern void add_path(RelOptInfo *parent_rel, Path *new_path); +extern bool add_path_precheck(RelOptInfo *parent_rel, + Cost startup_cost, Cost total_cost, + List *pathkeys, Relids required_outer); +extern void add_partial_path(RelOptInfo *parent_rel, Path *new_path); +extern bool add_partial_path_precheck(RelOptInfo *parent_rel, + Cost total_cost, List *pathkeys); + +extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer, int parallel_workers); +extern Path *create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern IndexPath *create_index_path(PlannerInfo *root, + IndexOptInfo *index, + List *indexclauses, + List *indexorderbys, + List *indexorderbycols, + List *pathkeys, + ScanDirection indexscandir, + bool indexonly, + Relids required_outer, + double loop_count, + bool partial_path); +extern BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root, + RelOptInfo *rel, + Path *bitmapqual, + Relids required_outer, + double loop_count, + int parallel_degree); +extern BitmapAndPath *create_bitmap_and_path(PlannerInfo *root, + RelOptInfo *rel, + List *bitmapquals); +extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root, + RelOptInfo *rel, + List *bitmapquals); +extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, + List *tidquals, Relids required_outer); +extern TidRangePath *create_tidrangescan_path(PlannerInfo *root, + RelOptInfo *rel, + List *tidrangequals, + Relids required_outer); +extern AppendPath *create_append_path(PlannerInfo *root, RelOptInfo *rel, + List *subpaths, List *partial_subpaths, + List *pathkeys, Relids required_outer, + int parallel_workers, bool parallel_aware, + double rows); +extern MergeAppendPath *create_merge_append_path(PlannerInfo *root, + RelOptInfo *rel, + List *subpaths, + List *pathkeys, + Relids required_outer); +extern GroupResultPath *create_group_result_path(PlannerInfo *root, + RelOptInfo *rel, + PathTarget *target, + List *havingqual); +extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath); +extern MemoizePath *create_memoize_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + List *param_exprs, + List *hash_operators, + bool singlerow, + bool binary_mode, + double calls); +extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, + Path *subpath, SpecialJoinInfo *sjinfo); +extern GatherPath *create_gather_path(PlannerInfo *root, + RelOptInfo *rel, Path *subpath, PathTarget *target, + Relids required_outer, double *rows); +extern GatherMergePath *create_gather_merge_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target, + List *pathkeys, + Relids required_outer, + double *rows); +extern SubqueryScanPath *create_subqueryscan_path(PlannerInfo *root, + RelOptInfo *rel, Path *subpath, + List *pathkeys, Relids required_outer); +extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, + List *pathkeys, Relids required_outer); +extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern Path *create_tablefuncscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern Path *create_namedtuplestorescan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern Path *create_resultscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); +extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Relids required_outer, + Path *fdw_outerpath, + List *fdw_private); +extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Relids required_outer, + Path *fdw_outerpath, + List *fdw_private); +extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel, + PathTarget *target, + double rows, Cost startup_cost, Cost total_cost, + List *pathkeys, + Path *fdw_outerpath, + List *fdw_private); + +extern Relids calc_nestloop_required_outer(Relids outerrelids, + Relids outer_paramrels, + Relids innerrelids, + Relids inner_paramrels); +extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path); + +extern NestPath *create_nestloop_path(PlannerInfo *root, + RelOptInfo *joinrel, + JoinType jointype, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra, + Path *outer_path, + Path *inner_path, + List *restrict_clauses, + List *pathkeys, + Relids required_outer); + +extern MergePath *create_mergejoin_path(PlannerInfo *root, + RelOptInfo *joinrel, + JoinType jointype, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra, + Path *outer_path, + Path *inner_path, + List *restrict_clauses, + List *pathkeys, + Relids required_outer, + List *mergeclauses, + List *outersortkeys, + List *innersortkeys); + +extern HashPath *create_hashjoin_path(PlannerInfo *root, + RelOptInfo *joinrel, + JoinType jointype, + JoinCostWorkspace *workspace, + JoinPathExtraData *extra, + Path *outer_path, + Path *inner_path, + bool parallel_hash, + List *restrict_clauses, + Relids required_outer, + List *hashclauses); + +extern ProjectionPath *create_projection_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target); +extern Path *apply_projection_to_path(PlannerInfo *root, + RelOptInfo *rel, + Path *path, + PathTarget *target); +extern ProjectSetPath *create_set_projection_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target); +extern SortPath *create_sort_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + List *pathkeys, + double limit_tuples); +extern IncrementalSortPath *create_incremental_sort_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + List *pathkeys, + int presorted_keys, + double limit_tuples); +extern GroupPath *create_group_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + List *groupClause, + List *qual, + double numGroups); +extern UpperUniquePath *create_upper_unique_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + int numCols, + double numGroups); +extern AggPath *create_agg_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target, + AggStrategy aggstrategy, + AggSplit aggsplit, + List *groupClause, + List *qual, + const AggClauseCosts *aggcosts, + double numGroups); +extern GroupingSetsPath *create_groupingsets_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + List *having_qual, + AggStrategy aggstrategy, + List *rollups, + const AggClauseCosts *agg_costs, + double numGroups); +extern MinMaxAggPath *create_minmaxagg_path(PlannerInfo *root, + RelOptInfo *rel, + PathTarget *target, + List *mmaggregates, + List *quals); +extern WindowAggPath *create_windowagg_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + PathTarget *target, + List *windowFuncs, + WindowClause *winclause, + List *qual, + bool topwindow); +extern SetOpPath *create_setop_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + SetOpCmd cmd, + SetOpStrategy strategy, + List *distinctList, + AttrNumber flagColIdx, + int firstFlag, + double numGroups, + double outputRows); +extern RecursiveUnionPath *create_recursiveunion_path(PlannerInfo *root, + RelOptInfo *rel, + Path *leftpath, + Path *rightpath, + PathTarget *target, + List *distinctList, + int wtParam, + double numGroups); +extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, + Path *subpath, List *rowMarks, int epqParam); +extern ModifyTablePath *create_modifytable_path(PlannerInfo *root, + RelOptInfo *rel, + Path *subpath, + CmdType operation, bool canSetTag, + Index nominalRelation, Index rootRelation, + bool partColsUpdated, + List *resultRelations, + List *updateColnosLists, + List *withCheckOptionLists, List *returningLists, + List *rowMarks, OnConflictExpr *onconflict, + List *mergeActionLists, int epqParam); +extern LimitPath *create_limit_path(PlannerInfo *root, RelOptInfo *rel, + Path *subpath, + Node *limitOffset, Node *limitCount, + LimitOption limitOption, + int64 offset_est, int64 count_est); +extern void adjust_limit_rows_costs(double *rows, + Cost *startup_cost, Cost *total_cost, + int64 offset_est, int64 count_est); + +extern Path *reparameterize_path(PlannerInfo *root, Path *path, + Relids required_outer, + double loop_count); +extern Path *reparameterize_path_by_child(PlannerInfo *root, Path *path, + RelOptInfo *child_rel); + +/* + * prototypes for relnode.c + */ +extern void setup_simple_rel_arrays(PlannerInfo *root); +extern void expand_planner_arrays(PlannerInfo *root, int add_size); +extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid, + RelOptInfo *parent); +extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid); +extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids); +extern RelOptInfo *build_join_rel(PlannerInfo *root, + Relids joinrelids, + RelOptInfo *outer_rel, + RelOptInfo *inner_rel, + SpecialJoinInfo *sjinfo, + List **restrictlist_ptr); +extern Relids min_join_parameterization(PlannerInfo *root, + Relids joinrelids, + RelOptInfo *outer_rel, + RelOptInfo *inner_rel); +extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, + Relids relids); +extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel); +extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root, + RelOptInfo *baserel, + Relids required_outer); +extern ParamPathInfo *get_joinrel_parampathinfo(PlannerInfo *root, + RelOptInfo *joinrel, + Path *outer_path, + Path *inner_path, + SpecialJoinInfo *sjinfo, + Relids required_outer, + List **restrict_clauses); +extern ParamPathInfo *get_appendrel_parampathinfo(RelOptInfo *appendrel, + Relids required_outer); +extern ParamPathInfo *find_param_path_info(RelOptInfo *rel, + Relids required_outer); +extern RelOptInfo *build_child_join_rel(PlannerInfo *root, + RelOptInfo *outer_rel, RelOptInfo *inner_rel, + RelOptInfo *parent_joinrel, List *restrictlist, + SpecialJoinInfo *sjinfo, JoinType jointype); + +#endif /* PATHNODE_H */ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h new file mode 100644 index 0000000..e313eb2 --- /dev/null +++ b/src/include/optimizer/paths.h @@ -0,0 +1,257 @@ +/*------------------------------------------------------------------------- + * + * paths.h + * prototypes for various files in optimizer/path + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/paths.h + * + *------------------------------------------------------------------------- + */ +#ifndef PATHS_H +#define PATHS_H + +#include "nodes/pathnodes.h" + + +/* + * allpaths.c + */ +extern PGDLLIMPORT bool enable_geqo; +extern PGDLLIMPORT int geqo_threshold; +extern PGDLLIMPORT int min_parallel_table_scan_size; +extern PGDLLIMPORT int min_parallel_index_scan_size; + +/* Hook for plugins to get control in set_rel_pathlist() */ +typedef void (*set_rel_pathlist_hook_type) (PlannerInfo *root, + RelOptInfo *rel, + Index rti, + RangeTblEntry *rte); +extern PGDLLIMPORT set_rel_pathlist_hook_type set_rel_pathlist_hook; + +/* Hook for plugins to get control in add_paths_to_joinrel() */ +typedef void (*set_join_pathlist_hook_type) (PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + JoinType jointype, + JoinPathExtraData *extra); +extern PGDLLIMPORT set_join_pathlist_hook_type set_join_pathlist_hook; + +/* Hook for plugins to replace standard_join_search() */ +typedef RelOptInfo *(*join_search_hook_type) (PlannerInfo *root, + int levels_needed, + List *initial_rels); +extern PGDLLIMPORT join_search_hook_type join_search_hook; + + +extern RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist); +extern RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed, + List *initial_rels); + +extern void generate_gather_paths(PlannerInfo *root, RelOptInfo *rel, + bool override_rows); +extern void generate_useful_gather_paths(PlannerInfo *root, RelOptInfo *rel, + bool override_rows); +extern int compute_parallel_worker(RelOptInfo *rel, double heap_pages, + double index_pages, int max_workers); +extern void create_partial_bitmap_paths(PlannerInfo *root, RelOptInfo *rel, + Path *bitmapqual); +extern void generate_partitionwise_join_paths(PlannerInfo *root, + RelOptInfo *rel); + +#ifdef OPTIMIZER_DEBUG +extern void debug_print_rel(PlannerInfo *root, RelOptInfo *rel); +#endif + +/* + * indxpath.c + * routines to generate index paths + */ +extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel); +extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel, + List *restrictlist, + List *exprlist, List *oprlist); +extern bool indexcol_is_bool_constant_for_query(PlannerInfo *root, + IndexOptInfo *index, + int indexcol); +extern bool match_index_to_operand(Node *operand, int indexcol, + IndexOptInfo *index); +extern void check_index_predicates(PlannerInfo *root, RelOptInfo *rel); + +/* + * tidpath.h + * routines to generate tid paths + */ +extern void create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel); + +/* + * joinpath.c + * routines to create join paths + */ +extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, + RelOptInfo *outerrel, RelOptInfo *innerrel, + JoinType jointype, SpecialJoinInfo *sjinfo, + List *restrictlist); + +/* + * joinrels.c + * routines to determine which relations to join + */ +extern void join_search_one_level(PlannerInfo *root, int level); +extern RelOptInfo *make_join_rel(PlannerInfo *root, + RelOptInfo *rel1, RelOptInfo *rel2); +extern bool have_join_order_restriction(PlannerInfo *root, + RelOptInfo *rel1, RelOptInfo *rel2); +extern bool have_dangerous_phv(PlannerInfo *root, + Relids outer_relids, Relids inner_params); +extern void mark_dummy_rel(RelOptInfo *rel); + +/* + * equivclass.c + * routines for managing EquivalenceClasses + */ +typedef bool (*ec_matches_callback_type) (PlannerInfo *root, + RelOptInfo *rel, + EquivalenceClass *ec, + EquivalenceMember *em, + void *arg); + +extern bool process_equivalence(PlannerInfo *root, + RestrictInfo **p_restrictinfo, + bool below_outer_join); +extern Expr *canonicalize_ec_expression(Expr *expr, + Oid req_type, Oid req_collation); +extern void reconsider_outer_join_clauses(PlannerInfo *root); +extern EquivalenceClass *get_eclass_for_sort_expr(PlannerInfo *root, + Expr *expr, + Relids nullable_relids, + List *opfamilies, + Oid opcintype, + Oid collation, + Index sortref, + Relids rel, + bool create_it); +extern EquivalenceMember *find_ec_member_matching_expr(EquivalenceClass *ec, + Expr *expr, + Relids relids); +extern EquivalenceMember *find_computable_ec_member(PlannerInfo *root, + EquivalenceClass *ec, + List *exprs, + Relids relids, + bool require_parallel_safe); +extern bool relation_can_be_sorted_early(PlannerInfo *root, RelOptInfo *rel, + EquivalenceClass *ec, + bool require_parallel_safe); +extern void generate_base_implied_equalities(PlannerInfo *root); +extern List *generate_join_implied_equalities(PlannerInfo *root, + Relids join_relids, + Relids outer_relids, + RelOptInfo *inner_rel); +extern List *generate_join_implied_equalities_for_ecs(PlannerInfo *root, + List *eclasses, + Relids join_relids, + Relids outer_relids, + RelOptInfo *inner_rel); +extern bool exprs_known_equal(PlannerInfo *root, Node *item1, Node *item2); +extern EquivalenceClass *match_eclasses_to_foreign_key_col(PlannerInfo *root, + ForeignKeyOptInfo *fkinfo, + int colno); +extern RestrictInfo *find_derived_clause_for_ec_member(EquivalenceClass *ec, + EquivalenceMember *em); +extern void add_child_rel_equivalences(PlannerInfo *root, + AppendRelInfo *appinfo, + RelOptInfo *parent_rel, + RelOptInfo *child_rel); +extern void add_child_join_rel_equivalences(PlannerInfo *root, + int nappinfos, + AppendRelInfo **appinfos, + RelOptInfo *parent_rel, + RelOptInfo *child_rel); +extern List *generate_implied_equalities_for_column(PlannerInfo *root, + RelOptInfo *rel, + ec_matches_callback_type callback, + void *callback_arg, + Relids prohibited_rels); +extern bool have_relevant_eclass_joinclause(PlannerInfo *root, + RelOptInfo *rel1, RelOptInfo *rel2); +extern bool has_relevant_eclass_joinclause(PlannerInfo *root, + RelOptInfo *rel1); +extern bool eclass_useful_for_merging(PlannerInfo *root, + EquivalenceClass *eclass, + RelOptInfo *rel); +extern bool is_redundant_derived_clause(RestrictInfo *rinfo, List *clauselist); +extern bool is_redundant_with_indexclauses(RestrictInfo *rinfo, + List *indexclauses); + +/* + * pathkeys.c + * utilities for matching and building path keys + */ +typedef enum +{ + PATHKEYS_EQUAL, /* pathkeys are identical */ + PATHKEYS_BETTER1, /* pathkey 1 is a superset of pathkey 2 */ + PATHKEYS_BETTER2, /* vice versa */ + PATHKEYS_DIFFERENT /* neither pathkey includes the other */ +} PathKeysComparison; + +extern PathKeysComparison compare_pathkeys(List *keys1, List *keys2); +extern bool pathkeys_contained_in(List *keys1, List *keys2); +extern bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common); +extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, + Relids required_outer, + CostSelector cost_criterion, + bool require_parallel_safe); +extern Path *get_cheapest_fractional_path_for_pathkeys(List *paths, + List *pathkeys, + Relids required_outer, + double fraction); +extern Path *get_cheapest_parallel_safe_total_inner(List *paths); +extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index, + ScanDirection scandir); +extern List *build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel, + ScanDirection scandir, bool *partialkeys); +extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr, + Relids nullable_relids, Oid opno, + Relids rel, bool create_it); +extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, + List *subquery_pathkeys, + List *subquery_tlist); +extern List *build_join_pathkeys(PlannerInfo *root, + RelOptInfo *joinrel, + JoinType jointype, + List *outer_pathkeys); +extern List *make_pathkeys_for_sortclauses(PlannerInfo *root, + List *sortclauses, + List *tlist); +extern void initialize_mergeclause_eclasses(PlannerInfo *root, + RestrictInfo *restrictinfo); +extern void update_mergeclause_eclasses(PlannerInfo *root, + RestrictInfo *restrictinfo); +extern List *find_mergeclauses_for_outer_pathkeys(PlannerInfo *root, + List *pathkeys, + List *restrictinfos); +extern List *select_outer_pathkeys_for_merge(PlannerInfo *root, + List *mergeclauses, + RelOptInfo *joinrel); +extern List *make_inner_pathkeys_for_merge(PlannerInfo *root, + List *mergeclauses, + List *outer_pathkeys); +extern List *trim_mergeclauses_for_inner_pathkeys(PlannerInfo *root, + List *mergeclauses, + List *pathkeys); +extern List *truncate_useless_pathkeys(PlannerInfo *root, + RelOptInfo *rel, + List *pathkeys); +extern bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel); +extern PathKey *make_canonical_pathkey(PlannerInfo *root, + EquivalenceClass *eclass, Oid opfamily, + int strategy, bool nulls_first); +extern void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels); + +#endif /* PATHS_H */ diff --git a/src/include/optimizer/placeholder.h b/src/include/optimizer/placeholder.h new file mode 100644 index 0000000..39803ea --- /dev/null +++ b/src/include/optimizer/placeholder.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * placeholder.h + * prototypes for optimizer/util/placeholder.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/placeholder.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLACEHOLDER_H +#define PLACEHOLDER_H + +#include "nodes/pathnodes.h" + + +extern PlaceHolderVar *make_placeholder_expr(PlannerInfo *root, Expr *expr, + Relids phrels); +extern PlaceHolderInfo *find_placeholder_info(PlannerInfo *root, + PlaceHolderVar *phv, bool create_new_ph); +extern void find_placeholders_in_jointree(PlannerInfo *root); +extern void update_placeholder_eval_levels(PlannerInfo *root, + SpecialJoinInfo *new_sjinfo); +extern void fix_placeholder_input_needed_levels(PlannerInfo *root); +extern void add_placeholders_to_base_rels(PlannerInfo *root); +extern void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, + RelOptInfo *outer_rel, RelOptInfo *inner_rel); + +#endif /* PLACEHOLDER_H */ diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h new file mode 100644 index 0000000..b0c06ca --- /dev/null +++ b/src/include/optimizer/plancat.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------- + * + * plancat.h + * prototypes for plancat.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/plancat.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANCAT_H +#define PLANCAT_H + +#include "nodes/pathnodes.h" +#include "utils/relcache.h" + +/* Hook for plugins to get control in get_relation_info() */ +typedef void (*get_relation_info_hook_type) (PlannerInfo *root, + Oid relationObjectId, + bool inhparent, + RelOptInfo *rel); +extern PGDLLIMPORT get_relation_info_hook_type get_relation_info_hook; + + +extern void get_relation_info(PlannerInfo *root, Oid relationObjectId, + bool inhparent, RelOptInfo *rel); + +extern List *infer_arbiter_indexes(PlannerInfo *root); + +extern void estimate_rel_size(Relation rel, int32 *attr_widths, + BlockNumber *pages, double *tuples, double *allvisfrac); + +extern int32 get_rel_data_width(Relation rel, int32 *attr_widths); +extern int32 get_relation_data_width(Oid relid, int32 *attr_widths); + +extern bool relation_excluded_by_constraints(PlannerInfo *root, + RelOptInfo *rel, RangeTblEntry *rte); + +extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel); + +extern bool has_unique_index(RelOptInfo *rel, AttrNumber attno); + +extern Selectivity restriction_selectivity(PlannerInfo *root, + Oid operatorid, + List *args, + Oid inputcollid, + int varRelid); + +extern Selectivity join_selectivity(PlannerInfo *root, + Oid operatorid, + List *args, + Oid inputcollid, + JoinType jointype, + SpecialJoinInfo *sjinfo); + +extern Selectivity function_selectivity(PlannerInfo *root, + Oid funcid, + List *args, + Oid inputcollid, + bool is_join, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo); + +extern void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, + QualCost *cost); + +extern double get_function_rows(PlannerInfo *root, Oid funcid, Node *node); + +extern bool has_row_triggers(PlannerInfo *root, Index rti, CmdType event); + +extern bool has_stored_generated_columns(PlannerInfo *root, Index rti); + +extern Bitmapset *get_dependent_generated_columns(PlannerInfo *root, Index rti, + Bitmapset *target_cols); + +#endif /* PLANCAT_H */ diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h new file mode 100644 index 0000000..c4f61c1 --- /dev/null +++ b/src/include/optimizer/planmain.h @@ -0,0 +1,120 @@ +/*------------------------------------------------------------------------- + * + * planmain.h + * prototypes for various files in optimizer/plan + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/planmain.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANMAIN_H +#define PLANMAIN_H + +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + +/* GUC parameters */ +#define DEFAULT_CURSOR_TUPLE_FRACTION 0.1 +extern PGDLLIMPORT double cursor_tuple_fraction; + +/* query_planner callback to compute query_pathkeys */ +typedef void (*query_pathkeys_callback) (PlannerInfo *root, void *extra); + +/* + * prototypes for plan/planmain.c + */ +extern RelOptInfo *query_planner(PlannerInfo *root, + query_pathkeys_callback qp_callback, void *qp_extra); + +/* + * prototypes for plan/planagg.c + */ +extern void preprocess_minmax_aggregates(PlannerInfo *root); + +/* + * prototypes for plan/createplan.c + */ +extern Plan *create_plan(PlannerInfo *root, Path *best_path); +extern ForeignScan *make_foreignscan(List *qptlist, List *qpqual, + Index scanrelid, List *fdw_exprs, List *fdw_private, + List *fdw_scan_tlist, List *fdw_recheck_quals, + Plan *outer_plan); +extern Plan *change_plan_targetlist(Plan *subplan, List *tlist, + bool tlist_parallel_safe); +extern Plan *materialize_finished_plan(Plan *subplan); +extern bool is_projection_capable_path(Path *path); +extern bool is_projection_capable_plan(Plan *plan); + +/* External use of these functions is deprecated: */ +extern Sort *make_sort_from_sortclauses(List *sortcls, Plan *lefttree); +extern Agg *make_agg(List *tlist, List *qual, + AggStrategy aggstrategy, AggSplit aggsplit, + int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations, + List *groupingSets, List *chain, double dNumGroups, + Size transitionSpace, Plan *lefttree); +extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount, + LimitOption limitOption, int uniqNumCols, + AttrNumber *uniqColIdx, Oid *uniqOperators, + Oid *uniqCollations); + +/* + * prototypes for plan/initsplan.c + */ +extern PGDLLIMPORT int from_collapse_limit; +extern PGDLLIMPORT int join_collapse_limit; + +extern void add_base_rels_to_query(PlannerInfo *root, Node *jtnode); +extern void add_other_rels_to_query(PlannerInfo *root); +extern void build_base_rel_tlists(PlannerInfo *root, List *final_tlist); +extern void add_vars_to_targetlist(PlannerInfo *root, List *vars, + Relids where_needed, bool create_new_ph); +extern void find_lateral_references(PlannerInfo *root); +extern void create_lateral_join_info(PlannerInfo *root); +extern List *deconstruct_jointree(PlannerInfo *root); +extern void distribute_restrictinfo_to_rels(PlannerInfo *root, + RestrictInfo *restrictinfo); +extern RestrictInfo *process_implied_equality(PlannerInfo *root, + Oid opno, + Oid collation, + Expr *item1, + Expr *item2, + Relids qualscope, + Relids nullable_relids, + Index security_level, + bool below_outer_join, + bool both_const); +extern RestrictInfo *build_implied_join_equality(PlannerInfo *root, + Oid opno, + Oid collation, + Expr *item1, + Expr *item2, + Relids qualscope, + Relids nullable_relids, + Index security_level); +extern void match_foreign_keys_to_quals(PlannerInfo *root); + +/* + * prototypes for plan/analyzejoins.c + */ +extern List *remove_useless_joins(PlannerInfo *root, List *joinlist); +extern void reduce_unique_semijoins(PlannerInfo *root); +extern bool query_supports_distinctness(Query *query); +extern bool query_is_distinct_for(Query *query, List *colnos, List *opids); +extern bool innerrel_is_unique(PlannerInfo *root, + Relids joinrelids, Relids outerrelids, RelOptInfo *innerrel, + JoinType jointype, List *restrictlist, bool force_cache); + +/* + * prototypes for plan/setrefs.c + */ +extern Plan *set_plan_references(PlannerInfo *root, Plan *plan); +extern bool trivial_subqueryscan(SubqueryScan *plan); +extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid); +extern void record_plan_type_dependency(PlannerInfo *root, Oid typid); +extern bool extract_query_dependencies_walker(Node *node, PlannerInfo *root); + +#endif /* PLANMAIN_H */ diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h new file mode 100644 index 0000000..eb96b2c --- /dev/null +++ b/src/include/optimizer/planner.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * planner.h + * prototypes for planner.c. + * + * Note that the primary entry points for planner.c are declared in + * optimizer/optimizer.h, because they're intended to be called from + * non-planner code. Declarations here are meant for use by other + * planner modules. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/planner.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANNER_H +#define PLANNER_H + +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + + +/* Hook for plugins to get control in planner() */ +typedef PlannedStmt *(*planner_hook_type) (Query *parse, + const char *query_string, + int cursorOptions, + ParamListInfo boundParams); +extern PGDLLIMPORT planner_hook_type planner_hook; + +/* Hook for plugins to get control when grouping_planner() plans upper rels */ +typedef void (*create_upper_paths_hook_type) (PlannerInfo *root, + UpperRelationKind stage, + RelOptInfo *input_rel, + RelOptInfo *output_rel, + void *extra); +extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook; + + +extern PlannedStmt *standard_planner(Query *parse, const char *query_string, + int cursorOptions, + ParamListInfo boundParams); + +extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse, + PlannerInfo *parent_root, + bool hasRecursion, double tuple_fraction); + +extern RowMarkType select_rowmark_type(RangeTblEntry *rte, + LockClauseStrength strength); + +extern bool limit_needed(Query *parse); + +extern void mark_partial_aggref(Aggref *agg, AggSplit aggsplit); + +extern Path *get_cheapest_fractional_path(RelOptInfo *rel, + double tuple_fraction); + +extern Expr *preprocess_phv_expression(PlannerInfo *root, Expr *expr); + +#endif /* PLANNER_H */ diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h new file mode 100644 index 0000000..2b11ff1 --- /dev/null +++ b/src/include/optimizer/prep.h @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * prep.h + * prototypes for files in optimizer/prep/ + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/prep.h + * + *------------------------------------------------------------------------- + */ +#ifndef PREP_H +#define PREP_H + +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + + +/* + * prototypes for prepjointree.c + */ +extern void transform_MERGE_to_join(Query *parse); +extern void replace_empty_jointree(Query *parse); +extern void pull_up_sublinks(PlannerInfo *root); +extern void preprocess_function_rtes(PlannerInfo *root); +extern void pull_up_subqueries(PlannerInfo *root); +extern void flatten_simple_union_all(PlannerInfo *root); +extern void reduce_outer_joins(PlannerInfo *root); +extern void remove_useless_result_rtes(PlannerInfo *root); +extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins); +extern Relids get_relids_for_join(Query *query, int joinrelid); + +/* + * prototypes for preptlist.c + */ +extern void preprocess_targetlist(PlannerInfo *root); + +extern List *extract_update_targetlist_colnos(List *tlist); + +extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex); + +/* + * prototypes for prepagg.c + */ +extern void get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, + AggClauseCosts *agg_costs); +extern void preprocess_aggrefs(PlannerInfo *root, Node *clause); + +/* + * prototypes for prepunion.c + */ +extern RelOptInfo *plan_set_operations(PlannerInfo *root); + + +#endif /* PREP_H */ diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h new file mode 100644 index 0000000..fd7a0ec --- /dev/null +++ b/src/include/optimizer/restrictinfo.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * restrictinfo.h + * prototypes for restrictinfo.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/restrictinfo.h + * + *------------------------------------------------------------------------- + */ +#ifndef RESTRICTINFO_H +#define RESTRICTINFO_H + +#include "nodes/pathnodes.h" + + +/* Convenience macro for the common case of a valid-everywhere qual */ +#define make_simple_restrictinfo(root, clause) \ + make_restrictinfo(root, clause, true, false, false, 0, NULL, NULL, NULL) + +extern RestrictInfo *make_restrictinfo(PlannerInfo *root, + Expr *clause, + bool is_pushed_down, + bool outerjoin_delayed, + bool pseudoconstant, + Index security_level, + Relids required_relids, + Relids outer_relids, + Relids nullable_relids); +extern RestrictInfo *commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op); +extern bool restriction_is_or_clause(RestrictInfo *restrictinfo); +extern bool restriction_is_securely_promotable(RestrictInfo *restrictinfo, + RelOptInfo *rel); +extern List *get_actual_clauses(List *restrictinfo_list); +extern List *extract_actual_clauses(List *restrictinfo_list, + bool pseudoconstant); +extern void extract_actual_join_clauses(List *restrictinfo_list, + Relids joinrelids, + List **joinquals, + List **otherquals); +extern bool has_pseudoconstant_clauses(PlannerInfo *root, + List *restrictinfo_list); +extern bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel); +extern bool join_clause_is_movable_into(RestrictInfo *rinfo, + Relids currentrelids, + Relids current_and_outer); + +#endif /* RESTRICTINFO_H */ diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h new file mode 100644 index 0000000..456d307 --- /dev/null +++ b/src/include/optimizer/subselect.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * subselect.h + * Planning routines for subselects. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/subselect.h + * + *------------------------------------------------------------------------- + */ +#ifndef SUBSELECT_H +#define SUBSELECT_H + +#include "nodes/pathnodes.h" +#include "nodes/plannodes.h" + +extern void SS_process_ctes(PlannerInfo *root); +extern JoinExpr *convert_ANY_sublink_to_join(PlannerInfo *root, + SubLink *sublink, + Relids available_rels); +extern JoinExpr *convert_EXISTS_sublink_to_join(PlannerInfo *root, + SubLink *sublink, + bool under_not, + Relids available_rels); +extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr); +extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual); +extern void SS_identify_outer_params(PlannerInfo *root); +extern void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel); +extern void SS_attach_initplans(PlannerInfo *root, Plan *plan); +extern void SS_finalize_plan(PlannerInfo *root, Plan *plan); +extern Param *SS_make_initplan_output_param(PlannerInfo *root, + Oid resulttype, int32 resulttypmod, + Oid resultcollation); +extern void SS_make_initplan_from_plan(PlannerInfo *root, + PlannerInfo *subroot, Plan *plan, + Param *prm); + +#endif /* SUBSELECT_H */ diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h new file mode 100644 index 0000000..04668ba --- /dev/null +++ b/src/include/optimizer/tlist.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * tlist.h + * prototypes for tlist.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/optimizer/tlist.h + * + *------------------------------------------------------------------------- + */ +#ifndef TLIST_H +#define TLIST_H + +#include "nodes/pathnodes.h" + + +extern TargetEntry *tlist_member(Expr *node, List *targetlist); + +extern List *add_to_flat_tlist(List *tlist, List *exprs); + +extern List *get_tlist_exprs(List *tlist, bool includeJunk); + +extern bool tlist_same_exprs(List *tlist1, List *tlist2); + +extern bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK); +extern bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK); + +extern void apply_tlist_labeling(List *dest_tlist, List *src_tlist); + +extern Oid *extract_grouping_ops(List *groupClause); +extern Oid *extract_grouping_collations(List *groupClause, List *tlist); +extern AttrNumber *extract_grouping_cols(List *groupClause, List *tlist); +extern bool grouping_is_sortable(List *groupClause); +extern bool grouping_is_hashable(List *groupClause); + +extern PathTarget *make_pathtarget_from_tlist(List *tlist); +extern List *make_tlist_from_pathtarget(PathTarget *target); +extern PathTarget *copy_pathtarget(PathTarget *src); +extern PathTarget *create_empty_pathtarget(void); +extern void add_column_to_pathtarget(PathTarget *target, + Expr *expr, Index sortgroupref); +extern void add_new_column_to_pathtarget(PathTarget *target, Expr *expr); +extern void add_new_columns_to_pathtarget(PathTarget *target, List *exprs); +extern void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target); +extern void split_pathtarget_at_srfs(PlannerInfo *root, + PathTarget *target, PathTarget *input_target, + List **targets, List **targets_contain_srfs); + +/* Convenience macro to get a PathTarget with valid cost/width fields */ +#define create_pathtarget(root, tlist) \ + set_pathtarget_cost_width(root, make_pathtarget_from_tlist(tlist)) + +#endif /* TLIST_H */ diff --git a/src/include/parser/.gitignore b/src/include/parser/.gitignore new file mode 100644 index 0000000..19ea955 --- /dev/null +++ b/src/include/parser/.gitignore @@ -0,0 +1 @@ +/gram.h diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h new file mode 100644 index 0000000..2a255fd --- /dev/null +++ b/src/include/parser/analyze.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * analyze.h + * parse analysis for optimizable statements + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/analyze.h + * + *------------------------------------------------------------------------- + */ +#ifndef ANALYZE_H +#define ANALYZE_H + +#include "nodes/params.h" +#include "parser/parse_node.h" +#include "utils/queryjumble.h" + +/* Hook for plugins to get control at end of parse analysis */ +typedef void (*post_parse_analyze_hook_type) (ParseState *pstate, + Query *query, + JumbleState *jstate); +extern PGDLLIMPORT post_parse_analyze_hook_type post_parse_analyze_hook; + + +extern Query *parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText, + const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv); +extern Query *parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, + Oid **paramTypes, int *numParams, QueryEnvironment *queryEnv); +extern Query *parse_analyze_withcb(RawStmt *parseTree, const char *sourceText, + ParserSetupHook parserSetup, + void *parserSetupArg, + QueryEnvironment *queryEnv); + +extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState, + CommonTableExpr *parentCTE, + bool locked_from_parent, + bool resolve_unknowns); + +extern List *transformInsertRow(ParseState *pstate, List *exprlist, + List *stmtcols, List *icolumns, List *attrnos, + bool strip_indirection); +extern List *transformUpdateTargetList(ParseState *pstate, + List *targetList); +extern Query *transformTopLevelStmt(ParseState *pstate, RawStmt *parseTree); +extern Query *transformStmt(ParseState *pstate, Node *parseTree); + +extern bool stmt_requires_parse_analysis(RawStmt *parseTree); +extern bool analyze_requires_snapshot(RawStmt *parseTree); + +extern const char *LCS_asString(LockClauseStrength strength); +extern void CheckSelectLocking(Query *qry, LockClauseStrength strength); +extern void applyLockingClause(Query *qry, Index rtindex, + LockClauseStrength strength, + LockWaitPolicy waitPolicy, bool pushedDown); + +extern List *BuildOnConflictExcludedTargetlist(Relation targetrel, + Index exclRelIndex); + +extern SortGroupClause *makeSortGroupClauseForSetOp(Oid rescoltype, bool require_hash); + +#endif /* ANALYZE_H */ diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h new file mode 100644 index 0000000..d9d4ac5 --- /dev/null +++ b/src/include/parser/gramparse.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * gramparse.h + * Shared definitions for the "raw" parser (flex and bison phases only) + * + * NOTE: this file is only meant to be included in the core parsing files, + * ie, parser.c, gram.y, scan.l, and src/common/keywords.c. + * Definitions that are needed outside the core parser should be in parser.h. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/gramparse.h + * + *------------------------------------------------------------------------- + */ + +#ifndef GRAMPARSE_H +#define GRAMPARSE_H + +#include "nodes/parsenodes.h" +#include "parser/scanner.h" + +/* + * NB: include gram.h only AFTER including scanner.h, because scanner.h + * is what #defines YYLTYPE. + */ +#include "parser/gram.h" + +/* + * The YY_EXTRA data that a flex scanner allows us to pass around. Private + * state needed for raw parsing/lexing goes here. + */ +typedef struct base_yy_extra_type +{ + /* + * Fields used by the core scanner. + */ + core_yy_extra_type core_yy_extra; + + /* + * State variables for base_yylex(). + */ + bool have_lookahead; /* is lookahead info valid? */ + int lookahead_token; /* one-token lookahead */ + core_YYSTYPE lookahead_yylval; /* yylval for lookahead token */ + YYLTYPE lookahead_yylloc; /* yylloc for lookahead token */ + char *lookahead_end; /* end of current token */ + char lookahead_hold_char; /* to be put back at *lookahead_end */ + + /* + * State variables that belong to the grammar. + */ + List *parsetree; /* final parse result is delivered here */ +} base_yy_extra_type; + +/* + * In principle we should use yyget_extra() to fetch the yyextra field + * from a yyscanner struct. However, flex always puts that field first, + * and this is sufficiently performance-critical to make it seem worth + * cheating a bit to use an inline macro. + */ +#define pg_yyget_extra(yyscanner) (*((base_yy_extra_type **) (yyscanner))) + + +/* from parser.c */ +extern int base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, + core_yyscan_t yyscanner); + +/* from gram.y */ +extern void parser_init(base_yy_extra_type *yyext); +extern int base_yyparse(core_yyscan_t yyscanner); + +#endif /* GRAMPARSE_H */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h new file mode 100644 index 0000000..65ffa89 --- /dev/null +++ b/src/include/parser/kwlist.h @@ -0,0 +1,487 @@ +/*------------------------------------------------------------------------- + * + * kwlist.h + * + * The keyword lists are kept in their own source files for use by + * automatic tools. The exact representation of a keyword is determined + * by the PG_KEYWORD macro, which is not defined in this file; it can + * be defined by the caller for special purposes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/parser/kwlist.h + * + *------------------------------------------------------------------------- + */ + +/* there is deliberately not an #ifndef KWLIST_H here */ + +/* + * List of keyword (name, token-value, category, bare-label-status) entries. + * + * Note: gen_keywordlist.pl requires the entries to appear in ASCII order. + */ + +/* name, value, category, is-bare-label */ +PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("analyse", ANALYSE, RESERVED_KEYWORD, BARE_LABEL) /* British spelling */ +PG_KEYWORD("analyze", ANALYZE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("and", AND, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("any", ANY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("array", ARRAY, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("as", AS, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("asc", ASC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("asensitive", ASENSITIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("assertion", ASSERTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("at", AT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("atomic", ATOMIC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("attribute", ATTRIBUTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("begin", BEGIN_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("between", BETWEEN, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("bigint", BIGINT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("binary", BINARY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("bit", BIT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("boolean", BOOLEAN_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("both", BOTH, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("breadth", BREADTH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("by", BY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cache", CACHE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("call", CALL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("called", CALLED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cascade", CASCADE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cascaded", CASCADED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("case", CASE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cast", CAST, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("catalog", CATALOG_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("chain", CHAIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("char", CHAR_P, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("character", CHARACTER, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("characteristics", CHARACTERISTICS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("check", CHECK, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("checkpoint", CHECKPOINT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("class", CLASS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("close", CLOSE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cluster", CLUSTER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("coalesce", COALESCE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("collate", COLLATE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("collation", COLLATION, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("column", COLUMN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("columns", COLUMNS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("comment", COMMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("comments", COMMENTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("commit", COMMIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("committed", COMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("compression", COMPRESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("concurrently", CONCURRENTLY, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("copy", COPY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cost", COST, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("create", CREATE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("cross", CROSS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_time", CURRENT_TIME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_timestamp", CURRENT_TIMESTAMP, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("current_user", CURRENT_USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cursor", CURSOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("deallocate", DEALLOCATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("dec", DEC, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("decimal", DECIMAL_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("declare", DECLARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("depth", DEPTH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("desc", DESC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("do", DO, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("document", DOCUMENT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("domain", DOMAIN_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("double", DOUBLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("drop", DROP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("each", EACH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("else", ELSE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("enable", ENABLE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("encoding", ENCODING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("encrypted", ENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("end", END_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("enum", ENUM_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("escape", ESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("event", EVENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("except", EXCEPT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("exclude", EXCLUDE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("excluding", EXCLUDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("exclusive", EXCLUSIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("execute", EXECUTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("exists", EXISTS, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("explain", EXPLAIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("expression", EXPRESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("extension", EXTENSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("external", EXTERNAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("extract", EXTRACT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("false", FALSE_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("family", FAMILY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("fetch", FETCH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("filter", FILTER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("finalize", FINALIZE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("first", FIRST_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("float", FLOAT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("following", FOLLOWING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("for", FOR, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("force", FORCE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("foreign", FOREIGN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("forward", FORWARD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("freeze", FREEZE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("from", FROM, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("full", FULL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("function", FUNCTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("functions", FUNCTIONS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("generated", GENERATED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("global", GLOBAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("grant", GRANT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("granted", GRANTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("greatest", GREATEST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("group", GROUP_P, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("grouping", GROUPING, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("groups", GROUPS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("handler", HANDLER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("having", HAVING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("header", HEADER_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("hold", HOLD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("hour", HOUR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("identity", IDENTITY_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("if", IF_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("immediate", IMMEDIATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("immutable", IMMUTABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("implicit", IMPLICIT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("import", IMPORT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("in", IN_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("include", INCLUDE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("including", INCLUDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("increment", INCREMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("insensitive", INSENSITIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("insert", INSERT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("instead", INSTEAD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("int", INT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("integer", INTEGER, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("intersect", INTERSECT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("interval", INTERVAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("into", INTO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("invoker", INVOKER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("is", IS, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("names", NAMES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("national", NATIONAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("natural", NATURAL, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("nchar", NCHAR, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("new", NEW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("next", NEXT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfc", NFC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfd", NFD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfkc", NFKC, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nfkd", NFKD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("no", NO, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("none", NONE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("normalize", NORMALIZE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("normalized", NORMALIZED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("not", NOT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nothing", NOTHING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("notify", NOTIFY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("notnull", NOTNULL, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("nowait", NOWAIT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("null", NULL_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("nullif", NULLIF, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("nulls", NULLS_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("numeric", NUMERIC, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("object", OBJECT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("of", OF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("off", OFF, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("offset", OFFSET, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("oids", OIDS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("old", OLD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("on", ON, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("only", ONLY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("operator", OPERATOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("option", OPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("options", OPTIONS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("or", OR, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("order", ORDER, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("ordinality", ORDINALITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("others", OTHERS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("out", OUT_P, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("outer", OUTER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("over", OVER, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("overlaps", OVERLAPS, TYPE_FUNC_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("overlay", OVERLAY, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parameter", PARAMETER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("primary", PRIMARY, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("prior", PRIOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("privileges", PRIVILEGES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedural", PROCEDURAL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedure", PROCEDURE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("procedures", PROCEDURES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("program", PROGRAM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("publication", PUBLICATION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("quote", QUOTE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("range", RANGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("read", READ, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("real", REAL, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ref", REF_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("referencing", REFERENCING, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("refresh", REFRESH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("release", RELEASE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rename", RENAME, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("repeatable", REPEATABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("replace", REPLACE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("replica", REPLICA, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("reset", RESET, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("restart", RESTART, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("restrict", RESTRICT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("return", RETURN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("returning", RETURNING, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("returns", RETURNS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("revoke", REVOKE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("right", RIGHT, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("role", ROLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rollback", ROLLBACK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rollup", ROLLUP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("routine", ROUTINE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("routines", ROUTINES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("row", ROW, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("rows", ROWS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("rule", RULE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("savepoint", SAVEPOINT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("schema", SCHEMA, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("schemas", SCHEMAS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("serializable", SERIALIZABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("server", SERVER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("session", SESSION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("session_user", SESSION_USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("set", SET, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("setof", SETOF, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("sets", SETS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("some", SOME, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sql", SQL_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stable", STABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("standalone", STANDALONE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("start", START, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("statement", STATEMENT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("table", TABLE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("tables", TABLES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("tablesample", TABLESAMPLE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("tablespace", TABLESPACE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("temp", TEMP, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("then", THEN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("ties", TIES, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("time", TIME, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("to", TO, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("transform", TRANSFORM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("trigger", TRIGGER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("trim", TRIM, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("true", TRUE_P, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("truncate", TRUNCATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("trusted", TRUSTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("type", TYPE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("types", TYPES_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("uescape", UESCAPE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unbounded", UNBOUNDED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("uncommitted", UNCOMMITTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unencrypted", UNENCRYPTED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("union", UNION, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("using", USING, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("vacuum", VACUUM, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("valid", VALID, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("validate", VALIDATE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("validator", VALIDATOR, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("version", VERSION_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("view", VIEW, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("views", VIEWS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("volatile", VOLATILE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("when", WHEN, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("where", WHERE, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("whitespace", WHITESPACE_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("window", WINDOW, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("with", WITH, RESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("within", WITHIN, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("without", WITHOUT, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("work", WORK, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("wrapper", WRAPPER, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("write", WRITE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, AS_LABEL) +PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h new file mode 100644 index 0000000..c56822f --- /dev/null +++ b/src/include/parser/parse_agg.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * parse_agg.h + * handle aggregates and window functions in parser + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_agg.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_AGG_H +#define PARSE_AGG_H + +#include "parser/parse_node.h" + +extern void transformAggregateCall(ParseState *pstate, Aggref *agg, + List *args, List *aggorder, + bool agg_distinct); + +extern Node *transformGroupingFunc(ParseState *pstate, GroupingFunc *g); + +extern void transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, + WindowDef *windef); + +extern void parseCheckAggregates(ParseState *pstate, Query *qry); + +extern List *expand_grouping_sets(List *groupingSets, bool groupDistinct, int limit); + +extern int get_aggregate_argtypes(Aggref *aggref, Oid *inputTypes); + +extern Oid resolve_aggregate_transtype(Oid aggfuncid, + Oid aggtranstype, + Oid *inputTypes, + int numArguments); + +extern void build_aggregate_transfn_expr(Oid *agg_input_types, + int agg_num_inputs, + int agg_num_direct_inputs, + bool agg_variadic, + Oid agg_state_type, + Oid agg_input_collation, + Oid transfn_oid, + Oid invtransfn_oid, + Expr **transfnexpr, + Expr **invtransfnexpr); + +extern void build_aggregate_serialfn_expr(Oid serialfn_oid, + Expr **serialfnexpr); + +extern void build_aggregate_deserialfn_expr(Oid deserialfn_oid, + Expr **deserialfnexpr); + +extern void build_aggregate_finalfn_expr(Oid *agg_input_types, + int num_finalfn_inputs, + Oid agg_state_type, + Oid agg_result_type, + Oid agg_input_collation, + Oid finalfn_oid, + Expr **finalfnexpr); + +#endif /* PARSE_AGG_H */ diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h new file mode 100644 index 0000000..2495c30 --- /dev/null +++ b/src/include/parser/parse_clause.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * parse_clause.h + * handle clauses in parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_clause.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_CLAUSE_H +#define PARSE_CLAUSE_H + +#include "parser/parse_node.h" + +extern void transformFromClause(ParseState *pstate, List *frmList); +extern int setTargetTable(ParseState *pstate, RangeVar *relation, + bool inh, bool alsoSource, AclMode requiredPerms); + +extern Node *transformWhereClause(ParseState *pstate, Node *clause, + ParseExprKind exprKind, const char *constructName); +extern Node *transformLimitClause(ParseState *pstate, Node *clause, + ParseExprKind exprKind, const char *constructName, + LimitOption limitOption); +extern List *transformGroupClause(ParseState *pstate, List *grouplist, + List **groupingSets, + List **targetlist, List *sortClause, + ParseExprKind exprKind, bool useSQL99); +extern List *transformSortClause(ParseState *pstate, List *orderlist, + List **targetlist, ParseExprKind exprKind, + bool useSQL99); + +extern List *transformWindowDefinitions(ParseState *pstate, + List *windowdefs, + List **targetlist); + +extern List *transformDistinctClause(ParseState *pstate, + List **targetlist, List *sortClause, bool is_agg); +extern List *transformDistinctOnClause(ParseState *pstate, List *distinctlist, + List **targetlist, List *sortClause); +extern void transformOnConflictArbiter(ParseState *pstate, + OnConflictClause *onConflictClause, + List **arbiterExpr, Node **arbiterWhere, + Oid *constraint); + +extern List *addTargetToSortList(ParseState *pstate, TargetEntry *tle, + List *sortlist, List *targetlist, SortBy *sortby); +extern Index assignSortGroupRef(TargetEntry *tle, List *tlist); +extern bool targetIsInSortList(TargetEntry *tle, Oid sortop, List *sortList); + +#endif /* PARSE_CLAUSE_H */ diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h new file mode 100644 index 0000000..b105c7d --- /dev/null +++ b/src/include/parser/parse_coerce.h @@ -0,0 +1,100 @@ +/*------------------------------------------------------------------------- + * + * parse_coerce.h + * Routines for type coercion. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_coerce.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_COERCE_H +#define PARSE_COERCE_H + +#include "parser/parse_node.h" + + +/* Type categories (see TYPCATEGORY_xxx symbols in catalog/pg_type.h) */ +typedef char TYPCATEGORY; + +/* Result codes for find_coercion_pathway */ +typedef enum CoercionPathType +{ + COERCION_PATH_NONE, /* failed to find any coercion pathway */ + COERCION_PATH_FUNC, /* apply the specified coercion function */ + COERCION_PATH_RELABELTYPE, /* binary-compatible cast, no function */ + COERCION_PATH_ARRAYCOERCE, /* need an ArrayCoerceExpr node */ + COERCION_PATH_COERCEVIAIO /* need a CoerceViaIO node */ +} CoercionPathType; + + +extern bool IsBinaryCoercible(Oid srctype, Oid targettype); +extern bool IsPreferredType(TYPCATEGORY category, Oid type); +extern TYPCATEGORY TypeCategory(Oid type); + +extern Node *coerce_to_target_type(ParseState *pstate, + Node *expr, Oid exprtype, + Oid targettype, int32 targettypmod, + CoercionContext ccontext, + CoercionForm cformat, + int location); +extern bool can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, + CoercionContext ccontext); +extern Node *coerce_type(ParseState *pstate, Node *node, + Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, + CoercionContext ccontext, CoercionForm cformat, int location); +extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, + Oid typeId, + CoercionContext ccontext, CoercionForm cformat, int location, + bool hideInputCoercion); + +extern Node *coerce_to_boolean(ParseState *pstate, Node *node, + const char *constructName); +extern Node *coerce_to_specific_type(ParseState *pstate, Node *node, + Oid targetTypeId, + const char *constructName); + +extern Node *coerce_to_specific_type_typmod(ParseState *pstate, Node *node, + Oid targetTypeId, int32 targetTypmod, + const char *constructName); + +extern int parser_coercion_errposition(ParseState *pstate, + int coerce_location, + Node *input_expr); + +extern Oid select_common_type(ParseState *pstate, List *exprs, + const char *context, Node **which_expr); +extern Node *coerce_to_common_type(ParseState *pstate, Node *node, + Oid targetTypeId, + const char *context); +extern bool verify_common_type(Oid common_type, List *exprs); + +extern int32 select_common_typmod(ParseState *pstate, List *exprs, Oid common_type); + +extern bool check_generic_type_consistency(const Oid *actual_arg_types, + const Oid *declared_arg_types, + int nargs); +extern Oid enforce_generic_type_consistency(const Oid *actual_arg_types, + Oid *declared_arg_types, + int nargs, + Oid rettype, + bool allow_poly); + +extern char *check_valid_polymorphic_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs); +extern char *check_valid_internal_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs); + +extern CoercionPathType find_coercion_pathway(Oid targetTypeId, + Oid sourceTypeId, + CoercionContext ccontext, + Oid *funcid); +extern CoercionPathType find_typmod_coercion_function(Oid typeId, + Oid *funcid); + +#endif /* PARSE_COERCE_H */ diff --git a/src/include/parser/parse_collate.h b/src/include/parser/parse_collate.h new file mode 100644 index 0000000..cd16aa0 --- /dev/null +++ b/src/include/parser/parse_collate.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------- + * + * parse_collate.h + * Routines for assigning collation information. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_collate.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_COLLATE_H +#define PARSE_COLLATE_H + +#include "parser/parse_node.h" + +extern void assign_query_collations(ParseState *pstate, Query *query); + +extern void assign_list_collations(ParseState *pstate, List *exprs); + +extern void assign_expr_collations(ParseState *pstate, Node *expr); + +extern Oid select_common_collation(ParseState *pstate, List *exprs, bool none_ok); + +#endif /* PARSE_COLLATE_H */ diff --git a/src/include/parser/parse_cte.h b/src/include/parser/parse_cte.h new file mode 100644 index 0000000..cb61b79 --- /dev/null +++ b/src/include/parser/parse_cte.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * parse_cte.h + * handle CTEs (common table expressions) in parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_cte.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_CTE_H +#define PARSE_CTE_H + +#include "parser/parse_node.h" + +extern List *transformWithClause(ParseState *pstate, WithClause *withClause); + +extern void analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, + List *tlist); + +#endif /* PARSE_CTE_H */ diff --git a/src/include/parser/parse_enr.h b/src/include/parser/parse_enr.h new file mode 100644 index 0000000..a3c05fd --- /dev/null +++ b/src/include/parser/parse_enr.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * parse_enr.h + * Internal definitions for parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_enr.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_ENR_H +#define PARSE_ENR_H + +#include "parser/parse_node.h" + +extern bool name_matches_visible_ENR(ParseState *pstate, const char *refname); +extern EphemeralNamedRelationMetadata get_visible_ENR(ParseState *pstate, const char *refname); + +#endif /* PARSE_ENR_H */ diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h new file mode 100644 index 0000000..c8e5c57 --- /dev/null +++ b/src/include/parser/parse_expr.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * parse_expr.h + * handle expressions in parser + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_expr.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_EXPR_H +#define PARSE_EXPR_H + +#include "parser/parse_node.h" + +/* GUC parameters */ +extern PGDLLIMPORT bool Transform_null_equals; + +extern Node *transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind); + +extern const char *ParseExprKindName(ParseExprKind exprKind); + +#endif /* PARSE_EXPR_H */ diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h new file mode 100644 index 0000000..8711e39 --- /dev/null +++ b/src/include/parser/parse_func.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * parse_func.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_func.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_FUNC_H +#define PARSE_FUNC_H + +#include "catalog/namespace.h" +#include "parser/parse_node.h" + + +/* Result codes for func_get_detail */ +typedef enum +{ + FUNCDETAIL_NOTFOUND, /* no matching function */ + FUNCDETAIL_MULTIPLE, /* too many matching functions */ + FUNCDETAIL_NORMAL, /* found a matching regular function */ + FUNCDETAIL_PROCEDURE, /* found a matching procedure */ + FUNCDETAIL_AGGREGATE, /* found a matching aggregate function */ + FUNCDETAIL_WINDOWFUNC, /* found a matching window function */ + FUNCDETAIL_COERCION /* it's a type coercion request */ +} FuncDetailCode; + + +extern Node *ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, + Node *last_srf, FuncCall *fn, bool proc_call, + int location); + +extern FuncDetailCode func_get_detail(List *funcname, + List *fargs, List *fargnames, + int nargs, Oid *argtypes, + bool expand_variadic, bool expand_defaults, + bool include_out_arguments, + Oid *funcid, Oid *rettype, + bool *retset, int *nvargs, Oid *vatype, + Oid **true_typeids, List **argdefaults); + +extern int func_match_argtypes(int nargs, + Oid *input_typeids, + FuncCandidateList raw_candidates, + FuncCandidateList *candidates); + +extern FuncCandidateList func_select_candidate(int nargs, + Oid *input_typeids, + FuncCandidateList candidates); + +extern void make_fn_arguments(ParseState *pstate, + List *fargs, + Oid *actual_arg_types, + Oid *declared_arg_types); + +extern const char *funcname_signature_string(const char *funcname, int nargs, + List *argnames, const Oid *argtypes); +extern const char *func_signature_string(List *funcname, int nargs, + List *argnames, const Oid *argtypes); + +extern Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, + bool missing_ok); +extern Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, + bool missing_ok); + +extern void check_srf_call_placement(ParseState *pstate, Node *last_srf, + int location); + +#endif /* PARSE_FUNC_H */ diff --git a/src/include/parser/parse_merge.h b/src/include/parser/parse_merge.h new file mode 100644 index 0000000..1a1baa1 --- /dev/null +++ b/src/include/parser/parse_merge.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * parse_merge.h + * handle MERGE statement in parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_merge.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_MERGE_H +#define PARSE_MERGE_H + +#include "parser/parse_node.h" + +extern Query *transformMergeStmt(ParseState *pstate, MergeStmt *stmt); + +#endif /* PARSE_MERGE_H */ diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h new file mode 100644 index 0000000..cf9c759 --- /dev/null +++ b/src/include/parser/parse_node.h @@ -0,0 +1,339 @@ +/*------------------------------------------------------------------------- + * + * parse_node.h + * Internal definitions for parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_node.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_NODE_H +#define PARSE_NODE_H + +#include "nodes/parsenodes.h" +#include "utils/queryenvironment.h" +#include "utils/relcache.h" + + +/* Forward references for some structs declared below */ +typedef struct ParseState ParseState; +typedef struct ParseNamespaceItem ParseNamespaceItem; +typedef struct ParseNamespaceColumn ParseNamespaceColumn; + +/* + * Expression kinds distinguished by transformExpr(). Many of these are not + * semantically distinct so far as expression transformation goes; rather, + * we distinguish them so that context-specific error messages can be printed. + * + * Note: EXPR_KIND_OTHER is not used in the core code, but is left for use + * by extension code that might need to call transformExpr(). The core code + * will not enforce any context-driven restrictions on EXPR_KIND_OTHER + * expressions, so the caller would have to check for sub-selects, aggregates, + * window functions, SRFs, etc if those need to be disallowed. + */ +typedef enum ParseExprKind +{ + EXPR_KIND_NONE = 0, /* "not in an expression" */ + EXPR_KIND_OTHER, /* reserved for extensions */ + EXPR_KIND_JOIN_ON, /* JOIN ON */ + EXPR_KIND_JOIN_USING, /* JOIN USING */ + EXPR_KIND_FROM_SUBSELECT, /* sub-SELECT in FROM clause */ + EXPR_KIND_FROM_FUNCTION, /* function in FROM clause */ + EXPR_KIND_WHERE, /* WHERE */ + EXPR_KIND_HAVING, /* HAVING */ + EXPR_KIND_FILTER, /* FILTER */ + EXPR_KIND_WINDOW_PARTITION, /* window definition PARTITION BY */ + EXPR_KIND_WINDOW_ORDER, /* window definition ORDER BY */ + EXPR_KIND_WINDOW_FRAME_RANGE, /* window frame clause with RANGE */ + EXPR_KIND_WINDOW_FRAME_ROWS, /* window frame clause with ROWS */ + EXPR_KIND_WINDOW_FRAME_GROUPS, /* window frame clause with GROUPS */ + EXPR_KIND_SELECT_TARGET, /* SELECT target list item */ + EXPR_KIND_INSERT_TARGET, /* INSERT target list item */ + EXPR_KIND_UPDATE_SOURCE, /* UPDATE assignment source item */ + EXPR_KIND_UPDATE_TARGET, /* UPDATE assignment target item */ + EXPR_KIND_MERGE_WHEN, /* MERGE WHEN [NOT] MATCHED condition */ + EXPR_KIND_GROUP_BY, /* GROUP BY */ + EXPR_KIND_ORDER_BY, /* ORDER BY */ + EXPR_KIND_DISTINCT_ON, /* DISTINCT ON */ + EXPR_KIND_LIMIT, /* LIMIT */ + EXPR_KIND_OFFSET, /* OFFSET */ + EXPR_KIND_RETURNING, /* RETURNING */ + EXPR_KIND_VALUES, /* VALUES */ + EXPR_KIND_VALUES_SINGLE, /* single-row VALUES (in INSERT only) */ + EXPR_KIND_CHECK_CONSTRAINT, /* CHECK constraint for a table */ + EXPR_KIND_DOMAIN_CHECK, /* CHECK constraint for a domain */ + EXPR_KIND_COLUMN_DEFAULT, /* default value for a table column */ + EXPR_KIND_FUNCTION_DEFAULT, /* default parameter value for function */ + EXPR_KIND_INDEX_EXPRESSION, /* index expression */ + EXPR_KIND_INDEX_PREDICATE, /* index predicate */ + EXPR_KIND_STATS_EXPRESSION, /* extended statistics expression */ + EXPR_KIND_ALTER_COL_TRANSFORM, /* transform expr in ALTER COLUMN TYPE */ + EXPR_KIND_EXECUTE_PARAMETER, /* parameter value in EXECUTE */ + EXPR_KIND_TRIGGER_WHEN, /* WHEN condition in CREATE TRIGGER */ + EXPR_KIND_POLICY, /* USING or WITH CHECK expr in policy */ + EXPR_KIND_PARTITION_BOUND, /* partition bound expression */ + EXPR_KIND_PARTITION_EXPRESSION, /* PARTITION BY expression */ + EXPR_KIND_CALL_ARGUMENT, /* procedure argument in CALL */ + EXPR_KIND_COPY_WHERE, /* WHERE condition in COPY FROM */ + EXPR_KIND_GENERATED_COLUMN, /* generation expression for a column */ + EXPR_KIND_CYCLE_MARK, /* cycle mark value */ +} ParseExprKind; + + +/* + * Function signatures for parser hooks + */ +typedef Node *(*PreParseColumnRefHook) (ParseState *pstate, ColumnRef *cref); +typedef Node *(*PostParseColumnRefHook) (ParseState *pstate, ColumnRef *cref, Node *var); +typedef Node *(*ParseParamRefHook) (ParseState *pstate, ParamRef *pref); +typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param, + Oid targetTypeId, int32 targetTypeMod, + int location); + + +/* + * State information used during parse analysis + * + * parentParseState: NULL in a top-level ParseState. When parsing a subquery, + * links to current parse state of outer query. + * + * p_sourcetext: source string that generated the raw parsetree being + * analyzed, or NULL if not available. (The string is used only to + * generate cursor positions in error messages: we need it to convert + * byte-wise locations in parse structures to character-wise cursor + * positions.) + * + * p_rtable: list of RTEs that will become the rangetable of the query. + * Note that neither relname nor refname of these entries are necessarily + * unique; searching the rtable by name is a bad idea. + * + * p_joinexprs: list of JoinExpr nodes associated with p_rtable entries. + * This is one-for-one with p_rtable, but contains NULLs for non-join + * RTEs, and may be shorter than p_rtable if the last RTE(s) aren't joins. + * + * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that + * will become the fromlist of the query's top-level FromExpr node. + * + * p_namespace: list of ParseNamespaceItems that represents the current + * namespace for table and column lookup. (The RTEs listed here may be just + * a subset of the whole rtable. See ParseNamespaceItem comments below.) + * + * p_lateral_active: true if we are currently parsing a LATERAL subexpression + * of this parse level. This makes p_lateral_only namespace items visible, + * whereas they are not visible when p_lateral_active is FALSE. + * + * p_ctenamespace: list of CommonTableExprs (WITH items) that are visible + * at the moment. This is entirely different from p_namespace because a CTE + * is not an RTE, rather "visibility" means you could make an RTE from it. + * + * p_future_ctes: list of CommonTableExprs (WITH items) that are not yet + * visible due to scope rules. This is used to help improve error messages. + * + * p_parent_cte: CommonTableExpr that immediately contains the current query, + * if any. + * + * p_target_relation: target relation, if query is INSERT/UPDATE/DELETE/MERGE + * + * p_target_nsitem: target relation's ParseNamespaceItem. + * + * p_is_insert: true to process assignment expressions like INSERT, false + * to process them like UPDATE. (Note this can change intra-statement, for + * cases like INSERT ON CONFLICT UPDATE.) + * + * p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses. + * We collect these while transforming expressions and then transform them + * afterwards (so that any resjunk tlist items needed for the sort/group + * clauses end up at the end of the query tlist). A WindowDef's location in + * this list, counting from 1, is the winref number to use to reference it. + * + * p_expr_kind: kind of expression we're currently parsing, as per enum above; + * EXPR_KIND_NONE when not in an expression. + * + * p_next_resno: next TargetEntry.resno to assign, starting from 1. + * + * p_multiassign_exprs: partially-processed MultiAssignRef source expressions. + * + * p_locking_clause: query's FOR UPDATE/FOR SHARE clause, if any. + * + * p_locked_from_parent: true if parent query level applies FOR UPDATE/SHARE + * to this subquery as a whole. + * + * p_resolve_unknowns: resolve unknown-type SELECT output columns as type TEXT + * (this is true by default). + * + * p_hasAggs, p_hasWindowFuncs, etc: true if we've found any of the indicated + * constructs in the query. + * + * p_last_srf: the set-returning FuncExpr or OpExpr most recently found in + * the query, or NULL if none. + * + * p_pre_columnref_hook, etc: optional parser hook functions for modifying the + * interpretation of ColumnRefs and ParamRefs. + * + * p_ref_hook_state: passthrough state for the parser hook functions. + */ +struct ParseState +{ + ParseState *parentParseState; /* stack link */ + const char *p_sourcetext; /* source text, or NULL if not available */ + List *p_rtable; /* range table so far */ + List *p_joinexprs; /* JoinExprs for RTE_JOIN p_rtable entries */ + List *p_joinlist; /* join items so far (will become FromExpr + * node's fromlist) */ + List *p_namespace; /* currently-referenceable RTEs (List of + * ParseNamespaceItem) */ + bool p_lateral_active; /* p_lateral_only items visible? */ + List *p_ctenamespace; /* current namespace for common table exprs */ + List *p_future_ctes; /* common table exprs not yet in namespace */ + CommonTableExpr *p_parent_cte; /* this query's containing CTE */ + Relation p_target_relation; /* INSERT/UPDATE/DELETE/MERGE target rel */ + ParseNamespaceItem *p_target_nsitem; /* target rel's NSItem, or NULL */ + bool p_is_insert; /* process assignment like INSERT not UPDATE */ + List *p_windowdefs; /* raw representations of window clauses */ + ParseExprKind p_expr_kind; /* what kind of expression we're parsing */ + int p_next_resno; /* next targetlist resno to assign */ + List *p_multiassign_exprs; /* junk tlist entries for multiassign */ + List *p_locking_clause; /* raw FOR UPDATE/FOR SHARE info */ + bool p_locked_from_parent; /* parent has marked this subquery + * with FOR UPDATE/FOR SHARE */ + bool p_resolve_unknowns; /* resolve unknown-type SELECT outputs as + * type text */ + + QueryEnvironment *p_queryEnv; /* curr env, incl refs to enclosing env */ + + /* Flags telling about things found in the query: */ + bool p_hasAggs; + bool p_hasWindowFuncs; + bool p_hasTargetSRFs; + bool p_hasSubLinks; + bool p_hasModifyingCTE; + + Node *p_last_srf; /* most recent set-returning func/op found */ + + /* + * Optional hook functions for parser callbacks. These are null unless + * set up by the caller of make_parsestate. + */ + PreParseColumnRefHook p_pre_columnref_hook; + PostParseColumnRefHook p_post_columnref_hook; + ParseParamRefHook p_paramref_hook; + CoerceParamHook p_coerce_param_hook; + void *p_ref_hook_state; /* common passthrough link for above */ +}; + +/* + * An element of a namespace list. + * + * p_names contains the table name and column names exposed by this nsitem. + * (Typically it's equal to p_rte->eref, but for a JOIN USING alias it's + * equal to p_rte->join_using_alias. Since the USING columns will be the + * join's first N columns, the net effect is just that we expose only those + * join columns via this nsitem.) + * + * p_rte and p_rtindex link to the underlying rangetable entry. + * + * The p_nscolumns array contains info showing how to construct Vars + * referencing the names appearing in the p_names->colnames list. + * + * Namespace items with p_rel_visible set define which RTEs are accessible by + * qualified names, while those with p_cols_visible set define which RTEs are + * accessible by unqualified names. These sets are different because a JOIN + * without an alias does not hide the contained tables (so they must be + * visible for qualified references) but it does hide their columns + * (unqualified references to the columns refer to the JOIN, not the member + * tables, so we must not complain that such a reference is ambiguous). + * Various special RTEs such as NEW/OLD for rules may also appear with only + * one flag set. + * + * While processing the FROM clause, namespace items may appear with + * p_lateral_only set, meaning they are visible only to LATERAL + * subexpressions. (The pstate's p_lateral_active flag tells whether we are + * inside such a subexpression at the moment.) If p_lateral_ok is not set, + * it's an error to actually use such a namespace item. One might think it + * would be better to just exclude such items from visibility, but the wording + * of SQL:2008 requires us to do it this way. We also use p_lateral_ok to + * forbid LATERAL references to an UPDATE/DELETE target table. + * + * At no time should a namespace list contain two entries that conflict + * according to the rules in checkNameSpaceConflicts; but note that those + * are more complicated than "must have different alias names", so in practice + * code searching a namespace list has to check for ambiguous references. + */ +struct ParseNamespaceItem +{ + Alias *p_names; /* Table and column names */ + RangeTblEntry *p_rte; /* The relation's rangetable entry */ + int p_rtindex; /* The relation's index in the rangetable */ + /* array of same length as p_names->colnames: */ + ParseNamespaceColumn *p_nscolumns; /* per-column data */ + bool p_rel_visible; /* Relation name is visible? */ + bool p_cols_visible; /* Column names visible as unqualified refs? */ + bool p_lateral_only; /* Is only visible to LATERAL expressions? */ + bool p_lateral_ok; /* If so, does join type allow use? */ +}; + +/* + * Data about one column of a ParseNamespaceItem. + * + * We track the info needed to construct a Var referencing the column + * (but only for user-defined columns; system column references and + * whole-row references are handled separately). + * + * p_varno and p_varattno identify the semantic referent, which is a + * base-relation column unless the reference is to a join USING column that + * isn't semantically equivalent to either join input column (because it is a + * FULL join or the input column requires a type coercion). In those cases + * p_varno and p_varattno refer to the JOIN RTE. + * + * p_varnosyn and p_varattnosyn are either identical to p_varno/p_varattno, + * or they specify the column's position in an aliased JOIN RTE that hides + * the semantic referent RTE's refname. (That could be either the JOIN RTE + * in which this ParseNamespaceColumn entry exists, or some lower join level.) + * + * If an RTE contains a dropped column, its ParseNamespaceColumn struct + * is all-zeroes. (Conventionally, test for p_varno == 0 to detect this.) + */ +struct ParseNamespaceColumn +{ + Index p_varno; /* rangetable index */ + AttrNumber p_varattno; /* attribute number of the column */ + Oid p_vartype; /* pg_type OID */ + int32 p_vartypmod; /* type modifier value */ + Oid p_varcollid; /* OID of collation, or InvalidOid */ + Index p_varnosyn; /* rangetable index of syntactic referent */ + AttrNumber p_varattnosyn; /* attribute number of syntactic referent */ + bool p_dontexpand; /* not included in star expansion */ +}; + +/* Support for parser_errposition_callback function */ +typedef struct ParseCallbackState +{ + ParseState *pstate; + int location; + ErrorContextCallback errcallback; +} ParseCallbackState; + + +extern ParseState *make_parsestate(ParseState *parentParseState); +extern void free_parsestate(ParseState *pstate); +extern int parser_errposition(ParseState *pstate, int location); + +extern void setup_parser_errposition_callback(ParseCallbackState *pcbstate, + ParseState *pstate, int location); +extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate); + +extern void transformContainerType(Oid *containerType, int32 *containerTypmod); + +extern SubscriptingRef *transformContainerSubscripts(ParseState *pstate, + Node *containerBase, + Oid containerType, + int32 containerTypMod, + List *indirection, + bool isAssignment); +extern Const *make_const(ParseState *pstate, A_Const *aconst); + +#endif /* PARSE_NODE_H */ diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h new file mode 100644 index 0000000..e15b622 --- /dev/null +++ b/src/include/parser/parse_oper.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + * + * parse_oper.h + * handle operator things for parser + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_oper.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_OPER_H +#define PARSE_OPER_H + +#include "access/htup.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" + + +typedef HeapTuple Operator; + +/* Routines to look up an operator given name and exact input type(s) */ +extern Oid LookupOperName(ParseState *pstate, List *opername, + Oid oprleft, Oid oprright, + bool noError, int location); +extern Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError); + +/* Routines to find operators matching a name and given input types */ +/* NB: the selected operator may require coercion of the input types! */ +extern Operator oper(ParseState *pstate, List *op, Oid arg1, Oid arg2, + bool noError, int location); +extern Operator left_oper(ParseState *pstate, List *op, Oid arg, + bool noError, int location); + +/* Routines to find operators that DO NOT require coercion --- ie, their */ +/* input types are either exactly as given, or binary-compatible */ +extern Operator compatible_oper(ParseState *pstate, List *op, + Oid arg1, Oid arg2, + bool noError, int location); + +/* currently no need for compatible_left_oper/compatible_right_oper */ + +/* Routines for identifying "<", "=", ">" operators for a type */ +extern void get_sort_group_operators(Oid argtype, + bool needLT, bool needEQ, bool needGT, + Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, + bool *isHashable); + +/* Convenience routines for common calls on the above */ +extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError); + +/* Extract operator OID or underlying-function OID from an Operator tuple */ +extern Oid oprid(Operator op); +extern Oid oprfuncid(Operator op); + +/* Build expression tree for an operator invocation */ +extern Expr *make_op(ParseState *pstate, List *opname, + Node *ltree, Node *rtree, Node *last_srf, int location); +extern Expr *make_scalar_array_op(ParseState *pstate, List *opname, + bool useOr, + Node *ltree, Node *rtree, int location); + +#endif /* PARSE_OPER_H */ diff --git a/src/include/parser/parse_param.h b/src/include/parser/parse_param.h new file mode 100644 index 0000000..df1ee66 --- /dev/null +++ b/src/include/parser/parse_param.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * parse_param.h + * handle parameters in parser + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_param.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_PARAM_H +#define PARSE_PARAM_H + +#include "parser/parse_node.h" + +extern void setup_parse_fixed_parameters(ParseState *pstate, + const Oid *paramTypes, int numParams); +extern void setup_parse_variable_parameters(ParseState *pstate, + Oid **paramTypes, int *numParams); +extern void check_variable_parameters(ParseState *pstate, Query *query); +extern bool query_contains_extern_params(Query *query); + +#endif /* PARSE_PARAM_H */ diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h new file mode 100644 index 0000000..de21c3c --- /dev/null +++ b/src/include/parser/parse_relation.h @@ -0,0 +1,124 @@ +/*------------------------------------------------------------------------- + * + * parse_relation.h + * prototypes for parse_relation.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_relation.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_RELATION_H +#define PARSE_RELATION_H + +#include "parser/parse_node.h" + + +extern ParseNamespaceItem *refnameNamespaceItem(ParseState *pstate, + const char *schemaname, + const char *refname, + int location, + int *sublevels_up); +extern CommonTableExpr *scanNameSpaceForCTE(ParseState *pstate, + const char *refname, + Index *ctelevelsup); +extern bool scanNameSpaceForENR(ParseState *pstate, const char *refname); +extern void checkNameSpaceConflicts(ParseState *pstate, List *namespace1, + List *namespace2); +extern ParseNamespaceItem *GetNSItemByRangeTablePosn(ParseState *pstate, + int varno, + int sublevels_up); +extern RangeTblEntry *GetRTEByRangeTablePosn(ParseState *pstate, + int varno, + int sublevels_up); +extern CommonTableExpr *GetCTEForRTE(ParseState *pstate, RangeTblEntry *rte, + int rtelevelsup); +extern Node *scanNSItemForColumn(ParseState *pstate, ParseNamespaceItem *nsitem, + int sublevels_up, const char *colname, + int location); +extern Node *colNameToVar(ParseState *pstate, const char *colname, bool localonly, + int location); +extern void markVarForSelectPriv(ParseState *pstate, Var *var); +extern Relation parserOpenTable(ParseState *pstate, const RangeVar *relation, + int lockmode); +extern ParseNamespaceItem *addRangeTableEntry(ParseState *pstate, + RangeVar *relation, + Alias *alias, + bool inh, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForRelation(ParseState *pstate, + Relation rel, + int lockmode, + Alias *alias, + bool inh, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForSubquery(ParseState *pstate, + Query *subquery, + Alias *alias, + bool lateral, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForFunction(ParseState *pstate, + List *funcnames, + List *funcexprs, + List *coldeflists, + RangeFunction *rangefunc, + bool lateral, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForValues(ParseState *pstate, + List *exprs, + List *coltypes, + List *coltypmods, + List *colcollations, + Alias *alias, + bool lateral, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForTableFunc(ParseState *pstate, + TableFunc *tf, + Alias *alias, + bool lateral, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForJoin(ParseState *pstate, + List *colnames, + ParseNamespaceColumn *nscolumns, + JoinType jointype, + int nummergedcols, + List *aliasvars, + List *leftcols, + List *rightcols, + Alias *joinalias, + Alias *alias, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForCTE(ParseState *pstate, + CommonTableExpr *cte, + Index levelsup, + RangeVar *rv, + bool inFromCl); +extern ParseNamespaceItem *addRangeTableEntryForENR(ParseState *pstate, + RangeVar *rv, + bool inFromCl); +extern bool isLockedRefname(ParseState *pstate, const char *refname); +extern void addNSItemToQuery(ParseState *pstate, ParseNamespaceItem *nsitem, + bool addToJoinList, + bool addToRelNameSpace, bool addToVarNameSpace); +extern void errorMissingRTE(ParseState *pstate, RangeVar *relation) pg_attribute_noreturn(); +extern void errorMissingColumn(ParseState *pstate, + const char *relname, const char *colname, int location) pg_attribute_noreturn(); +extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, + int location, bool include_dropped, + List **colnames, List **colvars); +extern List *expandNSItemVars(ParseNamespaceItem *nsitem, + int sublevels_up, int location, + List **colnames); +extern List *expandNSItemAttrs(ParseState *pstate, ParseNamespaceItem *nsitem, + int sublevels_up, bool require_col_privs, + int location); +extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK); +extern const NameData *attnumAttName(Relation rd, int attid); +extern Oid attnumTypeId(Relation rd, int attid); +extern Oid attnumCollationId(Relation rd, int attid); +extern bool isQueryUsingTempRelation(Query *query); + +#endif /* PARSE_RELATION_H */ diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h new file mode 100644 index 0000000..342e0d0 --- /dev/null +++ b/src/include/parser/parse_target.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * parse_target.h + * handle target lists + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_target.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_TARGET_H +#define PARSE_TARGET_H + +#include "parser/parse_node.h" + + +extern List *transformTargetList(ParseState *pstate, List *targetlist, + ParseExprKind exprKind); +extern List *transformExpressionList(ParseState *pstate, List *exprlist, + ParseExprKind exprKind, bool allowDefault); +extern void resolveTargetListUnknowns(ParseState *pstate, List *targetlist); +extern void markTargetListOrigins(ParseState *pstate, List *targetlist); +extern TargetEntry *transformTargetEntry(ParseState *pstate, + Node *node, Node *expr, ParseExprKind exprKind, + char *colname, bool resjunk); +extern Expr *transformAssignedExpr(ParseState *pstate, Expr *expr, + ParseExprKind exprKind, + const char *colname, + int attrno, + List *indirection, + int location); +extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle, + char *colname, int attrno, + List *indirection, + int location); +extern Node *transformAssignmentIndirection(ParseState *pstate, + Node *basenode, + const char *targetName, + bool targetIsSubscripting, + Oid targetTypeId, + int32 targetTypMod, + Oid targetCollation, + List *indirection, + ListCell *indirection_cell, + Node *rhs, + CoercionContext ccontext, + int location); +extern List *checkInsertTargets(ParseState *pstate, List *cols, + List **attrnos); +extern TupleDesc expandRecordVariable(ParseState *pstate, Var *var, + int levelsup); +extern char *FigureColname(Node *node); +extern char *FigureIndexColname(Node *node); + +#endif /* PARSE_TARGET_H */ diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h new file mode 100644 index 0000000..4e5624d --- /dev/null +++ b/src/include/parser/parse_type.h @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------- + * + * parse_type.h + * handle type operations for parser + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_type.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_TYPE_H +#define PARSE_TYPE_H + +#include "access/htup.h" +#include "parser/parse_node.h" + + +typedef HeapTuple Type; + +extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName, + int32 *typmod_p, bool missing_ok); +extern Type LookupTypeNameExtended(ParseState *pstate, + const TypeName *typeName, int32 *typmod_p, + bool temp_ok, bool missing_ok); +extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, + bool missing_ok); +extern Type typenameType(ParseState *pstate, const TypeName *typeName, + int32 *typmod_p); +extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName); +extern void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, + Oid *typeid_p, int32 *typmod_p); + +extern char *TypeNameToString(const TypeName *typeName); +extern char *TypeNameListToString(List *typenames); + +extern Oid LookupCollation(ParseState *pstate, List *collnames, int location); +extern Oid GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid); + +extern Type typeidType(Oid id); + +extern Oid typeTypeId(Type tp); +extern int16 typeLen(Type t); +extern bool typeByVal(Type t); +extern char *typeTypeName(Type t); +extern Oid typeTypeRelid(Type typ); +extern Oid typeTypeCollation(Type typ); +extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod); + +extern Oid typeidTypeRelid(Oid type_id); +extern Oid typeOrDomainTypeRelid(Oid type_id); + +extern TypeName *typeStringToTypeName(const char *str); +extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok); + +/* true if typeid is composite, or domain over composite, but not RECORD */ +#define ISCOMPLEX(typeid) (typeOrDomainTypeRelid(typeid) != InvalidOid) + +#endif /* PARSE_TYPE_H */ diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h new file mode 100644 index 0000000..11160ad --- /dev/null +++ b/src/include/parser/parse_utilcmd.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * parse_utilcmd.h + * parse analysis for utility commands + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parse_utilcmd.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSE_UTILCMD_H +#define PARSE_UTILCMD_H + +#include "parser/parse_node.h" + +struct AttrMap; /* avoid including attmap.h here */ + + +extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString); +extern AlterTableStmt *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, + const char *queryString, + List **beforeStmts, + List **afterStmts); +extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt, + const char *queryString); +extern CreateStatsStmt *transformStatsStmt(Oid relid, CreateStatsStmt *stmt, + const char *queryString); +extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, + List **actions, Node **whereClause); +extern List *transformCreateSchemaStmtElements(List *schemaElts, + const char *schemaName); +extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent, + PartitionBoundSpec *spec); +extern List *expandTableLikeClause(RangeVar *heapRel, + TableLikeClause *table_like_clause); +extern IndexStmt *generateClonedIndexStmt(RangeVar *heapRel, + Relation source_idx, + const struct AttrMap *attmap, + Oid *constraintOid); + +#endif /* PARSE_UTILCMD_H */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h new file mode 100644 index 0000000..828150f --- /dev/null +++ b/src/include/parser/parser.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + * + * parser.h + * Definitions for the "raw" parser (flex and bison phases only) + * + * This is the external API for the raw lexing/parsing functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parser.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSER_H +#define PARSER_H + +#include "nodes/parsenodes.h" + + +/* + * RawParseMode determines the form of the string that raw_parser() accepts: + * + * RAW_PARSE_DEFAULT: parse a semicolon-separated list of SQL commands, + * and return a List of RawStmt nodes. + * + * RAW_PARSE_TYPE_NAME: parse a type name, and return a one-element List + * containing a TypeName node. + * + * RAW_PARSE_PLPGSQL_EXPR: parse a PL/pgSQL expression, and return + * a one-element List containing a RawStmt node. + * + * RAW_PARSE_PLPGSQL_ASSIGNn: parse a PL/pgSQL assignment statement, + * and return a one-element List containing a RawStmt node. "n" + * gives the number of dotted names comprising the target ColumnRef. + */ +typedef enum +{ + RAW_PARSE_DEFAULT = 0, + RAW_PARSE_TYPE_NAME, + RAW_PARSE_PLPGSQL_EXPR, + RAW_PARSE_PLPGSQL_ASSIGN1, + RAW_PARSE_PLPGSQL_ASSIGN2, + RAW_PARSE_PLPGSQL_ASSIGN3 +} RawParseMode; + +/* Values for the backslash_quote GUC */ +typedef enum +{ + BACKSLASH_QUOTE_OFF, + BACKSLASH_QUOTE_ON, + BACKSLASH_QUOTE_SAFE_ENCODING +} BackslashQuoteType; + +/* GUC variables in scan.l (every one of these is a bad idea :-() */ +extern PGDLLIMPORT int backslash_quote; +extern PGDLLIMPORT bool escape_string_warning; +extern PGDLLIMPORT bool standard_conforming_strings; + + +/* Primary entry point for the raw parsing functions */ +extern List *raw_parser(const char *str, RawParseMode mode); + +/* Utility functions exported by gram.y (perhaps these should be elsewhere) */ +extern List *SystemFuncName(char *name); +extern TypeName *SystemTypeName(char *name); + +#endif /* PARSER_H */ diff --git a/src/include/parser/parsetree.h b/src/include/parser/parsetree.h new file mode 100644 index 0000000..3a1afff --- /dev/null +++ b/src/include/parser/parsetree.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * parsetree.h + * Routines to access various components and subcomponents of + * parse trees. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/parsetree.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARSETREE_H +#define PARSETREE_H + +#include "nodes/parsenodes.h" + + +/* ---------------- + * range table operations + * ---------------- + */ + +/* + * rt_fetch + * + * NB: this will crash and burn if handed an out-of-range RT index + */ +#define rt_fetch(rangetable_index, rangetable) \ + ((RangeTblEntry *) list_nth(rangetable, (rangetable_index)-1)) + +/* + * Given an RTE and an attribute number, return the appropriate + * variable name or alias for that attribute of that RTE. + */ +extern char *get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum); + +/* + * Check whether an attribute of an RTE has been dropped + */ +extern bool get_rte_attribute_is_dropped(RangeTblEntry *rte, + AttrNumber attnum); + + +/* ---------------- + * target list operations + * ---------------- + */ + +extern TargetEntry *get_tle_by_resno(List *tlist, AttrNumber resno); + +/* ---------------- + * FOR UPDATE/SHARE info + * ---------------- + */ + +extern RowMarkClause *get_parse_rowmark(Query *qry, Index rtindex); + +#endif /* PARSETREE_H */ diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h new file mode 100644 index 0000000..0843481 --- /dev/null +++ b/src/include/parser/scanner.h @@ -0,0 +1,150 @@ +/*------------------------------------------------------------------------- + * + * scanner.h + * API for the core scanner (flex machine) + * + * The core scanner is also used by PL/pgSQL, so we provide a public API + * for it. However, the rest of the backend is only expected to use the + * higher-level API provided by parser.h. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/scanner.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SCANNER_H +#define SCANNER_H + +#include "common/keywords.h" + +/* + * The scanner returns extra data about scanned tokens in this union type. + * Note that this is a subset of the fields used in YYSTYPE of the bison + * parsers built atop the scanner. + */ +typedef union core_YYSTYPE +{ + int ival; /* for integer literals */ + char *str; /* for identifiers and non-integer literals */ + const char *keyword; /* canonical spelling of keywords */ +} core_YYSTYPE; + +/* + * We track token locations in terms of byte offsets from the start of the + * source string, not the column number/line number representation that + * bison uses by default. Also, to minimize overhead we track only one + * location (usually the first token location) for each construct, not + * the beginning and ending locations as bison does by default. It's + * therefore sufficient to make YYLTYPE an int. + */ +#define YYLTYPE int + +/* + * Another important component of the scanner's API is the token code numbers. + * However, those are not defined in this file, because bison insists on + * defining them for itself. The token codes used by the core scanner are + * the ASCII characters plus these: + * %token <str> IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op + * %token <ival> ICONST PARAM + * %token TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER + * %token LESS_EQUALS GREATER_EQUALS NOT_EQUALS + * The above token definitions *must* be the first ones declared in any + * bison parser built atop this scanner, so that they will have consistent + * numbers assigned to them (specifically, IDENT = 258 and so on). + */ + +/* + * The YY_EXTRA data that a flex scanner allows us to pass around. + * Private state needed by the core scanner goes here. Note that the actual + * yy_extra struct may be larger and have this as its first component, thus + * allowing the calling parser to keep some fields of its own in YY_EXTRA. + */ +typedef struct core_yy_extra_type +{ + /* + * The string the scanner is physically scanning. We keep this mainly so + * that we can cheaply compute the offset of the current token (yytext). + */ + char *scanbuf; + Size scanbuflen; + + /* + * The keyword list to use, and the associated grammar token codes. + */ + const ScanKeywordList *keywordlist; + const uint16 *keyword_tokens; + + /* + * Scanner settings to use. These are initialized from the corresponding + * GUC variables by scanner_init(). Callers can modify them after + * scanner_init() if they don't want the scanner's behavior to follow the + * prevailing GUC settings. + */ + int backslash_quote; + bool escape_string_warning; + bool standard_conforming_strings; + + /* + * literalbuf is used to accumulate literal values when multiple rules are + * needed to parse a single literal. Call startlit() to reset buffer to + * empty, addlit() to add text. NOTE: the string in literalbuf is NOT + * necessarily null-terminated, but there always IS room to add a trailing + * null at offset literallen. We store a null only when we need it. + */ + char *literalbuf; /* palloc'd expandable buffer */ + int literallen; /* actual current string length */ + int literalalloc; /* current allocated buffer size */ + + /* + * Random assorted scanner state. + */ + int state_before_str_stop; /* start cond. before end quote */ + int xcdepth; /* depth of nesting in slash-star comments */ + char *dolqstart; /* current $foo$ quote start string */ + YYLTYPE save_yylloc; /* one-element stack for PUSH_YYLLOC() */ + + /* first part of UTF16 surrogate pair for Unicode escapes */ + int32 utf16_first_part; + + /* state variables for literal-lexing warnings */ + bool warn_on_first_escape; + bool saw_non_ascii; +} core_yy_extra_type; + +/* + * The type of yyscanner is opaque outside scan.l. + */ +typedef void *core_yyscan_t; + +/* Support for scanner_errposition_callback function */ +typedef struct ScannerCallbackState +{ + core_yyscan_t yyscanner; + int location; + ErrorContextCallback errcallback; +} ScannerCallbackState; + + +/* Constant data exported from parser/scan.l */ +extern PGDLLIMPORT const uint16 ScanKeywordTokens[]; + +/* Entry points in parser/scan.l */ +extern core_yyscan_t scanner_init(const char *str, + core_yy_extra_type *yyext, + const ScanKeywordList *keywordlist, + const uint16 *keyword_tokens); +extern void scanner_finish(core_yyscan_t yyscanner); +extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, + core_yyscan_t yyscanner); +extern int scanner_errposition(int location, core_yyscan_t yyscanner); +extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate, + core_yyscan_t yyscanner, + int location); +extern void cancel_scanner_errposition_callback(ScannerCallbackState *scbstate); +extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn(); + +#endif /* SCANNER_H */ diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h new file mode 100644 index 0000000..ff65224 --- /dev/null +++ b/src/include/parser/scansup.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------- + * + * scansup.h + * scanner support routines used by the core lexer + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/parser/scansup.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SCANSUP_H +#define SCANSUP_H + +extern char *downcase_truncate_identifier(const char *ident, int len, + bool warn); + +extern char *downcase_identifier(const char *ident, int len, + bool warn, bool truncate); + +extern void truncate_identifier(char *ident, int len, bool warn); + +extern bool scanner_isspace(char ch); + +#endif /* SCANSUP_H */ diff --git a/src/include/partitioning/partbounds.h b/src/include/partitioning/partbounds.h new file mode 100644 index 0000000..b1e3f1b --- /dev/null +++ b/src/include/partitioning/partbounds.h @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------- + * + * partbounds.h + * + * Copyright (c) 2007-2022, PostgreSQL Global Development Group + * + * src/include/partitioning/partbounds.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTBOUNDS_H +#define PARTBOUNDS_H + +#include "fmgr.h" +#include "parser/parse_node.h" +#include "partitioning/partdefs.h" + +struct RelOptInfo; /* avoid including pathnodes.h here */ + + +/* + * PartitionBoundInfoData encapsulates a set of partition bounds. It is + * usually associated with partitioned tables as part of its partition + * descriptor, but may also be used to represent a virtual partitioned + * table such as a partitioned joinrel within the planner. + * + * A list partition datum that is known to be NULL is never put into the + * datums array. Instead, it is tracked using the null_index field. + * + * In the case of range partitioning, ndatums will typically be far less than + * 2 * nparts, because a partition's upper bound and the next partition's lower + * bound are the same in most common cases, and we only store one of them (the + * upper bound). In case of hash partitioning, ndatums will be the same as the + * number of partitions. + * + * For range and list partitioned tables, datums is an array of datum-tuples + * with key->partnatts datums each. For hash partitioned tables, it is an array + * of datum-tuples with 2 datums, modulus and remainder, corresponding to a + * given partition. + * + * The datums in datums array are arranged in increasing order as defined by + * functions qsort_partition_rbound_cmp(), qsort_partition_list_value_cmp() and + * qsort_partition_hbound_cmp() for range, list and hash partitioned tables + * respectively. For range and list partitions this simply means that the + * datums in the datums array are arranged in increasing order as defined by + * the partition key's operator classes and collations. + * + * In the case of list partitioning, the indexes array stores one entry for + * each datum-array entry, which is the index of the partition that accepts + * rows matching that datum. So nindexes == ndatums. + * + * In the case of range partitioning, the indexes array stores one entry per + * distinct range datum, which is the index of the partition for which that + * datum is an upper bound (or -1 for a "gap" that has no partition). It is + * convenient to have an extra -1 entry representing values above the last + * range datum, so nindexes == ndatums + 1. + * + * In the case of hash partitioning, the number of entries in the indexes + * array is the same as the greatest modulus amongst all partitions (which + * is a multiple of all partition moduli), so nindexes == greatest modulus. + * The indexes array is indexed according to the hash key's remainder modulo + * the greatest modulus, and it contains either the partition index accepting + * that remainder, or -1 if there is no partition for that remainder. + * + * For LIST partitioned tables, we track the partition indexes of partitions + * which are possibly "interleaved" partitions. A partition is considered + * interleaved if it allows multiple values and there exists at least one + * other partition which could contain a value that lies between those values. + * For example, if a partition exists FOR VALUES IN(3,5) and another partition + * exists FOR VALUES IN (4), then the IN(3,5) partition is an interleaved + * partition. The same is possible with DEFAULT partitions since they can + * contain any value that does not belong in another partition. This field + * only serves as proof that a particular partition is not interleaved, not + * proof that it is interleaved. When we're uncertain, we marked the + * partition as interleaved. The interleaved_parts field is only ever set for + * RELOPT_BASEREL and RELOPT_OTHER_MEMBER_REL, it is always left NULL for join + * relations. + */ +typedef struct PartitionBoundInfoData +{ + char strategy; /* hash, list or range? */ + int ndatums; /* Length of the datums[] array */ + Datum **datums; + PartitionRangeDatumKind **kind; /* The kind of each range bound datum; + * NULL for hash and list partitioned + * tables */ + Bitmapset *interleaved_parts; /* Partition indexes of partitions which + * may be interleaved. See above. This is + * only set for LIST partitioned tables */ + int nindexes; /* Length of the indexes[] array */ + int *indexes; /* Partition indexes */ + int null_index; /* Index of the null-accepting partition; -1 + * if there isn't one */ + int default_index; /* Index of the default partition; -1 if there + * isn't one */ +} PartitionBoundInfoData; + +#define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1) +#define partition_bound_has_default(bi) ((bi)->default_index != -1) + +extern int get_hash_partition_greatest_modulus(PartitionBoundInfo b); +extern uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc, + Oid *partcollation, + Datum *values, bool *isnull); +extern List *get_qual_from_partbound(Relation parent, + PartitionBoundSpec *spec); +extern PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs, + int nparts, PartitionKey key, int **mapping); +extern bool partition_bounds_equal(int partnatts, int16 *parttyplen, + bool *parttypbyval, PartitionBoundInfo b1, + PartitionBoundInfo b2); +extern PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, + PartitionKey key); +extern PartitionBoundInfo partition_bounds_merge(int partnatts, + FmgrInfo *partsupfunc, + Oid *partcollation, + struct RelOptInfo *outer_rel, + struct RelOptInfo *inner_rel, + JoinType jointype, + List **outer_parts, + List **inner_parts); +extern bool partitions_are_ordered(PartitionBoundInfo boundinfo, + Bitmapset *live_parts); +extern void check_new_partition_bound(char *relname, Relation parent, + PartitionBoundSpec *spec, + ParseState *pstate); +extern void check_default_partition_contents(Relation parent, + Relation defaultRel, + PartitionBoundSpec *new_spec); + +extern int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, + Oid *partcollation, + Datum *rb_datums, PartitionRangeDatumKind *rb_kind, + Datum *tuple_datums, int n_tuple_datums); +extern int partition_list_bsearch(FmgrInfo *partsupfunc, + Oid *partcollation, + PartitionBoundInfo boundinfo, + Datum value, bool *is_equal); +extern int partition_range_datum_bsearch(FmgrInfo *partsupfunc, + Oid *partcollation, + PartitionBoundInfo boundinfo, + int nvalues, Datum *values, bool *is_equal); +extern int partition_hash_bsearch(PartitionBoundInfo boundinfo, + int modulus, int remainder); + +#endif /* PARTBOUNDS_H */ diff --git a/src/include/partitioning/partdefs.h b/src/include/partitioning/partdefs.h new file mode 100644 index 0000000..aed62ea --- /dev/null +++ b/src/include/partitioning/partdefs.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * partdefs.h + * Base definitions for partitioned table handling + * + * Copyright (c) 2007-2022, PostgreSQL Global Development Group + * + * src/include/partitioning/partdefs.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTDEFS_H +#define PARTDEFS_H + + +typedef struct PartitionBoundInfoData *PartitionBoundInfo; + +typedef struct PartitionKeyData *PartitionKey; + +typedef struct PartitionBoundSpec PartitionBoundSpec; + +typedef struct PartitionDescData *PartitionDesc; + +typedef struct PartitionDirectoryData *PartitionDirectory; + +#endif /* PARTDEFS_H */ diff --git a/src/include/partitioning/partdesc.h b/src/include/partitioning/partdesc.h new file mode 100644 index 0000000..ae1afe3 --- /dev/null +++ b/src/include/partitioning/partdesc.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * partdesc.h + * + * Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/partitioning/partdesc.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PARTDESC_H +#define PARTDESC_H + +#include "partitioning/partdefs.h" +#include "utils/relcache.h" + +/* + * Information about partitions of a partitioned table. + * + * For partitioned tables where detached partitions exist, we only cache + * descriptors that include all partitions, including detached; when we're + * requested a descriptor without the detached partitions, we create one + * afresh each time. (The reason for this is that the set of detached + * partitions that are visible to each caller depends on the snapshot it has, + * so it's pretty much impossible to evict a descriptor from cache at the + * right time.) + */ +typedef struct PartitionDescData +{ + int nparts; /* Number of partitions */ + bool detached_exist; /* Are there any detached partitions? */ + Oid *oids; /* Array of 'nparts' elements containing + * partition OIDs in order of the their bounds */ + bool *is_leaf; /* Array of 'nparts' elements storing whether + * the corresponding 'oids' element belongs to + * a leaf partition or not */ + PartitionBoundInfo boundinfo; /* collection of partition bounds */ +} PartitionDescData; + + +extern PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached); + +extern PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt, bool omit_detached); +extern PartitionDesc PartitionDirectoryLookup(PartitionDirectory, Relation); +extern void DestroyPartitionDirectory(PartitionDirectory pdir); + +extern Oid get_default_oid_from_partdesc(PartitionDesc partdesc); + +#endif /* PARTCACHE_H */ diff --git a/src/include/partitioning/partprune.h b/src/include/partitioning/partprune.h new file mode 100644 index 0000000..90684ef --- /dev/null +++ b/src/include/partitioning/partprune.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * partprune.h + * prototypes for partprune.c + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/partitioning/partprune.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTPRUNE_H +#define PARTPRUNE_H + +#include "nodes/execnodes.h" +#include "partitioning/partdefs.h" + +struct PlannerInfo; /* avoid including pathnodes.h here */ +struct RelOptInfo; + + +/* + * PartitionPruneContext + * Stores information needed at runtime for pruning computations + * related to a single partitioned table. + * + * strategy Partition strategy, e.g. LIST, RANGE, HASH. + * partnatts Number of columns in the partition key. + * nparts Number of partitions in this partitioned table. + * boundinfo Partition boundary info for the partitioned table. + * partcollation Array of partnatts elements, storing the collations of the + * partition key columns. + * partsupfunc Array of FmgrInfos for the comparison or hashing functions + * associated with the partition keys (partnatts elements). + * (This points into the partrel's partition key, typically.) + * stepcmpfuncs Array of FmgrInfos for the comparison or hashing function + * for each pruning step and partition key. + * ppccontext Memory context holding this PartitionPruneContext's + * subsidiary data, such as the FmgrInfos. + * planstate Points to the parent plan node's PlanState when called + * during execution; NULL when called from the planner. + * exprcontext ExprContext to use when evaluating pruning expressions + * exprstates Array of ExprStates, indexed as per PruneCxtStateIdx; one + * for each partition key in each pruning step. Allocated if + * planstate is non-NULL, otherwise NULL. + */ +typedef struct PartitionPruneContext +{ + char strategy; + int partnatts; + int nparts; + PartitionBoundInfo boundinfo; + Oid *partcollation; + FmgrInfo *partsupfunc; + FmgrInfo *stepcmpfuncs; + MemoryContext ppccontext; + PlanState *planstate; + ExprContext *exprcontext; + ExprState **exprstates; +} PartitionPruneContext; + +/* + * PruneCxtStateIdx() computes the correct index into the stepcmpfuncs[] + * and exprstates[] arrays for step step_id and partition key column keyno. + * (Note: there is code that assumes the entries for a given step are + * sequential, so this is not chosen freely.) + */ +#define PruneCxtStateIdx(partnatts, step_id, keyno) \ + ((partnatts) * (step_id) + (keyno)) + +extern PartitionPruneInfo *make_partition_pruneinfo(struct PlannerInfo *root, + struct RelOptInfo *parentrel, + List *subpaths, + List *prunequal); +extern Bitmapset *prune_append_rel_partitions(struct RelOptInfo *rel); +extern Bitmapset *get_matching_partitions(PartitionPruneContext *context, + List *pruning_steps); + +#endif /* PARTPRUNE_H */ diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in new file mode 100644 index 0000000..d09e9f9 --- /dev/null +++ b/src/include/pg_config.h.in @@ -0,0 +1,1025 @@ +/* src/include/pg_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* The normal alignment of `double', in bytes. */ +#undef ALIGNOF_DOUBLE + +/* The normal alignment of `int', in bytes. */ +#undef ALIGNOF_INT + +/* The normal alignment of `long', in bytes. */ +#undef ALIGNOF_LONG + +/* The normal alignment of `long long int', in bytes. */ +#undef ALIGNOF_LONG_LONG_INT + +/* The normal alignment of `PG_INT128_TYPE', in bytes. */ +#undef ALIGNOF_PG_INT128_TYPE + +/* The normal alignment of `short', in bytes. */ +#undef ALIGNOF_SHORT + +/* Size of a disk block --- this also limits the size of a tuple. You can set + it bigger if you need bigger tuples (although TOAST should reduce the need + to have large tuples, since fields can be spread across multiple tuples). + BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is + currently 2^15 (32768). This is determined by the 15-bit widths of the + lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h). + Changing BLCKSZ requires an initdb. */ +#undef BLCKSZ + +/* Saved arguments from configure */ +#undef CONFIGURE_ARGS + +/* Define to the default TCP port number on which the server listens and to + which clients will try to connect. This can be overridden at run-time, but + it's convenient if your clients have the right default compiled in. + (--with-pgport=PORTNUM) */ +#undef DEF_PGPORT + +/* Define to the default TCP port number as a string constant. */ +#undef DEF_PGPORT_STR + +/* Define to the file name extension of dynamically-loadable modules. */ +#undef DLSUFFIX + +/* Define to build with GSSAPI support. (--with-gssapi) */ +#undef ENABLE_GSS + +/* Define to 1 if you want National Language Support. (--enable-nls) */ +#undef ENABLE_NLS + +/* Define to 1 to build client libraries as thread-safe code. + (--enable-thread-safety) */ +#undef ENABLE_THREAD_SAFETY + +/* Define to 1 if gettimeofday() takes only 1 argument. */ +#undef GETTIMEOFDAY_1ARG + +#ifdef GETTIMEOFDAY_1ARG +# define gettimeofday(a,b) gettimeofday(a) +#endif + +/* Define to 1 if you have the `append_history' function. */ +#undef HAVE_APPEND_HISTORY + +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#undef HAVE_ASN1_STRING_GET0_DATA + +/* Define to 1 if you want to use atomics if available. */ +#undef HAVE_ATOMICS + +/* Define to 1 if you have the <atomic.h> header file. */ +#undef HAVE_ATOMIC_H + +/* Define to 1 if you have the `backtrace_symbols' function. */ +#undef HAVE_BACKTRACE_SYMBOLS + +/* Define to 1 if you have the `BIO_get_data' function. */ +#undef HAVE_BIO_GET_DATA + +/* Define to 1 if you have the `BIO_meth_new' function. */ +#undef HAVE_BIO_METH_NEW + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if your compiler handles computed gotos. */ +#undef HAVE_COMPUTED_GOTO + +/* Define to 1 if you have the `copyfile' function. */ +#undef HAVE_COPYFILE + +/* Define to 1 if you have the <copyfile.h> header file. */ +#undef HAVE_COPYFILE_H + +/* Define to 1 if you have the <crtdefs.h> header file. */ +#undef HAVE_CRTDEFS_H + +/* Define to 1 if you have the `CRYPTO_lock' function. */ +#undef HAVE_CRYPTO_LOCK + +/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you + don't. */ +#undef HAVE_DECL_FDATASYNC + +/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you + don't. */ +#undef HAVE_DECL_F_FULLFSYNC + +/* Define to 1 if you have the declaration of + `LLVMCreateGDBRegistrationListener', and to 0 if you don't. */ +#undef HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER + +/* Define to 1 if you have the declaration of + `LLVMCreatePerfJITEventListener', and to 0 if you don't. */ +#undef HAVE_DECL_LLVMCREATEPERFJITEVENTLISTENER + +/* Define to 1 if you have the declaration of `LLVMGetHostCPUFeatures', and to + 0 if you don't. */ +#undef HAVE_DECL_LLVMGETHOSTCPUFEATURES + +/* Define to 1 if you have the declaration of `LLVMGetHostCPUName', and to 0 + if you don't. */ +#undef HAVE_DECL_LLVMGETHOSTCPUNAME + +/* Define to 1 if you have the declaration of `LLVMOrcGetSymbolAddressIn', and + to 0 if you don't. */ +#undef HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN + +/* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you + don't. */ +#undef HAVE_DECL_POSIX_FADVISE + +/* Define to 1 if you have the declaration of `preadv', and to 0 if you don't. + */ +#undef HAVE_DECL_PREADV + +/* Define to 1 if you have the declaration of `pwritev', and to 0 if you + don't. */ +#undef HAVE_DECL_PWRITEV + +/* Define to 1 if you have the declaration of `RTLD_GLOBAL', and to 0 if you + don't. */ +#undef HAVE_DECL_RTLD_GLOBAL + +/* Define to 1 if you have the declaration of `RTLD_NOW', and to 0 if you + don't. */ +#undef HAVE_DECL_RTLD_NOW + +/* Define to 1 if you have the declaration of `sigwait', and to 0 if you + don't. */ +#undef HAVE_DECL_SIGWAIT + +/* Define to 1 if you have the declaration of `strlcat', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCAT + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCPY + +/* Define to 1 if you have the declaration of `strnlen', and to 0 if you + don't. */ +#undef HAVE_DECL_STRNLEN + +/* Define to 1 if you have the declaration of `strtoll', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOLL + +/* Define to 1 if you have the declaration of `strtoull', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOULL + +/* Define to 1 if you have the `dlopen' function. */ +#undef HAVE_DLOPEN + +/* Define to 1 if you have the <editline/history.h> header file. */ +#undef HAVE_EDITLINE_HISTORY_H + +/* Define to 1 if you have the <editline/readline.h> header file. */ +#undef HAVE_EDITLINE_READLINE_H + +/* Define to 1 if you have the <execinfo.h> header file. */ +#undef HAVE_EXECINFO_H + +/* Define to 1 if you have the `explicit_bzero' function. */ +#undef HAVE_EXPLICIT_BZERO + +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + +/* Define to 1 if you have the `fls' function. */ +#undef HAVE_FLS + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#undef HAVE_FSEEKO + +/* Define to 1 if your compiler understands __func__. */ +#undef HAVE_FUNCNAME__FUNC + +/* Define to 1 if your compiler understands __FUNCTION__. */ +#undef HAVE_FUNCNAME__FUNCTION + +/* Define to 1 if you have __atomic_compare_exchange_n(int *, int *, int). */ +#undef HAVE_GCC__ATOMIC_INT32_CAS + +/* Define to 1 if you have __atomic_compare_exchange_n(int64 *, int64 *, + int64). */ +#undef HAVE_GCC__ATOMIC_INT64_CAS + +/* Define to 1 if you have __sync_lock_test_and_set(char *) and friends. */ +#undef HAVE_GCC__SYNC_CHAR_TAS + +/* Define to 1 if you have __sync_val_compare_and_swap(int *, int, int). */ +#undef HAVE_GCC__SYNC_INT32_CAS + +/* Define to 1 if you have __sync_lock_test_and_set(int *) and friends. */ +#undef HAVE_GCC__SYNC_INT32_TAS + +/* Define to 1 if you have __sync_val_compare_and_swap(int64 *, int64, int64). + */ +#undef HAVE_GCC__SYNC_INT64_CAS + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `getifaddrs' function. */ +#undef HAVE_GETIFADDRS + +/* Define to 1 if you have the `getopt' function. */ +#undef HAVE_GETOPT + +/* Define to 1 if you have the <getopt.h> header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the `getopt_long' function. */ +#undef HAVE_GETOPT_LONG + +/* Define to 1 if you have the `getpeereid' function. */ +#undef HAVE_GETPEEREID + +/* Define to 1 if you have the `getpeerucred' function. */ +#undef HAVE_GETPEERUCRED + +/* Define to 1 if you have the `getpwuid_r' function. */ +#undef HAVE_GETPWUID_R + +/* Define to 1 if you have the `getrlimit' function. */ +#undef HAVE_GETRLIMIT + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the <gssapi/gssapi.h> header file. */ +#undef HAVE_GSSAPI_GSSAPI_H + +/* Define to 1 if you have the <gssapi.h> header file. */ +#undef HAVE_GSSAPI_H + +/* Define to 1 if you have the <history.h> header file. */ +#undef HAVE_HISTORY_H + +/* Define to 1 if you have the `history_truncate_file' function. */ +#undef HAVE_HISTORY_TRUNCATE_FILE + +/* Define to 1 if you have the `HMAC_CTX_free' function. */ +#undef HAVE_HMAC_CTX_FREE + +/* Define to 1 if you have the `HMAC_CTX_new' function. */ +#undef HAVE_HMAC_CTX_NEW + +/* Define to 1 if you have the <ifaddrs.h> header file. */ +#undef HAVE_IFADDRS_H + +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + +/* Define to 1 if you have the `inet_pton' function. */ +#undef HAVE_INET_PTON + +/* Define to 1 if the system has the type `int64'. */ +#undef HAVE_INT64 + +/* Define to 1 if the system has the type `int8'. */ +#undef HAVE_INT8 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the global variable 'int opterr'. */ +#undef HAVE_INT_OPTERR + +/* Define to 1 if you have the global variable 'int optreset'. */ +#undef HAVE_INT_OPTRESET + +/* Define to 1 if you have the global variable 'int timezone'. */ +#undef HAVE_INT_TIMEZONE + +/* Define to 1 if you have support for IPv6. */ +#undef HAVE_IPV6 + +/* Define to 1 if __builtin_constant_p(x) implies "i"(x) acceptance. */ +#undef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P + +/* Define to 1 if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* Define to 1 if you have the <langinfo.h> header file. */ +#undef HAVE_LANGINFO_H + +/* Define to 1 if you have the <ldap.h> header file. */ +#undef HAVE_LDAP_H + +/* Define to 1 if you have the `ldap_initialize' function. */ +#undef HAVE_LDAP_INITIALIZE + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if you have the `ldap' library (-lldap). */ +#undef HAVE_LIBLDAP + +/* Define to 1 if you have the `lz4' library (-llz4). */ +#undef HAVE_LIBLZ4 + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `pam' library (-lpam). */ +#undef HAVE_LIBPAM + +/* Define if you have a function readline library */ +#undef HAVE_LIBREADLINE + +/* Define to 1 if you have the `selinux' library (-lselinux). */ +#undef HAVE_LIBSELINUX + +/* Define to 1 if you have the `ssl' library (-lssl). */ +#undef HAVE_LIBSSL + +/* Define to 1 if you have the `wldap32' library (-lwldap32). */ +#undef HAVE_LIBWLDAP32 + +/* Define to 1 if you have the `xml2' library (-lxml2). */ +#undef HAVE_LIBXML2 + +/* Define to 1 if you have the `xslt' library (-lxslt). */ +#undef HAVE_LIBXSLT + +/* Define to 1 if you have the `z' library (-lz). */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#undef HAVE_LIBZSTD + +/* Define to 1 if you have the `link' function. */ +#undef HAVE_LINK + +/* Define to 1 if the system has the type `locale_t'. */ +#undef HAVE_LOCALE_T + +/* Define to 1 if `long int' works and is 64 bits. */ +#undef HAVE_LONG_INT_64 + +/* Define to 1 if `long long int' works and is 64 bits. */ +#undef HAVE_LONG_LONG_INT_64 + +/* Define to 1 if you have the <mbarrier.h> header file. */ +#undef HAVE_MBARRIER_H + +/* Define to 1 if you have the `mbstowcs_l' function. */ +#undef HAVE_MBSTOWCS_L + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset_s' function. */ +#undef HAVE_MEMSET_S + +/* Define to 1 if the system has the type `MINIDUMP_TYPE'. */ +#undef HAVE_MINIDUMP_TYPE + +/* Define to 1 if you have the `mkdtemp' function. */ +#undef HAVE_MKDTEMP + +/* Define to 1 if you have the <netinet/tcp.h> header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define to 1 if you have the <net/if.h> header file. */ +#undef HAVE_NET_IF_H + +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ +#undef HAVE_OPENSSL_INIT_SSL + +/* Define to 1 if you have the <ossp/uuid.h> header file. */ +#undef HAVE_OSSP_UUID_H + +/* Define to 1 if you have the <pam/pam_appl.h> header file. */ +#undef HAVE_PAM_PAM_APPL_H + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define to 1 if you have the <poll.h> header file. */ +#undef HAVE_POLL_H + +/* Define to 1 if you have a POSIX-conforming sigwait declaration. */ +#undef HAVE_POSIX_DECL_SIGWAIT + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_fallocate' function. */ +#undef HAVE_POSIX_FALLOCATE + +/* Define to 1 if the assembler supports PPC's LWARX mutex hint bit. */ +#undef HAVE_PPC_LWARX_MUTEX_HINT + +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pstat' function. */ +#undef HAVE_PSTAT + +/* Define to 1 if the PS_STRINGS thing exists. */ +#undef HAVE_PS_STRINGS + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the `pthread_barrier_wait' function. */ +#undef HAVE_PTHREAD_BARRIER_WAIT + +/* Define to 1 if you have the `pthread_is_threaded_np' function. */ +#undef HAVE_PTHREAD_IS_THREADED_NP + +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* Define to 1 if you have the <readline.h> header file. */ +#undef HAVE_READLINE_H + +/* Define to 1 if you have the <readline/history.h> header file. */ +#undef HAVE_READLINE_HISTORY_H + +/* Define to 1 if you have the <readline/readline.h> header file. */ +#undef HAVE_READLINE_READLINE_H + +/* Define to 1 if you have the `readlink' function. */ +#undef HAVE_READLINK + +/* Define to 1 if you have the `readv' function. */ +#undef HAVE_READV + +/* Define to 1 if you have the `rl_completion_matches' function. */ +#undef HAVE_RL_COMPLETION_MATCHES + +/* Define to 1 if you have the global variable 'rl_completion_suppress_quote'. + */ +#undef HAVE_RL_COMPLETION_SUPPRESS_QUOTE + +/* Define to 1 if you have the `rl_filename_completion_function' function. */ +#undef HAVE_RL_FILENAME_COMPLETION_FUNCTION + +/* Define to 1 if you have the global variable 'rl_filename_quote_characters'. + */ +#undef HAVE_RL_FILENAME_QUOTE_CHARACTERS + +/* Define to 1 if you have the global variable 'rl_filename_quoting_function'. + */ +#undef HAVE_RL_FILENAME_QUOTING_FUNCTION + +/* Define to 1 if you have the `rl_reset_screen_size' function. */ +#undef HAVE_RL_RESET_SCREEN_SIZE + +/* Define to 1 if you have the `rl_variable_bind' function. */ +#undef HAVE_RL_VARIABLE_BIND + +/* Define to 1 if you have the <security/pam_appl.h> header file. */ +#undef HAVE_SECURITY_PAM_APPL_H + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* Define to 1 if you have the `setproctitle_fast' function. */ +#undef HAVE_SETPROCTITLE_FAST + +/* Define to 1 if you have the `setsid' function. */ +#undef HAVE_SETSID + +/* Define to 1 if you have the `shm_open' function. */ +#undef HAVE_SHM_OPEN + +/* Define to 1 if the system has the type `socklen_t'. */ +#undef HAVE_SOCKLEN_T + +/* Define to 1 if you have spinlocks. */ +#undef HAVE_SPINLOCKS + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchrnul' function. */ +#undef HAVE_STRCHRNUL + +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strnlen' function. */ +#undef HAVE_STRNLEN + +/* Define to 1 if you have the `strsignal' function. */ +#undef HAVE_STRSIGNAL + +/* Define to 1 if you have the `strtof' function. */ +#undef HAVE_STRTOF + +/* Define to 1 if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + +/* Define to 1 if you have the `strtoq' function. */ +#undef HAVE_STRTOQ + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if you have the `strtouq' function. */ +#undef HAVE_STRTOUQ + +/* Define to 1 if the system has the type `struct addrinfo'. */ +#undef HAVE_STRUCT_ADDRINFO + +/* Define to 1 if the system has the type `struct cmsgcred'. */ +#undef HAVE_STRUCT_CMSGCRED + +/* Define to 1 if the system has the type `struct option'. */ +#undef HAVE_STRUCT_OPTION + +/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ +#undef HAVE_STRUCT_SOCKADDR_SA_LEN + +/* Define to 1 if the system has the type `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE + +/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY + +/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN + +/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY + +/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */ +#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN + +/* Define to 1 if the system has the type `struct sockaddr_un'. */ +#undef HAVE_STRUCT_SOCKADDR_UN + +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + +/* Define to 1 if you have the `symlink' function. */ +#undef HAVE_SYMLINK + +/* Define to 1 if you have the `syncfs' function. */ +#undef HAVE_SYNCFS + +/* Define to 1 if you have the `sync_file_range' function. */ +#undef HAVE_SYNC_FILE_RANGE + +/* Define to 1 if you have the syslog interface. */ +#undef HAVE_SYSLOG + +/* Define to 1 if you have the <sys/epoll.h> header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define to 1 if you have the <sys/event.h> header file. */ +#undef HAVE_SYS_EVENT_H + +/* Define to 1 if you have the <sys/ipc.h> header file. */ +#undef HAVE_SYS_IPC_H + +/* Define to 1 if you have the <sys/personality.h> header file. */ +#undef HAVE_SYS_PERSONALITY_H + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#undef HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the <sys/procctl.h> header file. */ +#undef HAVE_SYS_PROCCTL_H + +/* Define to 1 if you have the <sys/pstat.h> header file. */ +#undef HAVE_SYS_PSTAT_H + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/sem.h> header file. */ +#undef HAVE_SYS_SEM_H + +/* Define to 1 if you have the <sys/shm.h> header file. */ +#undef HAVE_SYS_SHM_H + +/* Define to 1 if you have the <sys/signalfd.h> header file. */ +#undef HAVE_SYS_SIGNALFD_H + +/* Define to 1 if you have the <sys/sockio.h> header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/tas.h> header file. */ +#undef HAVE_SYS_TAS_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <sys/ucred.h> header file. */ +#undef HAVE_SYS_UCRED_H + +/* Define to 1 if you have the <sys/uio.h> header file. */ +#undef HAVE_SYS_UIO_H + +/* Define to 1 if you have the <sys/un.h> header file. */ +#undef HAVE_SYS_UN_H + +/* Define to 1 if you have the <termios.h> header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if your compiler understands `typeof' or something similar. */ +#undef HAVE_TYPEOF + +/* Define to 1 if you have the <ucred.h> header file. */ +#undef HAVE_UCRED_H + +/* Define to 1 if the system has the type `uint64'. */ +#undef HAVE_UINT64 + +/* Define to 1 if the system has the type `uint8'. */ +#undef HAVE_UINT8 + +/* Define to 1 if the system has the type `union semun'. */ +#undef HAVE_UNION_SEMUN + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `unsetenv' function. */ +#undef HAVE_UNSETENV + +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have BSD UUID support. */ +#undef HAVE_UUID_BSD + +/* Define to 1 if you have E2FS UUID support. */ +#undef HAVE_UUID_E2FS + +/* Define to 1 if you have the <uuid.h> header file. */ +#undef HAVE_UUID_H + +/* Define to 1 if you have OSSP UUID support. */ +#undef HAVE_UUID_OSSP + +/* Define to 1 if you have the <uuid/uuid.h> header file. */ +#undef HAVE_UUID_UUID_H + +/* Define to 1 if you have the `wcstombs_l' function. */ +#undef HAVE_WCSTOMBS_L + +/* Define to 1 if you have the <wctype.h> header file. */ +#undef HAVE_WCTYPE_H + +/* Define to 1 if you have the <winldap.h> header file. */ +#undef HAVE_WINLDAP_H + +/* Define to 1 if you have the `writev' function. */ +#undef HAVE_WRITEV + +/* Define to 1 if you have the `X509_get_signature_info' function. */ +#undef HAVE_X509_GET_SIGNATURE_INFO + +/* Define to 1 if you have the `X509_get_signature_nid' function. */ +#undef HAVE_X509_GET_SIGNATURE_NID + +/* Define to 1 if the assembler supports X86_64's POPCNTQ instruction. */ +#undef HAVE_X86_64_POPCNTQ + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to 1 if your compiler understands __builtin_bswap16. */ +#undef HAVE__BUILTIN_BSWAP16 + +/* Define to 1 if your compiler understands __builtin_bswap32. */ +#undef HAVE__BUILTIN_BSWAP32 + +/* Define to 1 if your compiler understands __builtin_bswap64. */ +#undef HAVE__BUILTIN_BSWAP64 + +/* Define to 1 if your compiler understands __builtin_clz. */ +#undef HAVE__BUILTIN_CLZ + +/* Define to 1 if your compiler understands __builtin_constant_p. */ +#undef HAVE__BUILTIN_CONSTANT_P + +/* Define to 1 if your compiler understands __builtin_ctz. */ +#undef HAVE__BUILTIN_CTZ + +/* Define to 1 if your compiler understands __builtin_frame_address. */ +#undef HAVE__BUILTIN_FRAME_ADDRESS + +/* Define to 1 if your compiler understands __builtin_$op_overflow. */ +#undef HAVE__BUILTIN_OP_OVERFLOW + +/* Define to 1 if your compiler understands __builtin_popcount. */ +#undef HAVE__BUILTIN_POPCOUNT + +/* Define to 1 if your compiler understands __builtin_types_compatible_p. */ +#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P + +/* Define to 1 if your compiler understands __builtin_unreachable. */ +#undef HAVE__BUILTIN_UNREACHABLE + +/* Define to 1 if you have the `_configthreadlocale' function. */ +#undef HAVE__CONFIGTHREADLOCALE + +/* Define to 1 if you have __cpuid. */ +#undef HAVE__CPUID + +/* Define to 1 if you have __get_cpuid. */ +#undef HAVE__GET_CPUID + +/* Define to 1 if your compiler understands _Static_assert. */ +#undef HAVE__STATIC_ASSERT + +/* Define to 1 if you have the `__strtoll' function. */ +#undef HAVE___STRTOLL + +/* Define to 1 if you have the `__strtoull' function. */ +#undef HAVE___STRTOULL + +/* Define to the appropriate printf length modifier for 64-bit ints. */ +#undef INT64_MODIFIER + +/* Define to 1 if `locale_t' requires <xlocale.h>. */ +#undef LOCALE_T_IN_XLOCALE + +/* Define as the maximum alignment requirement of any C data type. */ +#undef MAXIMUM_ALIGNOF + +/* Define bytes to use libc memset(). */ +#undef MEMSET_LOOP_LIMIT + +/* Define to the OpenSSL API version in use. This avoids deprecation warnings + from newer OpenSSL versions. */ +#undef OPENSSL_API_COMPAT + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to the name of a signed 128-bit integer type. */ +#undef PG_INT128_TYPE + +/* Define to the name of a signed 64-bit integer type. */ +#undef PG_INT64_TYPE + +/* Define to the name of the default PostgreSQL service principal in Kerberos + (GSSAPI). (--with-krb-srvnam=NAME) */ +#undef PG_KRB_SRVNAM + +/* PostgreSQL major version as a string */ +#undef PG_MAJORVERSION + +/* PostgreSQL major version number */ +#undef PG_MAJORVERSION_NUM + +/* PostgreSQL minor version number */ +#undef PG_MINORVERSION_NUM + +/* Define to best printf format archetype, usually gnu_printf if available. */ +#undef PG_PRINTF_ATTRIBUTE + +/* Define to 1 to use <stdbool.h> to define type bool. */ +#undef PG_USE_STDBOOL + +/* PostgreSQL version as a string */ +#undef PG_VERSION + +/* PostgreSQL version as a number */ +#undef PG_VERSION_NUM + +/* A string containing the version number, platform, and C compiler */ +#undef PG_VERSION_STR + +/* Define to 1 to allow profiling output to be saved separately for each + process. */ +#undef PROFILE_PID_DIR + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* RELSEG_SIZE is the maximum number of blocks allowed in one disk file. Thus, + the maximum size of a single file is RELSEG_SIZE * BLCKSZ; relations bigger + than that are divided into multiple files. RELSEG_SIZE * BLCKSZ must be + less than your OS' limit on file size. This is often 2 GB or 4GB in a + 32-bit operating system, unless you have large file support enabled. By + default, we make the limit 1 GB to avoid any possible integer-overflow + problems within the OS. A limit smaller than necessary only means we divide + a large relation into more chunks than necessary, so it seems best to err + in the direction of a small limit. A power-of-2 value is recommended to + save a few cycles in md.c, but is not absolutely required. Changing + RELSEG_SIZE requires an initdb. */ +#undef RELSEG_SIZE + +/* The size of `bool', as computed by sizeof. */ +#undef SIZEOF_BOOL + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `off_t', as computed by sizeof. */ +#undef SIZEOF_OFF_T + +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if strerror_r() returns int. */ +#undef STRERROR_R_INT + +/* Define to 1 to use ARMv8 CRC Extension. */ +#undef USE_ARMV8_CRC32C + +/* Define to 1 to use ARMv8 CRC Extension with a runtime check. */ +#undef USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK + +/* Define to 1 to build with assertion checks. (--enable-cassert) */ +#undef USE_ASSERT_CHECKING + +/* Define to 1 to build with Bonjour support. (--with-bonjour) */ +#undef USE_BONJOUR + +/* Define to 1 to build with BSD Authentication support. (--with-bsd-auth) */ +#undef USE_BSD_AUTH + +/* Define to build with ICU support. (--with-icu) */ +#undef USE_ICU + +/* Define to 1 to build with LDAP support. (--with-ldap) */ +#undef USE_LDAP + +/* Define to 1 to build with XML support. (--with-libxml) */ +#undef USE_LIBXML + +/* Define to 1 to use XSLT support when building contrib/xml2. + (--with-libxslt) */ +#undef USE_LIBXSLT + +/* Define to 1 to build with LLVM based JIT support. (--with-llvm) */ +#undef USE_LLVM + +/* Define to 1 to build with LZ4 support. (--with-lz4) */ +#undef USE_LZ4 + +/* Define to select named POSIX semaphores. */ +#undef USE_NAMED_POSIX_SEMAPHORES + +/* Define to 1 to build with OpenSSL support. (--with-ssl=openssl) */ +#undef USE_OPENSSL + +/* Define to 1 to build with PAM support. (--with-pam) */ +#undef USE_PAM + +/* Define to 1 to use software CRC-32C implementation (slicing-by-8). */ +#undef USE_SLICING_BY_8_CRC32C + +/* Define to 1 use Intel SSE 4.2 CRC instructions. */ +#undef USE_SSE42_CRC32C + +/* Define to 1 to use Intel SSE 4.2 CRC instructions with a runtime check. */ +#undef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK + +/* Define to build with systemd support. (--with-systemd) */ +#undef USE_SYSTEMD + +/* Define to select SysV-style semaphores. */ +#undef USE_SYSV_SEMAPHORES + +/* Define to select SysV-style shared memory. */ +#undef USE_SYSV_SHARED_MEMORY + +/* Define to select unnamed POSIX semaphores. */ +#undef USE_UNNAMED_POSIX_SEMAPHORES + +/* Define to select Win32-style semaphores. */ +#undef USE_WIN32_SEMAPHORES + +/* Define to select Win32-style shared memory. */ +#undef USE_WIN32_SHARED_MEMORY + +/* Define to 1 to build with ZSTD support. (--with-zstd) */ +#undef USE_ZSTD + +/* Define to 1 if `wcstombs_l' requires <xlocale.h>. */ +#undef WCSTOMBS_L_IN_XLOCALE + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Size of a WAL file block. This need have no particular relation to BLCKSZ. + XLOG_BLCKSZ must be a power of 2, and if your system supports O_DIRECT I/O, + XLOG_BLCKSZ must be a multiple of the alignment requirement for direct-I/O + buffers, else direct I/O may fail. Changing XLOG_BLCKSZ requires an initdb. + */ +#undef XLOG_BLCKSZ + + + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#undef _LARGEFILE_SOURCE + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to keyword to use for C99 restrict support, or to nothing if not + supported */ +#undef pg_restrict + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif + +/* Define to how the compiler spells `typeof'. */ +#undef typeof diff --git a/src/include/pg_config_ext.h.in b/src/include/pg_config_ext.h.in new file mode 100644 index 0000000..8acadbd --- /dev/null +++ b/src/include/pg_config_ext.h.in @@ -0,0 +1,7 @@ +/* + * src/include/pg_config_ext.h.in. This is generated manually, not by + * autoheader, since we want to limit which symbols get defined here. + */ + +/* Define to the name of a signed 64-bit integer type. */ +#undef PG_INT64_TYPE diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h new file mode 100644 index 0000000..8d2e3e3 --- /dev/null +++ b/src/include/pg_config_manual.h @@ -0,0 +1,410 @@ +/*------------------------------------------------------------------------ + * PostgreSQL manual configuration settings + * + * This file contains various configuration symbols and limits. In + * all cases, changing them is only useful in very rare situations or + * for developers. If you edit any of these, be sure to do a *full* + * rebuild (and an initdb if noted). + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/pg_config_manual.h + *------------------------------------------------------------------------ + */ + +/* + * This is the default value for wal_segment_size to be used when initdb is run + * without the --wal-segsize option. It must be a valid segment size. + */ +#define DEFAULT_XLOG_SEG_SIZE (16*1024*1024) + +/* + * Maximum length for identifiers (e.g. table names, column names, + * function names). Names actually are limited to one fewer byte than this, + * because the length must include a trailing zero byte. + * + * Changing this requires an initdb. + */ +#define NAMEDATALEN 64 + +/* + * Maximum number of arguments to a function. + * + * The minimum value is 8 (GIN indexes use 8-argument support functions). + * The maximum possible value is around 600 (limited by index tuple size in + * pg_proc's index; BLCKSZ larger than 8K would allow more). Values larger + * than needed will waste memory and processing time, but do not directly + * cost disk space. + * + * Changing this does not require an initdb, but it does require a full + * backend recompile (including any user-defined C functions). + */ +#define FUNC_MAX_ARGS 100 + +/* + * When creating a product derived from PostgreSQL with changes that cause + * incompatibilities for loadable modules, it is recommended to change this + * string so that dfmgr.c can refuse to load incompatible modules with a clean + * error message. Typical examples that cause incompatibilities are any + * changes to node tags or node structures. (Note that dfmgr.c already + * detects common sources of incompatibilities due to major version + * differences and due to some changed compile-time constants. This setting + * is for catching anything that cannot be detected in a straightforward way.) + * + * There is no prescribed format for the string. The suggestion is to include + * product or company name, and optionally any internally-relevant ABI + * version. Example: "ACME Postgres/1.2". Note that the string will appear + * in a user-facing error message if an ABI mismatch is detected. + */ +#define FMGR_ABI_EXTRA "PostgreSQL" + +/* + * Maximum number of columns in an index. There is little point in making + * this anything but a multiple of 32, because the main cost is associated + * with index tuple header size (see access/itup.h). + * + * Changing this requires an initdb. + */ +#define INDEX_MAX_KEYS 32 + +/* + * Maximum number of columns in a partition key + */ +#define PARTITION_MAX_KEYS 32 + +/* + * Decide whether built-in 8-byte types, including float8, int8, and + * timestamp, are passed by value. This is on by default if sizeof(Datum) >= + * 8 (that is, on 64-bit platforms). If sizeof(Datum) < 8 (32-bit platforms), + * this must be off. We keep this here as an option so that it is easy to + * test the pass-by-reference code paths on 64-bit platforms. + * + * Changing this requires an initdb. + */ +#if SIZEOF_VOID_P >= 8 +#define USE_FLOAT8_BYVAL 1 +#endif + +/* + * When we don't have native spinlocks, we use semaphores to simulate them. + * Decreasing this value reduces consumption of OS resources; increasing it + * may improve performance, but supplying a real spinlock implementation is + * probably far better. + */ +#define NUM_SPINLOCK_SEMAPHORES 128 + +/* + * When we have neither spinlocks nor atomic operations support we're + * implementing atomic operations on top of spinlock on top of semaphores. To + * be safe against atomic operations while holding a spinlock separate + * semaphores have to be used. + */ +#define NUM_ATOMICS_SEMAPHORES 64 + +/* + * MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence, + * maximum usable pathname length is one less). + * + * We'd use a standard system header symbol for this, if there weren't + * so many to choose from: MAXPATHLEN, MAX_PATH, PATH_MAX are all + * defined by different "standards", and often have different values + * on the same platform! So we just punt and use a reasonably + * generous setting here. + */ +#define MAXPGPATH 1024 + +/* + * PG_SOMAXCONN: maximum accept-queue length limit passed to + * listen(2). You'd think we should use SOMAXCONN from + * <sys/socket.h>, but on many systems that symbol is much smaller + * than the kernel's actual limit. In any case, this symbol need be + * twiddled only if you have a kernel that refuses large limit values, + * rather than silently reducing the value to what it can handle + * (which is what most if not all Unixen do). + */ +#define PG_SOMAXCONN 10000 + +/* + * You can try changing this if you have a machine with bytes of + * another size, but no guarantee... + */ +#define BITS_PER_BYTE 8 + +/* + * Preferred alignment for disk I/O buffers. On some CPUs, copies between + * user space and kernel space are significantly faster if the user buffer + * is aligned on a larger-than-MAXALIGN boundary. Ideally this should be + * a platform-dependent value, but for now we just hard-wire it. + */ +#define ALIGNOF_BUFFER 32 + +/* + * If EXEC_BACKEND is defined, the postmaster uses an alternative method for + * starting subprocesses: Instead of simply using fork(), as is standard on + * Unix platforms, it uses fork()+exec() or something equivalent on Windows, + * as well as lots of extra code to bring the required global state to those + * new processes. This must be enabled on Windows (because there is no + * fork()). On other platforms, it's only useful for verifying those + * otherwise Windows-specific code paths. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +#define EXEC_BACKEND +#endif + +/* + * Define this if your operating system supports link() + */ +#if !defined(WIN32) && !defined(__CYGWIN__) +#define HAVE_WORKING_LINK 1 +#endif + +/* + * USE_POSIX_FADVISE controls whether Postgres will attempt to use the + * posix_fadvise() kernel call. Usually the automatic configure tests are + * sufficient, but some older Linux distributions had broken versions of + * posix_fadvise(). If necessary you can remove the #define here. + */ +#if HAVE_DECL_POSIX_FADVISE && defined(HAVE_POSIX_FADVISE) +#define USE_POSIX_FADVISE +#endif + +/* + * USE_PREFETCH code should be compiled only if we have a way to implement + * prefetching. (This is decoupled from USE_POSIX_FADVISE because there + * might in future be support for alternative low-level prefetch APIs. + * If you change this, you probably need to adjust the error message in + * check_effective_io_concurrency.) + */ +#ifdef USE_POSIX_FADVISE +#define USE_PREFETCH +#endif + +/* + * Default and maximum values for backend_flush_after, bgwriter_flush_after + * and checkpoint_flush_after; measured in blocks. Currently, these are + * enabled by default if sync_file_range() exists, ie, only on Linux. Perhaps + * we could also enable by default if we have mmap and msync(MS_ASYNC)? + */ +#ifdef HAVE_SYNC_FILE_RANGE +#define DEFAULT_BACKEND_FLUSH_AFTER 0 /* never enabled by default */ +#define DEFAULT_BGWRITER_FLUSH_AFTER 64 +#define DEFAULT_CHECKPOINT_FLUSH_AFTER 32 +#else +#define DEFAULT_BACKEND_FLUSH_AFTER 0 +#define DEFAULT_BGWRITER_FLUSH_AFTER 0 +#define DEFAULT_CHECKPOINT_FLUSH_AFTER 0 +#endif +/* upper limit for all three variables */ +#define WRITEBACK_MAX_PENDING_FLUSHES 256 + +/* + * USE_SSL code should be compiled only when compiling with an SSL + * implementation. + */ +#ifdef USE_OPENSSL +#define USE_SSL +#endif + +/* + * This is the default directory in which AF_UNIX socket files are + * placed. Caution: changing this risks breaking your existing client + * applications, which are likely to continue to look in the old + * directory. But if you just hate the idea of sockets in /tmp, + * here's where to twiddle it. You can also override this at runtime + * with the postmaster's -k switch. + * + * If set to an empty string, then AF_UNIX sockets are not used by default: A + * server will not create an AF_UNIX socket unless the run-time configuration + * is changed, a client will connect via TCP/IP by default and will only use + * an AF_UNIX socket if one is explicitly specified. + * + * This is done by default on Windows because there is no good standard + * location for AF_UNIX sockets and many installations on Windows don't + * support them yet. + */ +#ifndef WIN32 +#define DEFAULT_PGSOCKET_DIR "/tmp" +#else +#define DEFAULT_PGSOCKET_DIR "" +#endif + +/* + * This is the default event source for Windows event log. + */ +#define DEFAULT_EVENT_SOURCE "PostgreSQL" + +/* + * On PPC machines, decide whether to use the mutex hint bit in LWARX + * instructions. Setting the hint bit will slightly improve spinlock + * performance on POWER6 and later machines, but does nothing before that, + * and will result in illegal-instruction failures on some pre-POWER4 + * machines. By default we use the hint bit when building for 64-bit PPC, + * which should be safe in nearly all cases. You might want to override + * this if you are building 32-bit code for a known-recent PPC machine. + */ +#ifdef HAVE_PPC_LWARX_MUTEX_HINT /* must have assembler support in any case */ +#if defined(__ppc64__) || defined(__powerpc64__) +#define USE_PPC_LWARX_MUTEX_HINT +#endif +#endif + +/* + * On PPC machines, decide whether to use LWSYNC instructions in place of + * ISYNC and SYNC. This provides slightly better performance, but will + * result in illegal-instruction failures on some pre-POWER4 machines. + * By default we use LWSYNC when building for 64-bit PPC, which should be + * safe in nearly all cases. + */ +#if defined(__ppc64__) || defined(__powerpc64__) +#define USE_PPC_LWSYNC +#endif + +/* + * Assumed cache line size. This doesn't affect correctness, but can be used + * for low-level optimizations. Currently, this is used to pad some data + * structures in xlog.c, to ensure that highly-contended fields are on + * different cache lines. Too small a value can hurt performance due to false + * sharing, while the only downside of too large a value is a few bytes of + * wasted memory. The default is 128, which should be large enough for all + * supported platforms. + */ +#define PG_CACHE_LINE_SIZE 128 + +/* + *------------------------------------------------------------------------ + * The following symbols are for enabling debugging code, not for + * controlling user-visible features or resource limits. + *------------------------------------------------------------------------ + */ + +/* + * Include Valgrind "client requests", mostly in the memory allocator, so + * Valgrind understands PostgreSQL memory contexts. This permits detecting + * memory errors that Valgrind would not detect on a vanilla build. It also + * enables detection of buffer accesses that take place without holding a + * buffer pin (or without holding a buffer lock in the case of index access + * methods that superimpose their own custom client requests on top of the + * generic bufmgr.c requests). + * + * "make installcheck" is significantly slower under Valgrind. The client + * requests fall in hot code paths, so USE_VALGRIND slows execution by a few + * percentage points even when not run under Valgrind. + * + * Do not try to test the server under Valgrind without having built the + * server with USE_VALGRIND; else you will get false positives from sinval + * messaging (see comments in AddCatcacheInvalidationMessage). It's also + * important to use the suppression file src/tools/valgrind.supp to + * exclude other known false positives. + * + * You should normally use MEMORY_CONTEXT_CHECKING with USE_VALGRIND; + * instrumentation of repalloc() is inferior without it. + */ +/* #define USE_VALGRIND */ + +/* + * Define this to cause pfree()'d memory to be cleared immediately, to + * facilitate catching bugs that refer to already-freed values. + * Right now, this gets defined automatically if --enable-cassert. + */ +#ifdef USE_ASSERT_CHECKING +#define CLOBBER_FREED_MEMORY +#endif + +/* + * Define this to check memory allocation errors (scribbling on more + * bytes than were allocated). Right now, this gets defined + * automatically if --enable-cassert or USE_VALGRIND. + */ +#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND) +#define MEMORY_CONTEXT_CHECKING +#endif + +/* + * Define this to cause palloc()'d memory to be filled with random data, to + * facilitate catching code that depends on the contents of uninitialized + * memory. Caution: this is horrendously expensive. + */ +/* #define RANDOMIZE_ALLOCATED_MEMORY */ + +/* + * For cache-invalidation debugging, define DISCARD_CACHES_ENABLED to enable + * use of the debug_discard_caches GUC to aggressively flush syscache/relcache + * entries whenever it's possible to deliver invalidations. See + * AcceptInvalidationMessages() in src/backend/utils/cache/inval.c for + * details. + * + * USE_ASSERT_CHECKING builds default to enabling this. It's possible to use + * DISCARD_CACHES_ENABLED without a cassert build and the implied + * CLOBBER_FREED_MEMORY and MEMORY_CONTEXT_CHECKING options, but it's unlikely + * to be as effective at identifying problems. + */ +/* #define DISCARD_CACHES_ENABLED */ + +#if defined(USE_ASSERT_CHECKING) && !defined(DISCARD_CACHES_ENABLED) +#define DISCARD_CACHES_ENABLED +#endif + +/* + * Backwards compatibility for the older compile-time-only clobber-cache + * macros. + */ +#if !defined(DISCARD_CACHES_ENABLED) && (defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY)) +#define DISCARD_CACHES_ENABLED +#endif + +/* + * Recover memory used for relcache entries when invalidated. See + * RelationBuildDescr() in src/backend/utils/cache/relcache.c. + * + * This is active automatically for clobber-cache builds when clobbering is + * active, but can be overridden here by explicitly defining + * RECOVER_RELATION_BUILD_MEMORY. Define to 1 to always free relation cache + * memory even when clobber is off, or to 0 to never free relation cache + * memory even when clobbering is on. + */ + /* #define RECOVER_RELATION_BUILD_MEMORY 0 */ /* Force disable */ + /* #define RECOVER_RELATION_BUILD_MEMORY 1 */ /* Force enable */ + +/* + * Define this to force all parse and plan trees to be passed through + * copyObject(), to facilitate catching errors and omissions in + * copyObject(). + */ +/* #define COPY_PARSE_PLAN_TREES */ + +/* + * Define this to force all parse and plan trees to be passed through + * outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in + * those modules. + */ +/* #define WRITE_READ_PARSE_PLAN_TREES */ + +/* + * Define this to force all raw parse trees for DML statements to be scanned + * by raw_expression_tree_walker(), to facilitate catching errors and + * omissions in that function. + */ +/* #define RAW_EXPRESSION_COVERAGE_TEST */ + +/* + * Enable debugging print statements for lock-related operations. + */ +/* #define LOCK_DEBUG */ + +/* + * Enable debugging print statements for WAL-related operations; see + * also the wal_debug GUC var. + */ +/* #define WAL_DEBUG */ + +/* + * Enable tracing of resource consumption during sort operations; + * see also the trace_sort GUC var. For 8.1 this is enabled by default. + */ +#define TRACE_SORT 1 + +/* + * Enable tracing of syncscan operations (see also the trace_syncscan GUC var). + */ +/* #define TRACE_SYNCSCAN */ diff --git a/src/include/pg_getopt.h b/src/include/pg_getopt.h new file mode 100644 index 0000000..9d91e60 --- /dev/null +++ b/src/include/pg_getopt.h @@ -0,0 +1,56 @@ +/* + * Postgres files that use getopt(3) always include this file. + * We must cope with three different scenarios: + * 1. We're using the platform's getopt(), and we should just import the + * appropriate declarations. + * 2. The platform lacks getopt(), and we must declare everything. + * 3. The platform has getopt(), but we're not using it because we don't + * like its behavior. The declarations we make here must be compatible + * with both the platform's getopt() and our src/port/getopt.c. + * + * Portions Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Portions Copyright (c) 2003-2022, PostgreSQL Global Development Group + * + * src/include/pg_getopt.h + */ +#ifndef PG_GETOPT_H +#define PG_GETOPT_H + +/* POSIX says getopt() is provided by unistd.h */ +#include <unistd.h> + +/* rely on the system's getopt.h if present */ +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#endif + +/* + * If we have <getopt.h>, assume it declares these variables, else do that + * ourselves. (We used to just declare them unconditionally, but Cygwin + * doesn't like that.) + */ +#ifndef HAVE_GETOPT_H + +extern PGDLLIMPORT char *optarg; +extern PGDLLIMPORT int optind; +extern PGDLLIMPORT int opterr; +extern PGDLLIMPORT int optopt; + +#endif /* HAVE_GETOPT_H */ + +/* + * Some platforms have optreset but fail to declare it in <getopt.h>, so cope. + * Cygwin, however, doesn't like this either. + */ +#if defined(HAVE_INT_OPTRESET) && !defined(__CYGWIN__) +extern PGDLLIMPORT int optreset; +#endif + +/* Provide getopt() declaration if the platform doesn't have it */ +#ifndef HAVE_GETOPT +extern int getopt(int nargc, char *const *nargv, const char *ostr); +#endif + +#endif /* PG_GETOPT_H */ diff --git a/src/include/pg_trace.h b/src/include/pg_trace.h new file mode 100644 index 0000000..8c63222 --- /dev/null +++ b/src/include/pg_trace.h @@ -0,0 +1,17 @@ +/* ---------- + * pg_trace.h + * + * Definitions for the PostgreSQL tracing framework + * + * Copyright (c) 2006-2022, PostgreSQL Global Development Group + * + * src/include/pg_trace.h + * ---------- + */ + +#ifndef PG_TRACE_H +#define PG_TRACE_H + +#include "utils/probes.h" /* pgrminclude ignore */ + +#endif /* PG_TRACE_H */ diff --git a/src/include/pgstat.h b/src/include/pgstat.h new file mode 100644 index 0000000..44279ea --- /dev/null +++ b/src/include/pgstat.h @@ -0,0 +1,701 @@ +/* ---------- + * pgstat.h + * + * Definitions for the PostgreSQL cumulative statistics system. + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/pgstat.h + * ---------- + */ +#ifndef PGSTAT_H +#define PGSTAT_H + +#include "datatype/timestamp.h" +#include "portability/instr_time.h" +#include "postmaster/pgarch.h" /* for MAX_XFN_CHARS */ +#include "utils/backend_progress.h" /* for backward compatibility */ +#include "utils/backend_status.h" /* for backward compatibility */ +#include "utils/relcache.h" +#include "utils/wait_event.h" /* for backward compatibility */ + + +/* ---------- + * Paths for the statistics files (relative to installation's $PGDATA). + * ---------- + */ +#define PGSTAT_STAT_PERMANENT_DIRECTORY "pg_stat" +#define PGSTAT_STAT_PERMANENT_FILENAME "pg_stat/pgstat.stat" +#define PGSTAT_STAT_PERMANENT_TMPFILE "pg_stat/pgstat.tmp" + +/* Default directory to store temporary statistics data in */ +#define PG_STAT_TMP_DIR "pg_stat_tmp" + +/* The types of statistics entries */ +typedef enum PgStat_Kind +{ + /* use 0 for INVALID, to catch zero-initialized data */ + PGSTAT_KIND_INVALID = 0, + + /* stats for variable-numbered objects */ + PGSTAT_KIND_DATABASE, /* database-wide statistics */ + PGSTAT_KIND_RELATION, /* per-table statistics */ + PGSTAT_KIND_FUNCTION, /* per-function statistics */ + PGSTAT_KIND_REPLSLOT, /* per-slot statistics */ + PGSTAT_KIND_SUBSCRIPTION, /* per-subscription statistics */ + + /* stats for fixed-numbered objects */ + PGSTAT_KIND_ARCHIVER, + PGSTAT_KIND_BGWRITER, + PGSTAT_KIND_CHECKPOINTER, + PGSTAT_KIND_SLRU, + PGSTAT_KIND_WAL, +} PgStat_Kind; + +#define PGSTAT_KIND_FIRST_VALID PGSTAT_KIND_DATABASE +#define PGSTAT_KIND_LAST PGSTAT_KIND_WAL +#define PGSTAT_NUM_KINDS (PGSTAT_KIND_LAST + 1) + +/* Values for track_functions GUC variable --- order is significant! */ +typedef enum TrackFunctionsLevel +{ + TRACK_FUNC_OFF, + TRACK_FUNC_PL, + TRACK_FUNC_ALL +} TrackFunctionsLevel; + +typedef enum PgStat_FetchConsistency +{ + PGSTAT_FETCH_CONSISTENCY_NONE, + PGSTAT_FETCH_CONSISTENCY_CACHE, + PGSTAT_FETCH_CONSISTENCY_SNAPSHOT, +} PgStat_FetchConsistency; + +/* Values to track the cause of session termination */ +typedef enum SessionEndType +{ + DISCONNECT_NOT_YET, /* still active */ + DISCONNECT_NORMAL, + DISCONNECT_CLIENT_EOF, + DISCONNECT_FATAL, + DISCONNECT_KILLED +} SessionEndType; + +/* ---------- + * The data type used for counters. + * ---------- + */ +typedef int64 PgStat_Counter; + + +/* ------------------------------------------------------------ + * Structures kept in backend local memory while accumulating counts + * ------------------------------------------------------------ + */ + +/* ---------- + * PgStat_FunctionCounts The actual per-function counts kept by a backend + * + * This struct should contain only actual event counters, because we memcmp + * it against zeroes to detect whether there are any pending stats. + * + * Note that the time counters are in instr_time format here. We convert to + * microseconds in PgStat_Counter format when flushing out pending statistics. + * ---------- + */ +typedef struct PgStat_FunctionCounts +{ + PgStat_Counter f_numcalls; + instr_time f_total_time; + instr_time f_self_time; +} PgStat_FunctionCounts; + +/* ---------- + * PgStat_BackendFunctionEntry Non-flushed function stats. + * ---------- + */ +typedef struct PgStat_BackendFunctionEntry +{ + PgStat_FunctionCounts f_counts; +} PgStat_BackendFunctionEntry; + +/* + * Working state needed to accumulate per-function-call timing statistics. + */ +typedef struct PgStat_FunctionCallUsage +{ + /* Link to function's hashtable entry (must still be there at exit!) */ + /* NULL means we are not tracking the current function call */ + PgStat_FunctionCounts *fs; + /* Total time previously charged to function, as of function start */ + instr_time save_f_total_time; + /* Backend-wide total time as of function start */ + instr_time save_total; + /* system clock as of function start */ + instr_time f_start; +} PgStat_FunctionCallUsage; + +/* ---------- + * PgStat_BackendSubEntry Non-flushed subscription stats. + * ---------- + */ +typedef struct PgStat_BackendSubEntry +{ + PgStat_Counter apply_error_count; + PgStat_Counter sync_error_count; +} PgStat_BackendSubEntry; + +/* ---------- + * PgStat_TableCounts The actual per-table counts kept by a backend + * + * This struct should contain only actual event counters, because we memcmp + * it against zeroes to detect whether there are any stats updates to apply. + * It is a component of PgStat_TableStatus (within-backend state). + * + * Note: for a table, tuples_returned is the number of tuples successfully + * fetched by heap_getnext, while tuples_fetched is the number of tuples + * successfully fetched by heap_fetch under the control of bitmap indexscans. + * For an index, tuples_returned is the number of index entries returned by + * the index AM, while tuples_fetched is the number of tuples successfully + * fetched by heap_fetch under the control of simple indexscans for this index. + * + * tuples_inserted/updated/deleted/hot_updated count attempted actions, + * regardless of whether the transaction committed. delta_live_tuples, + * delta_dead_tuples, and changed_tuples are set depending on commit or abort. + * Note that delta_live_tuples and delta_dead_tuples can be negative! + * ---------- + */ +typedef struct PgStat_TableCounts +{ + PgStat_Counter t_numscans; + + PgStat_Counter t_tuples_returned; + PgStat_Counter t_tuples_fetched; + + PgStat_Counter t_tuples_inserted; + PgStat_Counter t_tuples_updated; + PgStat_Counter t_tuples_deleted; + PgStat_Counter t_tuples_hot_updated; + bool t_truncdropped; + + PgStat_Counter t_delta_live_tuples; + PgStat_Counter t_delta_dead_tuples; + PgStat_Counter t_changed_tuples; + + PgStat_Counter t_blocks_fetched; + PgStat_Counter t_blocks_hit; +} PgStat_TableCounts; + +/* ---------- + * PgStat_TableStatus Per-table status within a backend + * + * Many of the event counters are nontransactional, ie, we count events + * in committed and aborted transactions alike. For these, we just count + * directly in the PgStat_TableStatus. However, delta_live_tuples, + * delta_dead_tuples, and changed_tuples must be derived from event counts + * with awareness of whether the transaction or subtransaction committed or + * aborted. Hence, we also keep a stack of per-(sub)transaction status + * records for every table modified in the current transaction. At commit + * or abort, we propagate tuples_inserted/updated/deleted up to the + * parent subtransaction level, or out to the parent PgStat_TableStatus, + * as appropriate. + * ---------- + */ +typedef struct PgStat_TableStatus +{ + Oid t_id; /* table's OID */ + bool t_shared; /* is it a shared catalog? */ + struct PgStat_TableXactStatus *trans; /* lowest subxact's counts */ + PgStat_TableCounts t_counts; /* event counts to be sent */ + Relation relation; /* rel that is using this entry */ +} PgStat_TableStatus; + +/* ---------- + * PgStat_TableXactStatus Per-table, per-subtransaction status + * ---------- + */ +typedef struct PgStat_TableXactStatus +{ + PgStat_Counter tuples_inserted; /* tuples inserted in (sub)xact */ + PgStat_Counter tuples_updated; /* tuples updated in (sub)xact */ + PgStat_Counter tuples_deleted; /* tuples deleted in (sub)xact */ + bool truncdropped; /* relation truncated/dropped in this + * (sub)xact */ + /* tuples i/u/d prior to truncate/drop */ + PgStat_Counter inserted_pre_truncdrop; + PgStat_Counter updated_pre_truncdrop; + PgStat_Counter deleted_pre_truncdrop; + int nest_level; /* subtransaction nest level */ + /* links to other structs for same relation: */ + struct PgStat_TableXactStatus *upper; /* next higher subxact if any */ + PgStat_TableStatus *parent; /* per-table status */ + /* structs of same subxact level are linked here: */ + struct PgStat_TableXactStatus *next; /* next of same subxact */ +} PgStat_TableXactStatus; + + +/* ------------------------------------------------------------ + * Data structures on disk and in shared memory follow + * + * PGSTAT_FILE_FORMAT_ID should be changed whenever any of these + * data structures change. + * ------------------------------------------------------------ + */ + +#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA7 + +typedef struct PgStat_ArchiverStats +{ + PgStat_Counter archived_count; /* archival successes */ + char last_archived_wal[MAX_XFN_CHARS + 1]; /* last WAL file + * archived */ + TimestampTz last_archived_timestamp; /* last archival success time */ + PgStat_Counter failed_count; /* failed archival attempts */ + char last_failed_wal[MAX_XFN_CHARS + 1]; /* WAL file involved in + * last failure */ + TimestampTz last_failed_timestamp; /* last archival failure time */ + TimestampTz stat_reset_timestamp; +} PgStat_ArchiverStats; + +typedef struct PgStat_BgWriterStats +{ + PgStat_Counter buf_written_clean; + PgStat_Counter maxwritten_clean; + PgStat_Counter buf_alloc; + TimestampTz stat_reset_timestamp; +} PgStat_BgWriterStats; + +typedef struct PgStat_CheckpointerStats +{ + PgStat_Counter timed_checkpoints; + PgStat_Counter requested_checkpoints; + PgStat_Counter checkpoint_write_time; /* times in milliseconds */ + PgStat_Counter checkpoint_sync_time; + PgStat_Counter buf_written_checkpoints; + PgStat_Counter buf_written_backend; + PgStat_Counter buf_fsync_backend; +} PgStat_CheckpointerStats; + +typedef struct PgStat_StatDBEntry +{ + PgStat_Counter n_xact_commit; + PgStat_Counter n_xact_rollback; + PgStat_Counter n_blocks_fetched; + PgStat_Counter n_blocks_hit; + PgStat_Counter n_tuples_returned; + PgStat_Counter n_tuples_fetched; + PgStat_Counter n_tuples_inserted; + PgStat_Counter n_tuples_updated; + PgStat_Counter n_tuples_deleted; + TimestampTz last_autovac_time; + PgStat_Counter n_conflict_tablespace; + PgStat_Counter n_conflict_lock; + PgStat_Counter n_conflict_snapshot; + PgStat_Counter n_conflict_bufferpin; + PgStat_Counter n_conflict_startup_deadlock; + PgStat_Counter n_temp_files; + PgStat_Counter n_temp_bytes; + PgStat_Counter n_deadlocks; + PgStat_Counter n_checksum_failures; + TimestampTz last_checksum_failure; + PgStat_Counter n_block_read_time; /* times in microseconds */ + PgStat_Counter n_block_write_time; + PgStat_Counter n_sessions; + PgStat_Counter total_session_time; + PgStat_Counter total_active_time; + PgStat_Counter total_idle_in_xact_time; + PgStat_Counter n_sessions_abandoned; + PgStat_Counter n_sessions_fatal; + PgStat_Counter n_sessions_killed; + + TimestampTz stat_reset_timestamp; +} PgStat_StatDBEntry; + +typedef struct PgStat_StatFuncEntry +{ + PgStat_Counter f_numcalls; + + PgStat_Counter f_total_time; /* times in microseconds */ + PgStat_Counter f_self_time; +} PgStat_StatFuncEntry; + +typedef struct PgStat_StatReplSlotEntry +{ + /* + * In PG 15 this field is unused, but not removed, to avoid changing + * PGSTAT_FILE_FORMAT_ID. + */ + NameData slotname_unused; + PgStat_Counter spill_txns; + PgStat_Counter spill_count; + PgStat_Counter spill_bytes; + PgStat_Counter stream_txns; + PgStat_Counter stream_count; + PgStat_Counter stream_bytes; + PgStat_Counter total_txns; + PgStat_Counter total_bytes; + TimestampTz stat_reset_timestamp; +} PgStat_StatReplSlotEntry; + +typedef struct PgStat_SLRUStats +{ + PgStat_Counter blocks_zeroed; + PgStat_Counter blocks_hit; + PgStat_Counter blocks_read; + PgStat_Counter blocks_written; + PgStat_Counter blocks_exists; + PgStat_Counter flush; + PgStat_Counter truncate; + TimestampTz stat_reset_timestamp; +} PgStat_SLRUStats; + +typedef struct PgStat_StatSubEntry +{ + PgStat_Counter apply_error_count; + PgStat_Counter sync_error_count; + TimestampTz stat_reset_timestamp; +} PgStat_StatSubEntry; + +typedef struct PgStat_StatTabEntry +{ + PgStat_Counter numscans; + + PgStat_Counter tuples_returned; + PgStat_Counter tuples_fetched; + + PgStat_Counter tuples_inserted; + PgStat_Counter tuples_updated; + PgStat_Counter tuples_deleted; + PgStat_Counter tuples_hot_updated; + + PgStat_Counter n_live_tuples; + PgStat_Counter n_dead_tuples; + PgStat_Counter changes_since_analyze; + PgStat_Counter inserts_since_vacuum; + + PgStat_Counter blocks_fetched; + PgStat_Counter blocks_hit; + + TimestampTz vacuum_timestamp; /* user initiated vacuum */ + PgStat_Counter vacuum_count; + TimestampTz autovac_vacuum_timestamp; /* autovacuum initiated */ + PgStat_Counter autovac_vacuum_count; + TimestampTz analyze_timestamp; /* user initiated */ + PgStat_Counter analyze_count; + TimestampTz autovac_analyze_timestamp; /* autovacuum initiated */ + PgStat_Counter autovac_analyze_count; +} PgStat_StatTabEntry; + +typedef struct PgStat_WalStats +{ + PgStat_Counter wal_records; + PgStat_Counter wal_fpi; + uint64 wal_bytes; + PgStat_Counter wal_buffers_full; + PgStat_Counter wal_write; + PgStat_Counter wal_sync; + PgStat_Counter wal_write_time; + PgStat_Counter wal_sync_time; + TimestampTz stat_reset_timestamp; +} PgStat_WalStats; + + +/* + * Functions in pgstat.c + */ + +/* functions called from postmaster */ +extern Size StatsShmemSize(void); +extern void StatsShmemInit(void); + +/* Functions called during server startup / shutdown */ +extern void pgstat_restore_stats(void); +extern void pgstat_discard_stats(void); +extern void pgstat_before_server_shutdown(int code, Datum arg); + +/* Functions for backend initialization */ +extern void pgstat_initialize(void); + +/* Functions called from backends */ +extern long pgstat_report_stat(bool force); +extern void pgstat_force_next_flush(void); + +extern void pgstat_reset_counters(void); +extern void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objectid); +extern void pgstat_reset_of_kind(PgStat_Kind kind); + +/* stats accessors */ +extern void pgstat_clear_snapshot(void); +extern TimestampTz pgstat_get_stat_snapshot_timestamp(bool *have_snapshot); + +/* helpers */ +extern PgStat_Kind pgstat_get_kind_from_str(char *kind_str); +extern bool pgstat_have_entry(PgStat_Kind kind, Oid dboid, Oid objoid); + +/* GUC hook for stats_fetch_consistency */ +extern void assign_stats_fetch_consistency(int newval, void *extra); + +/* + * Functions in pgstat_archiver.c + */ + +extern void pgstat_report_archiver(const char *xlog, bool failed); +extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void); + + +/* + * Functions in pgstat_bgwriter.c + */ + +extern void pgstat_report_bgwriter(void); +extern PgStat_BgWriterStats *pgstat_fetch_stat_bgwriter(void); + + +/* + * Functions in pgstat_checkpointer.c + */ + +extern void pgstat_report_checkpointer(void); +extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void); + + +/* + * Functions in pgstat_database.c + */ + +extern void pgstat_drop_database(Oid databaseid); +extern void pgstat_report_autovac(Oid dboid); +extern void pgstat_report_recovery_conflict(int reason); +extern void pgstat_report_deadlock(void); +extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount); +extern void pgstat_report_checksum_failure(void); +extern void pgstat_report_connect(Oid dboid); + +#define pgstat_count_buffer_read_time(n) \ + (pgStatBlockReadTime += (n)) +#define pgstat_count_buffer_write_time(n) \ + (pgStatBlockWriteTime += (n)) +#define pgstat_count_conn_active_time(n) \ + (pgStatActiveTime += (n)) +#define pgstat_count_conn_txn_idle_time(n) \ + (pgStatTransactionIdleTime += (n)) + +extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid); + +/* + * Functions in pgstat_function.c + */ + +extern void pgstat_create_function(Oid proid); +extern void pgstat_drop_function(Oid proid); + +struct FunctionCallInfoBaseData; +extern void pgstat_init_function_usage(struct FunctionCallInfoBaseData *fcinfo, + PgStat_FunctionCallUsage *fcu); +extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, + bool finalize); + +extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid); +extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id); + + +/* + * Functions in pgstat_relation.c + */ + +extern void pgstat_create_relation(Relation rel); +extern void pgstat_drop_relation(Relation rel); +extern void pgstat_copy_relation_stats(Relation dstrel, Relation srcrel); + +extern void pgstat_init_relation(Relation rel); +extern void pgstat_assoc_relation(Relation rel); +extern void pgstat_unlink_relation(Relation rel); + +extern void pgstat_report_vacuum(Oid tableoid, bool shared, + PgStat_Counter livetuples, PgStat_Counter deadtuples); +extern void pgstat_report_analyze(Relation rel, + PgStat_Counter livetuples, PgStat_Counter deadtuples, + bool resetcounter); + +/* + * If stats are enabled, but pending data hasn't been prepared yet, call + * pgstat_assoc_relation() to do so. See its comment for why this is done + * separately from pgstat_init_relation(). + */ +#define pgstat_should_count_relation(rel) \ + (likely((rel)->pgstat_info != NULL) ? true : \ + ((rel)->pgstat_enabled ? pgstat_assoc_relation(rel), true : false)) + +/* nontransactional event counts are simple enough to inline */ + +#define pgstat_count_heap_scan(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_numscans++; \ + } while (0) +#define pgstat_count_heap_getnext(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_tuples_returned++; \ + } while (0) +#define pgstat_count_heap_fetch(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_tuples_fetched++; \ + } while (0) +#define pgstat_count_index_scan(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_numscans++; \ + } while (0) +#define pgstat_count_index_tuples(rel, n) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_tuples_returned += (n); \ + } while (0) +#define pgstat_count_buffer_read(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_blocks_fetched++; \ + } while (0) +#define pgstat_count_buffer_hit(rel) \ + do { \ + if (pgstat_should_count_relation(rel)) \ + (rel)->pgstat_info->t_counts.t_blocks_hit++; \ + } while (0) + +extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n); +extern void pgstat_count_heap_update(Relation rel, bool hot); +extern void pgstat_count_heap_delete(Relation rel); +extern void pgstat_count_truncate(Relation rel); +extern void pgstat_update_heap_dead_tuples(Relation rel, int delta); + +extern void pgstat_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void pgstat_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len); + +extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); +extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry_ext(bool shared, + Oid relid); +extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id); + + +/* + * Functions in pgstat_replslot.c + */ + +extern void pgstat_reset_replslot(const char *name); +struct ReplicationSlot; +extern void pgstat_report_replslot(struct ReplicationSlot *slot, const PgStat_StatReplSlotEntry *repSlotStat); +extern void pgstat_create_replslot(struct ReplicationSlot *slot); +extern void pgstat_acquire_replslot(struct ReplicationSlot *slot); +extern void pgstat_drop_replslot(struct ReplicationSlot *slot); +extern PgStat_StatReplSlotEntry *pgstat_fetch_replslot(NameData slotname); + + +/* + * Functions in pgstat_slru.c + */ + +extern void pgstat_reset_slru(const char *); +extern void pgstat_count_slru_page_zeroed(int slru_idx); +extern void pgstat_count_slru_page_hit(int slru_idx); +extern void pgstat_count_slru_page_read(int slru_idx); +extern void pgstat_count_slru_page_written(int slru_idx); +extern void pgstat_count_slru_page_exists(int slru_idx); +extern void pgstat_count_slru_flush(int slru_idx); +extern void pgstat_count_slru_truncate(int slru_idx); +extern const char *pgstat_get_slru_name(int slru_idx); +extern int pgstat_get_slru_index(const char *name); +extern PgStat_SLRUStats *pgstat_fetch_slru(void); + + +/* + * Functions in pgstat_subscription.c + */ + +extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error); +extern void pgstat_create_subscription(Oid subid); +extern void pgstat_drop_subscription(Oid subid); +extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid); + + +/* + * Functions in pgstat_xact.c + */ + +extern void AtEOXact_PgStat(bool isCommit, bool parallel); +extern void AtEOSubXact_PgStat(bool isCommit, int nestDepth); +extern void AtPrepare_PgStat(void); +extern void PostPrepare_PgStat(void); +struct xl_xact_stats_item; +extern int pgstat_get_transactional_drops(bool isCommit, struct xl_xact_stats_item **items); +extern void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo); + + +/* + * Functions in pgstat_wal.c + */ + +extern void pgstat_report_wal(bool force); +extern PgStat_WalStats *pgstat_fetch_stat_wal(void); + + +/* + * Variables in pgstat.c + */ + +/* GUC parameters */ +extern PGDLLIMPORT bool pgstat_track_counts; +extern PGDLLIMPORT int pgstat_track_functions; +extern PGDLLIMPORT int pgstat_fetch_consistency; + + +/* + * Variables in pgstat_bgwriter.c + */ + +/* updated directly by bgwriter and bufmgr */ +extern PGDLLIMPORT PgStat_BgWriterStats PendingBgWriterStats; + + +/* + * Variables in pgstat_checkpointer.c + */ + +/* + * Checkpointer statistics counters are updated directly by checkpointer and + * bufmgr. + */ +extern PGDLLIMPORT PgStat_CheckpointerStats PendingCheckpointerStats; + + +/* + * Variables in pgstat_database.c + */ + +/* Updated by pgstat_count_buffer_*_time macros */ +extern PGDLLIMPORT PgStat_Counter pgStatBlockReadTime; +extern PGDLLIMPORT PgStat_Counter pgStatBlockWriteTime; + +/* + * Updated by pgstat_count_conn_*_time macros, called by + * pgstat_report_activity(). + */ +extern PGDLLIMPORT PgStat_Counter pgStatActiveTime; +extern PGDLLIMPORT PgStat_Counter pgStatTransactionIdleTime; + +/* updated by the traffic cop and in errfinish() */ +extern PGDLLIMPORT SessionEndType pgStatSessionEndCause; + + +/* + * Variables in pgstat_wal.c + */ + +/* updated directly by backends and background processes */ +extern PGDLLIMPORT PgStat_WalStats PendingWalStats; + + +#endif /* PGSTAT_H */ diff --git a/src/include/pgtar.h b/src/include/pgtar.h new file mode 100644 index 0000000..94289f1 --- /dev/null +++ b/src/include/pgtar.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * pgtar.h + * Functions for manipulating tarfile datastructures (src/port/tar.c) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/pgtar.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TAR_H +#define PG_TAR_H + +#define TAR_BLOCK_SIZE 512 + +enum tarError +{ + TAR_OK = 0, + TAR_NAME_TOO_LONG, + TAR_SYMLINK_TOO_LONG +}; + +extern enum tarError tarCreateHeader(char *h, const char *filename, + const char *linktarget, pgoff_t size, + mode_t mode, uid_t uid, gid_t gid, + time_t mtime); +extern uint64 read_tar_number(const char *s, int len); +extern void print_tar_number(char *s, int len, uint64 val); +extern int tarChecksum(char *header); + +/* + * Compute the number of padding bytes required for an entry in a tar + * archive. We must pad out to a multiple of TAR_BLOCK_SIZE. Since that's + * a power of 2, we can use TYPEALIGN(). + */ +static inline size_t +tarPaddingBytesRequired(size_t len) +{ + return TYPEALIGN(TAR_BLOCK_SIZE, len) - len; +} + +#endif diff --git a/src/include/pgtime.h b/src/include/pgtime.h new file mode 100644 index 0000000..1c44be8 --- /dev/null +++ b/src/include/pgtime.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * pgtime.h + * PostgreSQL internal timezone library + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/pgtime.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PGTIME_H +#define _PGTIME_H + + +/* + * The API of this library is generally similar to the corresponding + * C library functions, except that we use pg_time_t which (we hope) is + * 64 bits wide, and which is most definitely signed not unsigned. + */ + +typedef int64 pg_time_t; + +/* + * Data structure representing a broken-down timestamp. + * + * CAUTION: the IANA timezone library (src/timezone/) follows the POSIX + * convention that tm_mon counts from 0 and tm_year is relative to 1900. + * However, Postgres' datetime functions generally treat tm_mon as counting + * from 1 and tm_year as relative to 1 BC. Be sure to make the appropriate + * adjustments when moving from one code domain to the other. + */ +struct pg_tm +{ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; /* see above */ + int tm_year; /* see above */ + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +/* These structs are opaque outside the timezone library */ +typedef struct pg_tz pg_tz; +typedef struct pg_tzenum pg_tzenum; + +/* Maximum length of a timezone name (not including trailing null) */ +#define TZ_STRLEN_MAX 255 + +/* these functions are in localtime.c */ + +extern struct pg_tm *pg_localtime(const pg_time_t *timep, const pg_tz *tz); +extern struct pg_tm *pg_gmtime(const pg_time_t *timep); +extern int pg_next_dst_boundary(const pg_time_t *timep, + long int *before_gmtoff, + int *before_isdst, + pg_time_t *boundary, + long int *after_gmtoff, + int *after_isdst, + const pg_tz *tz); +extern bool pg_interpret_timezone_abbrev(const char *abbrev, + const pg_time_t *timep, + long int *gmtoff, + int *isdst, + const pg_tz *tz); +extern bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff); +extern const char *pg_get_timezone_name(pg_tz *tz); +extern bool pg_tz_acceptable(pg_tz *tz); + +/* these functions are in strftime.c */ + +extern size_t pg_strftime(char *s, size_t max, const char *format, + const struct pg_tm *tm); + +/* these functions and variables are in pgtz.c */ + +extern PGDLLIMPORT pg_tz *session_timezone; +extern PGDLLIMPORT pg_tz *log_timezone; + +extern void pg_timezone_initialize(void); +extern pg_tz *pg_tzset(const char *tzname); +extern pg_tz *pg_tzset_offset(long gmtoffset); + +extern pg_tzenum *pg_tzenumerate_start(void); +extern pg_tz *pg_tzenumerate_next(pg_tzenum *dir); +extern void pg_tzenumerate_end(pg_tzenum *dir); + +#endif /* _PGTIME_H */ diff --git a/src/include/port.h b/src/include/port.h new file mode 100644 index 0000000..9f35761 --- /dev/null +++ b/src/include/port.h @@ -0,0 +1,553 @@ +/*------------------------------------------------------------------------- + * + * port.h + * Header for src/port/ compatibility functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PORT_H +#define PG_PORT_H + +#include <ctype.h> + +/* + * Windows has enough specialized port stuff that we push most of it off + * into another file. + * Note: Some CYGWIN includes might #define WIN32. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +#include "port/win32_port.h" +#endif + +/* socket has a different definition on WIN32 */ +#ifndef WIN32 +typedef int pgsocket; + +#define PGINVALID_SOCKET (-1) +#else +typedef SOCKET pgsocket; + +#define PGINVALID_SOCKET INVALID_SOCKET +#endif + +/* if platform lacks socklen_t, we assume this will work */ +#ifndef HAVE_SOCKLEN_T +typedef unsigned int socklen_t; +#endif + +/* non-blocking */ +extern bool pg_set_noblock(pgsocket sock); +extern bool pg_set_block(pgsocket sock); + +/* Portable path handling for Unix/Win32 (in path.c) */ + +extern bool has_drive_prefix(const char *filename); +extern char *first_dir_separator(const char *filename); +extern char *last_dir_separator(const char *filename); +extern char *first_path_var_separator(const char *pathlist); +extern void join_path_components(char *ret_path, + const char *head, const char *tail); +extern void canonicalize_path(char *path); +extern void make_native_path(char *path); +extern void cleanup_path(char *path); +extern bool path_contains_parent_reference(const char *path); +extern bool path_is_relative_and_below_cwd(const char *path); +extern bool path_is_prefix_of_path(const char *path1, const char *path2); +extern char *make_absolute_path(const char *path); +extern const char *get_progname(const char *argv0); +extern void get_share_path(const char *my_exec_path, char *ret_path); +extern void get_etc_path(const char *my_exec_path, char *ret_path); +extern void get_include_path(const char *my_exec_path, char *ret_path); +extern void get_pkginclude_path(const char *my_exec_path, char *ret_path); +extern void get_includeserver_path(const char *my_exec_path, char *ret_path); +extern void get_lib_path(const char *my_exec_path, char *ret_path); +extern void get_pkglib_path(const char *my_exec_path, char *ret_path); +extern void get_locale_path(const char *my_exec_path, char *ret_path); +extern void get_doc_path(const char *my_exec_path, char *ret_path); +extern void get_html_path(const char *my_exec_path, char *ret_path); +extern void get_man_path(const char *my_exec_path, char *ret_path); +extern bool get_home_path(char *ret_path); +extern void get_parent_directory(char *path); + +/* common/pgfnames.c */ +extern char **pgfnames(const char *path); +extern void pgfnames_cleanup(char **filenames); + +#define IS_NONWINDOWS_DIR_SEP(ch) ((ch) == '/') +#define is_nonwindows_absolute_path(filename) \ +( \ + IS_NONWINDOWS_DIR_SEP((filename)[0]) \ +) + +#define IS_WINDOWS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') +/* See path_is_relative_and_below_cwd() for how we handle 'E:abc'. */ +#define is_windows_absolute_path(filename) \ +( \ + IS_WINDOWS_DIR_SEP((filename)[0]) || \ + (isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \ + IS_WINDOWS_DIR_SEP((filename)[2])) \ +) + +/* + * is_absolute_path and IS_DIR_SEP + * + * By using macros here we avoid needing to include path.c in libpq. + */ +#ifndef WIN32 +#define IS_DIR_SEP(ch) IS_NONWINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_nonwindows_absolute_path(filename) +#else +#define IS_DIR_SEP(ch) IS_WINDOWS_DIR_SEP(ch) +#define is_absolute_path(filename) is_windows_absolute_path(filename) +#endif + +/* + * This macro provides a centralized list of all errnos that identify + * hard failure of a previously-established network connection. + * The macro is intended to be used in a switch statement, in the form + * "case ALL_CONNECTION_FAILURE_ERRNOS:". + * + * Note: this groups EPIPE and ECONNRESET, which we take to indicate a + * probable server crash, with other errors that indicate loss of network + * connectivity without proving much about the server's state. Places that + * are actually reporting errors typically single out EPIPE and ECONNRESET, + * while allowing the network failures to be reported generically. + */ +#define ALL_CONNECTION_FAILURE_ERRNOS \ + EPIPE: \ + case ECONNRESET: \ + case ECONNABORTED: \ + case EHOSTDOWN: \ + case EHOSTUNREACH: \ + case ENETDOWN: \ + case ENETRESET: \ + case ENETUNREACH: \ + case ETIMEDOUT + +/* Portable locale initialization (in exec.c) */ +extern void set_pglocale_pgservice(const char *argv0, const char *app); + +/* Portable way to find and execute binaries (in exec.c) */ +extern int validate_exec(const char *path); +extern int find_my_exec(const char *argv0, char *retpath); +extern int find_other_exec(const char *argv0, const char *target, + const char *versionstr, char *retpath); +extern char *pipe_read_line(char *cmd, char *line, int maxsize); + +/* Doesn't belong here, but this is used with find_other_exec(), so... */ +#define PG_BACKEND_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n" + +#ifdef EXEC_BACKEND +/* Disable ASLR before exec, for developer builds only (in exec.c) */ +extern int pg_disable_aslr(void); +#endif + + +#if defined(WIN32) || defined(__CYGWIN__) +#define EXE ".exe" +#else +#define EXE "" +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +#define DEVNULL "nul" +#else +#define DEVNULL "/dev/null" +#endif + +/* Portable delay handling */ +extern void pg_usleep(long microsec); + +/* Portable SQL-like case-independent comparisons and conversions */ +extern int pg_strcasecmp(const char *s1, const char *s2); +extern int pg_strncasecmp(const char *s1, const char *s2, size_t n); +extern unsigned char pg_toupper(unsigned char ch); +extern unsigned char pg_tolower(unsigned char ch); +extern unsigned char pg_ascii_toupper(unsigned char ch); +extern unsigned char pg_ascii_tolower(unsigned char ch); + +/* + * Beginning in v12, we always replace snprintf() and friends with our own + * implementation. This symbol is no longer consulted by the core code, + * but keep it defined anyway in case any extensions are looking at it. + */ +#define USE_REPL_SNPRINTF 1 + +/* + * Versions of libintl >= 0.13 try to replace printf() and friends with + * macros to their own versions that understand the %$ format. We do the + * same, so disable their macros, if they exist. + */ +#ifdef vsnprintf +#undef vsnprintf +#endif +#ifdef snprintf +#undef snprintf +#endif +#ifdef vsprintf +#undef vsprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef printf +#undef printf +#endif + +extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); +extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); +extern int pg_vsprintf(char *str, const char *fmt, va_list args); +extern int pg_sprintf(char *str, const char *fmt,...) pg_attribute_printf(2, 3); +extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); +extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); +extern int pg_vprintf(const char *fmt, va_list args); +extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); + +/* + * We use __VA_ARGS__ for printf to prevent replacing references to + * the "printf" format archetype in format() attribute declarations. + * That unfortunately means that taking a function pointer to printf + * will not do what we'd wish. (If you need to do that, you must name + * pg_printf explicitly.) For printf's sibling functions, use + * parameterless macros so that function pointers will work unsurprisingly. + */ +#define vsnprintf pg_vsnprintf +#define snprintf pg_snprintf +#define vsprintf pg_vsprintf +#define sprintf pg_sprintf +#define vfprintf pg_vfprintf +#define fprintf pg_fprintf +#define vprintf pg_vprintf +#define printf(...) pg_printf(__VA_ARGS__) + +/* This is also provided by snprintf.c */ +extern int pg_strfromd(char *str, size_t count, int precision, double value); + +/* Replace strerror() with our own, somewhat more robust wrapper */ +extern char *pg_strerror(int errnum); +#define strerror pg_strerror + +/* Likewise for strerror_r(); note we prefer the GNU API for that */ +extern char *pg_strerror_r(int errnum, char *buf, size_t buflen); +#define strerror_r pg_strerror_r +#define PG_STRERROR_R_BUFLEN 256 /* Recommended buffer size for strerror_r */ + +/* Wrap strsignal(), or provide our own version if necessary */ +extern const char *pg_strsignal(int signum); + +extern int pclose_check(FILE *stream); + +/* Global variable holding time zone information. */ +#if defined(WIN32) || defined(__CYGWIN__) +#define TIMEZONE_GLOBAL _timezone +#define TZNAME_GLOBAL _tzname +#else +#define TIMEZONE_GLOBAL timezone +#define TZNAME_GLOBAL tzname +#endif + +#if defined(WIN32) || defined(__CYGWIN__) +/* + * Win32 doesn't have reliable rename/unlink during concurrent access. + */ +extern int pgrename(const char *from, const char *to); +extern int pgunlink(const char *path); + +/* Include this first so later includes don't see these defines */ +#ifdef _MSC_VER +#include <io.h> +#endif + +#define rename(from, to) pgrename(from, to) +#define unlink(path) pgunlink(path) +#endif /* defined(WIN32) || defined(__CYGWIN__) */ + +/* + * Win32 also doesn't have symlinks, but we can emulate them with + * junction points on newer Win32 versions. + * + * Cygwin has its own symlinks which work on Win95/98/ME where + * junction points don't, so use those instead. We have no way of + * knowing what type of system Cygwin binaries will be run on. + * Note: Some CYGWIN includes might #define WIN32. + */ +#if defined(WIN32) && !defined(__CYGWIN__) +extern int pgsymlink(const char *oldpath, const char *newpath); +extern int pgreadlink(const char *path, char *buf, size_t size); +extern bool pgwin32_is_junction(const char *path); + +#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) +#define readlink(path, buf, size) pgreadlink(path, buf, size) +#endif + +extern bool rmtree(const char *path, bool rmtopdir); + +#if defined(WIN32) && !defined(__CYGWIN__) + +/* + * open() and fopen() replacements to allow deletion of open files and + * passing of other special options. + */ +#define O_DIRECT 0x80000000 +extern HANDLE pgwin32_open_handle(const char *, int, bool); +extern int pgwin32_open(const char *, int,...); +extern FILE *pgwin32_fopen(const char *, const char *); +#define open(a,b,c) pgwin32_open(a,b,c) +#define fopen(a,b) pgwin32_fopen(a,b) + +/* + * Mingw-w64 headers #define popen and pclose to _popen and _pclose. We want + * to use our popen wrapper, rather than plain _popen, so override that. For + * consistency, use our version of pclose, too. + */ +#ifdef popen +#undef popen +#endif +#ifdef pclose +#undef pclose +#endif + +/* + * system() and popen() replacements to enclose the command in an extra + * pair of quotes. + */ +extern int pgwin32_system(const char *command); +extern FILE *pgwin32_popen(const char *command, const char *type); + +#define system(a) pgwin32_system(a) +#define popen(a,b) pgwin32_popen(a,b) +#define pclose(a) _pclose(a) + +/* New versions of MingW have gettimeofday, old mingw and msvc don't */ +#ifndef HAVE_GETTIMEOFDAY +/* Last parameter not used */ +extern int gettimeofday(struct timeval *tp, struct timezone *tzp); +#endif +#else /* !WIN32 */ + +/* + * Win32 requires a special close for sockets and pipes, while on Unix + * close() does them all. + */ +#define closesocket close +#endif /* WIN32 */ + +/* + * On Windows, setvbuf() does not support _IOLBF mode, and interprets that + * as _IOFBF. To add insult to injury, setvbuf(file, NULL, _IOFBF, 0) + * crashes outright if "parameter validation" is enabled. Therefore, in + * places where we'd like to select line-buffered mode, we fall back to + * unbuffered mode instead on Windows. Always use PG_IOLBF not _IOLBF + * directly in order to implement this behavior. + */ +#ifndef WIN32 +#define PG_IOLBF _IOLBF +#else +#define PG_IOLBF _IONBF +#endif + +/* + * Default "extern" declarations or macro substitutes for library routines. + * When necessary, these routines are provided by files in src/port/. + */ + +/* Type to use with fseeko/ftello */ +#ifndef WIN32 /* WIN32 is handled in port/win32_port.h */ +#define pgoff_t off_t +#endif + +#ifndef HAVE_FLS +extern int fls(int mask); +#endif + +#ifndef HAVE_GETPEEREID +/* On Windows, Perl might have incompatible definitions of uid_t and gid_t. */ +#ifndef PLPERL_HAVE_UID_GID +extern int getpeereid(int sock, uid_t *uid, gid_t *gid); +#endif +#endif + +/* + * Glibc doesn't use the builtin for clang due to a *gcc* bug in a version + * newer than the gcc compatibility clang claims to have. This would cause a + * *lot* of superfluous function calls, therefore revert when using clang. In + * C++ there's issues with libc++ (not libstdc++), so disable as well. + */ +#if defined(__clang__) && !defined(__cplusplus) +/* needs to be separate to not confuse other compilers */ +#if __has_builtin(__builtin_isinf) +/* need to include before, to avoid getting overwritten */ +#include <math.h> +#undef isinf +#define isinf __builtin_isinf +#endif /* __has_builtin(isinf) */ +#endif /* __clang__ && !__cplusplus */ + +#ifndef HAVE_EXPLICIT_BZERO +extern void explicit_bzero(void *buf, size_t len); +#endif + +#ifndef HAVE_STRTOF +extern float strtof(const char *nptr, char **endptr); +#endif + +#ifdef HAVE_BUGGY_STRTOF +extern float pg_strtof(const char *nptr, char **endptr); +#define strtof(a,b) (pg_strtof((a),(b))) +#endif + +#ifndef HAVE_LINK +extern int link(const char *src, const char *dst); +#endif + +#ifndef HAVE_MKDTEMP +extern char *mkdtemp(char *path); +#endif + +#ifndef HAVE_INET_ATON +#include <netinet/in.h> +#include <arpa/inet.h> +extern int inet_aton(const char *cp, struct in_addr *addr); +#endif + +/* + * Windows and older Unix don't have pread(2) and pwrite(2). We have + * replacement functions, but they have slightly different semantics so we'll + * use a name with a pg_ prefix to avoid confusion. + */ +#ifdef HAVE_PREAD +#define pg_pread pread +#else +extern ssize_t pg_pread(int fd, void *buf, size_t nbyte, off_t offset); +#endif + +#ifdef HAVE_PWRITE +#define pg_pwrite pwrite +#else +extern ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset); +#endif + +/* For pg_pwritev() and pg_preadv(), see port/pg_iovec.h. */ + +#if !HAVE_DECL_STRLCAT +extern size_t strlcat(char *dst, const char *src, size_t siz); +#endif + +#if !HAVE_DECL_STRLCPY +extern size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +#if !HAVE_DECL_STRNLEN +extern size_t strnlen(const char *str, size_t maxlen); +#endif + +#ifndef HAVE_SETENV +extern int setenv(const char *name, const char *value, int overwrite); +#endif + +#ifndef HAVE_UNSETENV +extern int unsetenv(const char *name); +#endif + +#ifndef HAVE_DLOPEN +extern void *dlopen(const char *file, int mode); +extern void *dlsym(void *handle, const char *symbol); +extern int dlclose(void *handle); +extern char *dlerror(void); +#endif + +/* + * In some older systems, the RTLD_NOW flag isn't defined and the mode + * argument to dlopen must always be 1. + */ +#if !HAVE_DECL_RTLD_NOW +#define RTLD_NOW 1 +#endif + +/* + * The RTLD_GLOBAL flag is wanted if available, but it doesn't exist + * everywhere. If it doesn't exist, set it to 0 so it has no effect. + */ +#if !HAVE_DECL_RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +/* thread.c */ +#ifndef WIN32 +extern bool pg_get_user_name(uid_t user_id, char *buffer, size_t buflen); +extern bool pg_get_user_home_dir(uid_t user_id, char *buffer, size_t buflen); +#endif + +extern void pg_qsort(void *base, size_t nel, size_t elsize, + int (*cmp) (const void *, const void *)); +extern int pg_qsort_strcmp(const void *a, const void *b); + +#define qsort(a,b,c,d) pg_qsort(a,b,c,d) + +typedef int (*qsort_arg_comparator) (const void *a, const void *b, void *arg); + +extern void qsort_arg(void *base, size_t nel, size_t elsize, + qsort_arg_comparator cmp, void *arg); + +extern void qsort_interruptible(void *base, size_t nel, size_t elsize, + qsort_arg_comparator cmp, void *arg); + +extern void *bsearch_arg(const void *key, const void *base, + size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + void *arg); + +/* port/chklocale.c */ +extern int pg_get_encoding_from_locale(const char *ctype, bool write_message); + +#if defined(WIN32) && !defined(FRONTEND) +extern int pg_codepage_to_encoding(UINT cp); +#endif + +/* port/inet_net_ntop.c */ +extern char *pg_inet_net_ntop(int af, const void *src, int bits, + char *dst, size_t size); + +/* port/pg_strong_random.c */ +extern void pg_strong_random_init(void); +extern bool pg_strong_random(void *buf, size_t len); + +/* + * pg_backend_random used to be a wrapper for pg_strong_random before + * Postgres 12 for the backend code. + */ +#define pg_backend_random pg_strong_random + +/* port/pgcheckdir.c */ +extern int pg_check_dir(const char *dir); + +/* port/pgmkdirp.c */ +extern int pg_mkdir_p(char *path, int omode); + +/* port/pqsignal.c */ +typedef void (*pqsigfunc) (int signo); +extern pqsigfunc pqsignal(int signo, pqsigfunc func); + +/* port/quotes.c */ +extern char *escape_single_quotes_ascii(const char *src); + +/* common/wait_error.c */ +extern char *wait_result_to_str(int exit_status); +extern bool wait_result_is_signal(int exit_status, int signum); +extern bool wait_result_is_any_signal(int exit_status, bool include_command_not_found); + +#endif /* PG_PORT_H */ diff --git a/src/include/port/aix.h b/src/include/port/aix.h new file mode 100644 index 0000000..5b1159c --- /dev/null +++ b/src/include/port/aix.h @@ -0,0 +1,14 @@ +/* + * src/include/port/aix.h + */ +#define CLASS_CONFLICT +#define DISABLE_XOPEN_NLS + +/* + * "IBM XL C/C++ for AIX, V12.1" miscompiles, for 32-bit, some inline + * expansions of ginCompareItemPointers() "long long" arithmetic. To take + * advantage of inlining, build a 64-bit PostgreSQL. + */ +#if defined(__ILP32__) && defined(__IBMC__) +#define PG_FORCE_DISABLE_INLINE +#endif diff --git a/src/include/port/atomics.h b/src/include/port/atomics.h new file mode 100644 index 0000000..9550e04 --- /dev/null +++ b/src/include/port/atomics.h @@ -0,0 +1,524 @@ +/*------------------------------------------------------------------------- + * + * atomics.h + * Atomic operations. + * + * Hardware and compiler dependent functions for manipulating memory + * atomically and dealing with cache coherency. Used to implement locking + * facilities and lockless algorithms/data structures. + * + * To bring up postgres on a platform/compiler at the very least + * implementations for the following operations should be provided: + * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier() + * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32() + * * pg_atomic_test_set_flag(), pg_atomic_init_flag(), pg_atomic_clear_flag() + * * PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY should be defined if appropriate. + * + * There exist generic, hardware independent, implementations for several + * compilers which might be sufficient, although possibly not optimal, for a + * new platform. If no such generic implementation is available spinlocks (or + * even OS provided semaphores) will be used to implement the API. + * + * Implement _u64 atomics if and only if your platform can use them + * efficiently (and obviously correctly). + * + * Use higher level functionality (lwlocks, spinlocks, heavyweight locks) + * whenever possible. Writing correct code using these facilities is hard. + * + * For an introduction to using memory barriers within the PostgreSQL backend, + * see src/backend/storage/lmgr/README.barrier + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/atomics.h + * + *------------------------------------------------------------------------- + */ +#ifndef ATOMICS_H +#define ATOMICS_H + +#ifdef FRONTEND +#error "atomics.h may not be included from frontend code" +#endif + +#define INSIDE_ATOMICS_H + +#include <limits.h> + +/* + * First a set of architecture specific files is included. + * + * These files can provide the full set of atomics or can do pretty much + * nothing if all the compilers commonly used on these platforms provide + * usable generics. + * + * Don't add an inline assembly of the actual atomic operations if all the + * common implementations of your platform provide intrinsics. Intrinsics are + * much easier to understand and potentially support more architectures. + * + * It will often make sense to define memory barrier semantics here, since + * e.g. generic compiler intrinsics for x86 memory barriers can't know that + * postgres doesn't need x86 read/write barriers do anything more than a + * compiler barrier. + * + */ +#if defined(__arm__) || defined(__arm) || \ + defined(__aarch64__) || defined(__aarch64) +#include "port/atomics/arch-arm.h" +#elif defined(__i386__) || defined(__i386) || defined(__x86_64__) +#include "port/atomics/arch-x86.h" +#elif defined(__ia64__) || defined(__ia64) +#include "port/atomics/arch-ia64.h" +#elif defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__) +#include "port/atomics/arch-ppc.h" +#elif defined(__hppa) || defined(__hppa__) +#include "port/atomics/arch-hppa.h" +#endif + +/* + * Compiler specific, but architecture independent implementations. + * + * Provide architecture independent implementations of the atomic + * facilities. At the very least compiler barriers should be provided, but a + * full implementation of + * * pg_compiler_barrier(), pg_write_barrier(), pg_read_barrier() + * * pg_atomic_compare_exchange_u32(), pg_atomic_fetch_add_u32() + * using compiler intrinsics are a good idea. + */ +/* + * gcc or compatible, including clang and icc. Exclude xlc. The ppc64le "IBM + * XL C/C++ for Linux, V13.1.2" emulates gcc, but __sync_lock_test_and_set() + * of one-byte types elicits SIGSEGV. That bug was gone by V13.1.5 (2016-12). + */ +#if (defined(__GNUC__) || defined(__INTEL_COMPILER)) && !(defined(__IBMC__) || defined(__IBMCPP__)) +#include "port/atomics/generic-gcc.h" +#elif defined(_MSC_VER) +#include "port/atomics/generic-msvc.h" +#elif defined(__hpux) && defined(__ia64) && !defined(__GNUC__) +#include "port/atomics/generic-acc.h" +#elif defined(__SUNPRO_C) && !defined(__GNUC__) +#include "port/atomics/generic-sunpro.h" +#else +/* + * Unsupported compiler, we'll likely use slower fallbacks... At least + * compiler barriers should really be provided. + */ +#endif + +/* + * Provide a full fallback of the pg_*_barrier(), pg_atomic**_flag and + * pg_atomic_* APIs for platforms without sufficient spinlock and/or atomics + * support. In the case of spinlock backed atomics the emulation is expected + * to be efficient, although less so than native atomics support. + */ +#include "port/atomics/fallback.h" + +/* + * Provide additional operations using supported infrastructure. These are + * expected to be efficient if the underlying atomic operations are efficient. + */ +#include "port/atomics/generic.h" + + +/* + * pg_compiler_barrier - prevent the compiler from moving code across + * + * A compiler barrier need not (and preferably should not) emit any actual + * machine code, but must act as an optimization fence: the compiler must not + * reorder loads or stores to main memory around the barrier. However, the + * CPU may still reorder loads or stores at runtime, if the architecture's + * memory model permits this. + */ +#define pg_compiler_barrier() pg_compiler_barrier_impl() + +/* + * pg_memory_barrier - prevent the CPU from reordering memory access + * + * A memory barrier must act as a compiler barrier, and in addition must + * guarantee that all loads and stores issued prior to the barrier are + * completed before any loads or stores issued after the barrier. Unless + * loads and stores are totally ordered (which is not the case on most + * architectures) this requires issuing some sort of memory fencing + * instruction. + */ +#define pg_memory_barrier() pg_memory_barrier_impl() + +/* + * pg_(read|write)_barrier - prevent the CPU from reordering memory access + * + * A read barrier must act as a compiler barrier, and in addition must + * guarantee that any loads issued prior to the barrier are completed before + * any loads issued after the barrier. Similarly, a write barrier acts + * as a compiler barrier, and also orders stores. Read and write barriers + * are thus weaker than a full memory barrier, but stronger than a compiler + * barrier. In practice, on machines with strong memory ordering, read and + * write barriers may require nothing more than a compiler barrier. + */ +#define pg_read_barrier() pg_read_barrier_impl() +#define pg_write_barrier() pg_write_barrier_impl() + +/* + * Spinloop delay - Allow CPU to relax in busy loops + */ +#define pg_spin_delay() pg_spin_delay_impl() + +/* + * pg_atomic_init_flag - initialize atomic flag. + * + * No barrier semantics. + */ +static inline void +pg_atomic_init_flag(volatile pg_atomic_flag *ptr) +{ + pg_atomic_init_flag_impl(ptr); +} + +/* + * pg_atomic_test_set_flag - TAS() + * + * Returns true if the flag has successfully been set, false otherwise. + * + * Acquire (including read barrier) semantics. + */ +static inline bool +pg_atomic_test_set_flag(volatile pg_atomic_flag *ptr) +{ + return pg_atomic_test_set_flag_impl(ptr); +} + +/* + * pg_atomic_unlocked_test_flag - Check if the lock is free + * + * Returns true if the flag currently is not set, false otherwise. + * + * No barrier semantics. + */ +static inline bool +pg_atomic_unlocked_test_flag(volatile pg_atomic_flag *ptr) +{ + return pg_atomic_unlocked_test_flag_impl(ptr); +} + +/* + * pg_atomic_clear_flag - release lock set by TAS() + * + * Release (including write barrier) semantics. + */ +static inline void +pg_atomic_clear_flag(volatile pg_atomic_flag *ptr) +{ + pg_atomic_clear_flag_impl(ptr); +} + + +/* + * pg_atomic_init_u32 - initialize atomic variable + * + * Has to be done before any concurrent usage.. + * + * No barrier semantics. + */ +static inline void +pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + AssertPointerAlignment(ptr, 4); + + pg_atomic_init_u32_impl(ptr, val); +} + +/* + * pg_atomic_read_u32 - unlocked read from atomic variable. + * + * The read is guaranteed to return a value as it has been written by this or + * another process at some point in the past. There's however no cache + * coherency interaction guaranteeing the value hasn't since been written to + * again. + * + * No barrier semantics. + */ +static inline uint32 +pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr) +{ + AssertPointerAlignment(ptr, 4); + return pg_atomic_read_u32_impl(ptr); +} + +/* + * pg_atomic_write_u32 - write to atomic variable. + * + * The write is guaranteed to succeed as a whole, i.e. it's not possible to + * observe a partial write for any reader. Note that this correctly interacts + * with pg_atomic_compare_exchange_u32, in contrast to + * pg_atomic_unlocked_write_u32(). + * + * No barrier semantics. + */ +static inline void +pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + AssertPointerAlignment(ptr, 4); + + pg_atomic_write_u32_impl(ptr, val); +} + +/* + * pg_atomic_unlocked_write_u32 - unlocked write to atomic variable. + * + * The write is guaranteed to succeed as a whole, i.e. it's not possible to + * observe a partial write for any reader. But note that writing this way is + * not guaranteed to correctly interact with read-modify-write operations like + * pg_atomic_compare_exchange_u32. This should only be used in cases where + * minor performance regressions due to atomics emulation are unacceptable. + * + * No barrier semantics. + */ +static inline void +pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + AssertPointerAlignment(ptr, 4); + + pg_atomic_unlocked_write_u32_impl(ptr, val); +} + +/* + * pg_atomic_exchange_u32 - exchange newval with current value + * + * Returns the old value of 'ptr' before the swap. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval) +{ + AssertPointerAlignment(ptr, 4); + + return pg_atomic_exchange_u32_impl(ptr, newval); +} + +/* + * pg_atomic_compare_exchange_u32 - CAS operation + * + * Atomically compare the current value of ptr with *expected and store newval + * iff ptr and *expected have the same value. The current value of *ptr will + * always be stored in *expected. + * + * Return true if values have been exchanged, false otherwise. + * + * Full barrier semantics. + */ +static inline bool +pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + AssertPointerAlignment(ptr, 4); + AssertPointerAlignment(expected, 4); + + return pg_atomic_compare_exchange_u32_impl(ptr, expected, newval); +} + +/* + * pg_atomic_fetch_add_u32 - atomically add to variable + * + * Returns the value of ptr before the arithmetic operation. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + AssertPointerAlignment(ptr, 4); + return pg_atomic_fetch_add_u32_impl(ptr, add_); +} + +/* + * pg_atomic_fetch_sub_u32 - atomically subtract from variable + * + * Returns the value of ptr before the arithmetic operation. Note that sub_ + * may not be INT_MIN due to platform limitations. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_) +{ + AssertPointerAlignment(ptr, 4); + Assert(sub_ != INT_MIN); + return pg_atomic_fetch_sub_u32_impl(ptr, sub_); +} + +/* + * pg_atomic_fetch_and_u32 - atomically bit-and and_ with variable + * + * Returns the value of ptr before the arithmetic operation. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_) +{ + AssertPointerAlignment(ptr, 4); + return pg_atomic_fetch_and_u32_impl(ptr, and_); +} + +/* + * pg_atomic_fetch_or_u32 - atomically bit-or or_ with variable + * + * Returns the value of ptr before the arithmetic operation. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_) +{ + AssertPointerAlignment(ptr, 4); + return pg_atomic_fetch_or_u32_impl(ptr, or_); +} + +/* + * pg_atomic_add_fetch_u32 - atomically add to variable + * + * Returns the value of ptr after the arithmetic operation. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_add_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + AssertPointerAlignment(ptr, 4); + return pg_atomic_add_fetch_u32_impl(ptr, add_); +} + +/* + * pg_atomic_sub_fetch_u32 - atomically subtract from variable + * + * Returns the value of ptr after the arithmetic operation. Note that sub_ may + * not be INT_MIN due to platform limitations. + * + * Full barrier semantics. + */ +static inline uint32 +pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_) +{ + AssertPointerAlignment(ptr, 4); + Assert(sub_ != INT_MIN); + return pg_atomic_sub_fetch_u32_impl(ptr, sub_); +} + +/* ---- + * The 64 bit operations have the same semantics as their 32bit counterparts + * if they are available. Check the corresponding 32bit function for + * documentation. + * ---- + */ +static inline void +pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val) +{ + /* + * Can't necessarily enforce alignment - and don't need it - when using + * the spinlock based fallback implementation. Therefore only assert when + * not using it. + */ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + pg_atomic_init_u64_impl(ptr, val); +} + +static inline uint64 +pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_read_u64_impl(ptr); +} + +static inline void +pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + pg_atomic_write_u64_impl(ptr, val); +} + +static inline uint64 +pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_exchange_u64_impl(ptr, newval); +} + +static inline bool +pg_atomic_compare_exchange_u64(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); + AssertPointerAlignment(expected, 8); +#endif + return pg_atomic_compare_exchange_u64_impl(ptr, expected, newval); +} + +static inline uint64 +pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_fetch_add_u64_impl(ptr, add_); +} + +static inline uint64 +pg_atomic_fetch_sub_u64(volatile pg_atomic_uint64 *ptr, int64 sub_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + Assert(sub_ != PG_INT64_MIN); + return pg_atomic_fetch_sub_u64_impl(ptr, sub_); +} + +static inline uint64 +pg_atomic_fetch_and_u64(volatile pg_atomic_uint64 *ptr, uint64 and_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_fetch_and_u64_impl(ptr, and_); +} + +static inline uint64 +pg_atomic_fetch_or_u64(volatile pg_atomic_uint64 *ptr, uint64 or_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_fetch_or_u64_impl(ptr, or_); +} + +static inline uint64 +pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + return pg_atomic_add_fetch_u64_impl(ptr, add_); +} + +static inline uint64 +pg_atomic_sub_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 sub_) +{ +#ifndef PG_HAVE_ATOMIC_U64_SIMULATION + AssertPointerAlignment(ptr, 8); +#endif + Assert(sub_ != PG_INT64_MIN); + return pg_atomic_sub_fetch_u64_impl(ptr, sub_); +} + +#undef INSIDE_ATOMICS_H + +#endif /* ATOMICS_H */ diff --git a/src/include/port/atomics/arch-arm.h b/src/include/port/atomics/arch-arm.h new file mode 100644 index 0000000..9fe8f1b --- /dev/null +++ b/src/include/port/atomics/arch-arm.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * arch-arm.h + * Atomic operations considerations specific to ARM + * + * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group + * + * NOTES: + * + * src/include/port/atomics/arch-arm.h + * + *------------------------------------------------------------------------- + */ + +/* intentionally no include guards, should only be included by atomics.h */ +#ifndef INSIDE_ATOMICS_H +#error "should be included via atomics.h" +#endif + +/* + * 64 bit atomics on ARM32 are implemented using kernel fallbacks and thus + * might be slow, so disable entirely. On ARM64 that problem doesn't exist. + */ +#if !defined(__aarch64__) && !defined(__aarch64) +#define PG_DISABLE_64_BIT_ATOMICS +#else +/* + * Architecture Reference Manual for ARMv8 states aligned read/write to/from + * general purpose register is atomic. + */ +#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY +#endif /* __aarch64__ || __aarch64 */ diff --git a/src/include/port/atomics/arch-hppa.h b/src/include/port/atomics/arch-hppa.h new file mode 100644 index 0000000..7a7bb6e --- /dev/null +++ b/src/include/port/atomics/arch-hppa.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * arch-hppa.h + * Atomic operations considerations specific to HPPA + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * src/include/port/atomics/arch-hppa.h + * + *------------------------------------------------------------------------- + */ + +/* HPPA doesn't do either read or write reordering */ +#define pg_memory_barrier_impl() pg_compiler_barrier_impl() diff --git a/src/include/port/atomics/arch-ia64.h b/src/include/port/atomics/arch-ia64.h new file mode 100644 index 0000000..771bac1 --- /dev/null +++ b/src/include/port/atomics/arch-ia64.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * arch-ia64.h + * Atomic operations considerations specific to intel itanium + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * src/include/port/atomics/arch-ia64.h + * + *------------------------------------------------------------------------- + */ + +/* + * Itanium is weakly ordered, so read and write barriers require a full + * fence. + */ +#if defined(__INTEL_COMPILER) +# define pg_memory_barrier_impl() __mf() +#elif defined(__GNUC__) +# define pg_memory_barrier_impl() __asm__ __volatile__ ("mf" : : : "memory") +#elif defined(__hpux) +# define pg_memory_barrier_impl() _Asm_mf() +#endif + +/* per architecture manual doubleword accesses have single copy atomicity */ +#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h new file mode 100644 index 0000000..eb64513 --- /dev/null +++ b/src/include/port/atomics/arch-ppc.h @@ -0,0 +1,254 @@ +/*------------------------------------------------------------------------- + * + * arch-ppc.h + * Atomic operations considerations specific to PowerPC + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * src/include/port/atomics/arch-ppc.h + * + *------------------------------------------------------------------------- + */ + +#if defined(__GNUC__) + +/* + * lwsync orders loads with respect to each other, and similarly with stores. + * But a load can be performed before a subsequent store, so sync must be used + * for a full memory barrier. + */ +#define pg_memory_barrier_impl() __asm__ __volatile__ ("sync" : : : "memory") +#define pg_read_barrier_impl() __asm__ __volatile__ ("lwsync" : : : "memory") +#define pg_write_barrier_impl() __asm__ __volatile__ ("lwsync" : : : "memory") +#endif + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +/* 64bit atomics are only supported in 64bit mode */ +#if SIZEOF_VOID_P >= 8 +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct pg_atomic_uint64 +{ + volatile uint64 value pg_attribute_aligned(8); +} pg_atomic_uint64; + +#endif + +/* + * This mimics gcc __atomic_compare_exchange_n(..., __ATOMIC_SEQ_CST), but + * code generation differs at the end. __atomic_compare_exchange_n(): + * 100: isync + * 104: mfcr r3 + * 108: rlwinm r3,r3,3,31,31 + * 10c: bne 120 <.eb+0x10> + * 110: clrldi r3,r3,63 + * 114: addi r1,r1,112 + * 118: blr + * 11c: nop + * 120: clrldi r3,r3,63 + * 124: stw r9,0(r4) + * 128: addi r1,r1,112 + * 12c: blr + * + * This: + * f0: isync + * f4: mfcr r9 + * f8: rldicl. r3,r9,35,63 + * fc: bne 104 <.eb> + * 100: stw r10,0(r4) + * 104: addi r1,r1,112 + * 108: blr + * + * This implementation may or may not have materially different performance. + * It's not exploiting the fact that cr0 still holds the relevant comparison + * bits, set during the __asm__. One could fix that by moving more code into + * the __asm__. (That would remove the freedom to eliminate dead stores when + * the caller ignores "expected", but few callers do.) + * + * Recognizing constant "newval" would be superfluous, because there's no + * immediate-operand version of stwcx. + */ +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + uint32 found; + uint32 condition_register; + bool ret; + +#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P + if (__builtin_constant_p(*expected) && + (int32) *expected <= PG_INT16_MAX && + (int32) *expected >= PG_INT16_MIN) + __asm__ __volatile__( + " sync \n" + " lwarx %0,0,%5 \n" + " cmpwi %0,%3 \n" + " bne $+12 \n" /* branch to isync */ + " stwcx. %4,0,%5 \n" + " bne $-16 \n" /* branch to lwarx */ + " isync \n" + " mfcr %1 \n" +: "=&r"(found), "=r"(condition_register), "+m"(ptr->value) +: "i"(*expected), "r"(newval), "r"(&ptr->value) +: "memory", "cc"); + else +#endif + __asm__ __volatile__( + " sync \n" + " lwarx %0,0,%5 \n" + " cmpw %0,%3 \n" + " bne $+12 \n" /* branch to isync */ + " stwcx. %4,0,%5 \n" + " bne $-16 \n" /* branch to lwarx */ + " isync \n" + " mfcr %1 \n" +: "=&r"(found), "=r"(condition_register), "+m"(ptr->value) +: "r"(*expected), "r"(newval), "r"(&ptr->value) +: "memory", "cc"); + + ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */ + if (!ret) + *expected = found; + return ret; +} + +/* + * This mirrors gcc __sync_fetch_and_add(). + * + * Like tas(), use constraint "=&b" to avoid allocating r0. + */ +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +static inline uint32 +pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + uint32 _t; + uint32 res; + +#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P + if (__builtin_constant_p(add_) && + add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN) + __asm__ __volatile__( + " sync \n" + " lwarx %1,0,%4 \n" + " addi %0,%1,%3 \n" + " stwcx. %0,0,%4 \n" + " bne $-12 \n" /* branch to lwarx */ + " isync \n" +: "=&r"(_t), "=&b"(res), "+m"(ptr->value) +: "i"(add_), "r"(&ptr->value) +: "memory", "cc"); + else +#endif + __asm__ __volatile__( + " sync \n" + " lwarx %1,0,%4 \n" + " add %0,%1,%3 \n" + " stwcx. %0,0,%4 \n" + " bne $-12 \n" /* branch to lwarx */ + " isync \n" +: "=&r"(_t), "=&r"(res), "+m"(ptr->value) +: "r"(add_), "r"(&ptr->value) +: "memory", "cc"); + + return res; +} + +#ifdef PG_HAVE_ATOMIC_U64_SUPPORT + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + uint64 found; + uint32 condition_register; + bool ret; + + /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/; s/cmpw/cmpd/ */ +#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P + if (__builtin_constant_p(*expected) && + (int64) *expected <= PG_INT16_MAX && + (int64) *expected >= PG_INT16_MIN) + __asm__ __volatile__( + " sync \n" + " ldarx %0,0,%5 \n" + " cmpdi %0,%3 \n" + " bne $+12 \n" /* branch to isync */ + " stdcx. %4,0,%5 \n" + " bne $-16 \n" /* branch to ldarx */ + " isync \n" + " mfcr %1 \n" +: "=&r"(found), "=r"(condition_register), "+m"(ptr->value) +: "i"(*expected), "r"(newval), "r"(&ptr->value) +: "memory", "cc"); + else +#endif + __asm__ __volatile__( + " sync \n" + " ldarx %0,0,%5 \n" + " cmpd %0,%3 \n" + " bne $+12 \n" /* branch to isync */ + " stdcx. %4,0,%5 \n" + " bne $-16 \n" /* branch to ldarx */ + " isync \n" + " mfcr %1 \n" +: "=&r"(found), "=r"(condition_register), "+m"(ptr->value) +: "r"(*expected), "r"(newval), "r"(&ptr->value) +: "memory", "cc"); + + ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */ + if (!ret) + *expected = found; + return ret; +} + +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +static inline uint64 +pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + uint64 _t; + uint64 res; + + /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/ */ +#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P + if (__builtin_constant_p(add_) && + add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN) + __asm__ __volatile__( + " sync \n" + " ldarx %1,0,%4 \n" + " addi %0,%1,%3 \n" + " stdcx. %0,0,%4 \n" + " bne $-12 \n" /* branch to ldarx */ + " isync \n" +: "=&r"(_t), "=&b"(res), "+m"(ptr->value) +: "i"(add_), "r"(&ptr->value) +: "memory", "cc"); + else +#endif + __asm__ __volatile__( + " sync \n" + " ldarx %1,0,%4 \n" + " add %0,%1,%3 \n" + " stdcx. %0,0,%4 \n" + " bne $-12 \n" /* branch to ldarx */ + " isync \n" +: "=&r"(_t), "=&r"(res), "+m"(ptr->value) +: "r"(add_), "r"(&ptr->value) +: "memory", "cc"); + + return res; +} + +#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */ + +/* per architecture manual doubleword accesses have single copy atomicity */ +#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY diff --git a/src/include/port/atomics/arch-x86.h b/src/include/port/atomics/arch-x86.h new file mode 100644 index 0000000..cef1ba7 --- /dev/null +++ b/src/include/port/atomics/arch-x86.h @@ -0,0 +1,252 @@ +/*------------------------------------------------------------------------- + * + * arch-x86.h + * Atomic operations considerations specific to intel x86 + * + * Note that we actually require a 486 upwards because the 386 doesn't have + * support for xadd and cmpxchg. Given that the 386 isn't supported anywhere + * anymore that's not much of a restriction luckily. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * src/include/port/atomics/arch-x86.h + * + *------------------------------------------------------------------------- + */ + +/* + * Both 32 and 64 bit x86 do not allow loads to be reordered with other loads, + * or stores to be reordered with other stores, but a load can be performed + * before a subsequent store. + * + * Technically, some x86-ish chips support uncached memory access and/or + * special instructions that are weakly ordered. In those cases we'd need + * the read and write barriers to be lfence and sfence. But since we don't + * do those things, a compiler barrier should be enough. + * + * "lock; addl" has worked for longer than "mfence". It's also rumored to be + * faster in many scenarios. + */ + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#if defined(__i386__) || defined(__i386) +#define pg_memory_barrier_impl() \ + __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory", "cc") +#elif defined(__x86_64__) +#define pg_memory_barrier_impl() \ + __asm__ __volatile__ ("lock; addl $0,0(%%rsp)" : : : "memory", "cc") +#endif +#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */ + +#define pg_read_barrier_impl() pg_compiler_barrier_impl() +#define pg_write_barrier_impl() pg_compiler_barrier_impl() + +/* + * Provide implementation for atomics using inline assembly on x86 gcc. It's + * nice to support older gcc's and the compare/exchange implementation here is + * actually more efficient than the * __sync variant. + */ +#if defined(HAVE_ATOMICS) + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +#define PG_HAVE_ATOMIC_FLAG_SUPPORT +typedef struct pg_atomic_flag +{ + volatile char value; +} pg_atomic_flag; + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +/* + * It's too complicated to write inline asm for 64bit types on 32bit and the + * 486 can't do it anyway. + */ +#ifdef __x86_64__ +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct pg_atomic_uint64 +{ + /* alignment guaranteed due to being on a 64bit platform */ + volatile uint64 value; +} pg_atomic_uint64; +#endif /* __x86_64__ */ + +#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */ + +#endif /* defined(HAVE_ATOMICS) */ + +#if !defined(PG_HAVE_SPIN_DELAY) +/* + * This sequence is equivalent to the PAUSE instruction ("rep" is + * ignored by old IA32 processors if the following instruction is + * not a string operation); the IA-32 Architecture Software + * Developer's Manual, Vol. 3, Section 7.7.2 describes why using + * PAUSE in the inner loop of a spin lock is necessary for good + * performance: + * + * The PAUSE instruction improves the performance of IA-32 + * processors supporting Hyper-Threading Technology when + * executing spin-wait loops and other routines where one + * thread is accessing a shared lock or semaphore in a tight + * polling loop. When executing a spin-wait loop, the + * processor can suffer a severe performance penalty when + * exiting the loop because it detects a possible memory order + * violation and flushes the core processor's pipeline. The + * PAUSE instruction provides a hint to the processor that the + * code sequence is a spin-wait loop. The processor uses this + * hint to avoid the memory order violation and prevent the + * pipeline flush. In addition, the PAUSE instruction + * de-pipelines the spin-wait loop to prevent it from + * consuming execution resources excessively. + */ +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define PG_HAVE_SPIN_DELAY +static __inline__ void +pg_spin_delay_impl(void) +{ + __asm__ __volatile__(" rep; nop \n"); +} +#elif defined(_MSC_VER) && defined(__x86_64__) +#define PG_HAVE_SPIN_DELAY +static __forceinline void +pg_spin_delay_impl(void) +{ + _mm_pause(); +} +#elif defined(_MSC_VER) +#define PG_HAVE_SPIN_DELAY +static __forceinline void +pg_spin_delay_impl(void) +{ + /* See comment for gcc code. Same code, MASM syntax */ + __asm rep nop; +} +#endif +#endif /* !defined(PG_HAVE_SPIN_DELAY) */ + + +#if defined(HAVE_ATOMICS) + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +#define PG_HAVE_ATOMIC_TEST_SET_FLAG +static inline bool +pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr) +{ + register char _res = 1; + + __asm__ __volatile__( + " lock \n" + " xchgb %0,%1 \n" +: "+q"(_res), "+m"(ptr->value) +: +: "memory"); + return _res == 0; +} + +#define PG_HAVE_ATOMIC_CLEAR_FLAG +static inline void +pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr) +{ + /* + * On a TSO architecture like x86 it's sufficient to use a compiler + * barrier to achieve release semantics. + */ + __asm__ __volatile__("" ::: "memory"); + ptr->value = 0; +} + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + char ret; + + /* + * Perform cmpxchg and use the zero flag which it implicitly sets when + * equal to measure the success. + */ + __asm__ __volatile__( + " lock \n" + " cmpxchgl %4,%5 \n" + " setz %2 \n" +: "=a" (*expected), "=m"(ptr->value), "=q" (ret) +: "a" (*expected), "r" (newval), "m"(ptr->value) +: "memory", "cc"); + return (bool) ret; +} + +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +static inline uint32 +pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + uint32 res; + __asm__ __volatile__( + " lock \n" + " xaddl %0,%1 \n" +: "=q"(res), "=m"(ptr->value) +: "0" (add_), "m"(ptr->value) +: "memory", "cc"); + return res; +} + +#ifdef __x86_64__ + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + char ret; + + /* + * Perform cmpxchg and use the zero flag which it implicitly sets when + * equal to measure the success. + */ + __asm__ __volatile__( + " lock \n" + " cmpxchgq %4,%5 \n" + " setz %2 \n" +: "=a" (*expected), "=m"(ptr->value), "=q" (ret) +: "a" (*expected), "r" (newval), "m"(ptr->value) +: "memory", "cc"); + return (bool) ret; +} + +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +static inline uint64 +pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + uint64 res; + __asm__ __volatile__( + " lock \n" + " xaddq %0,%1 \n" +: "=q"(res), "=m"(ptr->value) +: "0" (add_), "m"(ptr->value) +: "memory", "cc"); + return res; +} + +#endif /* __x86_64__ */ + +#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */ + +/* + * 8 byte reads / writes have single-copy atomicity on 32 bit x86 platforms + * since at least the 586. As well as on all x86-64 cpus. + */ +#if defined(__i568__) || defined(__i668__) || /* gcc i586+ */ \ + (defined(_M_IX86) && _M_IX86 >= 500) || /* msvc i586+ */ \ + defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) /* gcc, sunpro, msvc */ +#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY +#endif /* 8 byte single-copy atomicity */ + +#endif /* HAVE_ATOMICS */ diff --git a/src/include/port/atomics/fallback.h b/src/include/port/atomics/fallback.h new file mode 100644 index 0000000..1cdef5f --- /dev/null +++ b/src/include/port/atomics/fallback.h @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------- + * + * fallback.h + * Fallback for platforms without spinlock and/or atomics support. Slower + * than native atomics support, but not unusably slow. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/atomics/fallback.h + * + *------------------------------------------------------------------------- + */ + +/* intentionally no include guards, should only be included by atomics.h */ +#ifndef INSIDE_ATOMICS_H +# error "should be included via atomics.h" +#endif + +#ifndef pg_memory_barrier_impl +/* + * If we have no memory barrier implementation for this architecture, we + * fall back to acquiring and releasing a spinlock. This might, in turn, + * fall back to the semaphore-based spinlock implementation, which will be + * amazingly slow. + * + * It's not self-evident that every possible legal implementation of a + * spinlock acquire-and-release would be equivalent to a full memory barrier. + * For example, I'm not sure that Itanium's acq and rel add up to a full + * fence. But all of our actual implementations seem OK in this regard. + */ +#define PG_HAVE_MEMORY_BARRIER_EMULATION + +extern void pg_spinlock_barrier(void); +#define pg_memory_barrier_impl pg_spinlock_barrier +#endif + +#ifndef pg_compiler_barrier_impl +/* + * If the compiler/arch combination does not provide compiler barriers, + * provide a fallback. The fallback simply consists of a function call into + * an externally defined function. That should guarantee compiler barrier + * semantics except for compilers that do inter translation unit/global + * optimization - those better provide an actual compiler barrier. + * + * A native compiler barrier for sure is a lot faster than this... + */ +#define PG_HAVE_COMPILER_BARRIER_EMULATION +extern void pg_extern_compiler_barrier(void); +#define pg_compiler_barrier_impl pg_extern_compiler_barrier +#endif + + +/* + * If we have atomics implementation for this platform, fall back to providing + * the atomics API using a spinlock to protect the internal state. Possibly + * the spinlock implementation uses semaphores internally... + * + * We have to be a bit careful here, as it's not guaranteed that atomic + * variables are mapped to the same address in every process (e.g. dynamic + * shared memory segments). We can't just hash the address and use that to map + * to a spinlock. Instead assign a spinlock on initialization of the atomic + * variable. + */ +#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && !defined(PG_HAVE_ATOMIC_U32_SUPPORT) + +#define PG_HAVE_ATOMIC_FLAG_SIMULATION +#define PG_HAVE_ATOMIC_FLAG_SUPPORT + +typedef struct pg_atomic_flag +{ + /* + * To avoid circular includes we can't use s_lock as a type here. Instead + * just reserve enough space for all spinlock types. Some platforms would + * be content with just one byte instead of 4, but that's not too much + * waste. + */ +#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ + int sema[4]; +#else + int sema; +#endif + volatile bool value; +} pg_atomic_flag; + +#endif /* PG_HAVE_ATOMIC_FLAG_SUPPORT */ + +#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT) + +#define PG_HAVE_ATOMIC_U32_SIMULATION + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + /* Check pg_atomic_flag's definition above for an explanation */ +#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ + int sema[4]; +#else + int sema; +#endif + volatile uint32 value; +} pg_atomic_uint32; + +#endif /* PG_HAVE_ATOMIC_U32_SUPPORT */ + +#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT) + +#define PG_HAVE_ATOMIC_U64_SIMULATION + +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct pg_atomic_uint64 +{ + /* Check pg_atomic_flag's definition above for an explanation */ +#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ + int sema[4]; +#else + int sema; +#endif + volatile uint64 value; +} pg_atomic_uint64; + +#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */ + +#ifdef PG_HAVE_ATOMIC_FLAG_SIMULATION + +#define PG_HAVE_ATOMIC_INIT_FLAG +extern void pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr); + +#define PG_HAVE_ATOMIC_TEST_SET_FLAG +extern bool pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr); + +#define PG_HAVE_ATOMIC_CLEAR_FLAG +extern void pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr); + +#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG +extern bool pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr); + +#endif /* PG_HAVE_ATOMIC_FLAG_SIMULATION */ + +#ifdef PG_HAVE_ATOMIC_U32_SIMULATION + +#define PG_HAVE_ATOMIC_INIT_U32 +extern void pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_); + +#define PG_HAVE_ATOMIC_WRITE_U32 +extern void pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val); + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +extern bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval); + +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +extern uint32 pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_); + +#endif /* PG_HAVE_ATOMIC_U32_SIMULATION */ + + +#ifdef PG_HAVE_ATOMIC_U64_SIMULATION + +#define PG_HAVE_ATOMIC_INIT_U64 +extern void pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_); + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +extern bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval); + +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +extern uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_); + +#endif /* PG_HAVE_ATOMIC_U64_SIMULATION */ diff --git a/src/include/port/atomics/generic-acc.h b/src/include/port/atomics/generic-acc.h new file mode 100644 index 0000000..842b2de --- /dev/null +++ b/src/include/port/atomics/generic-acc.h @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------- + * + * generic-acc.h + * Atomic operations support when using HPs acc on HPUX + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * Documentation: + * * inline assembly for Itanium-based HP-UX: + * http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/inline_assem_ERS.pdf + * * Implementing Spinlocks on the Intel (R) Itanium (R) Architecture and PA-RISC + * http://h21007.www2.hp.com/portal/download/files/unprot/itanium/spinlocks.pdf + * + * Itanium only supports a small set of numbers (6, -8, -4, -1, 1, 4, 8, 16) + * for atomic add/sub, so we just implement everything but compare_exchange + * via the compare_exchange fallbacks in atomics/generic.h. + * + * src/include/port/atomics/generic-acc.h + * + * ------------------------------------------------------------------------- + */ + +#include <machine/sys/inline.h> + +#define pg_compiler_barrier_impl() _Asm_sched_fence() + +#if defined(HAVE_ATOMICS) + +/* IA64 always has 32/64 bit atomics */ + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct pg_atomic_uint64 +{ + /* + * Alignment is guaranteed to be 64bit. Search for "Well-behaved + * application restrictions" => "Data alignment and data sharing" on HP's + * website. Unfortunately the URL doesn't seem to stable enough to + * include. + */ + volatile uint64 value; +} pg_atomic_uint64; + + +#define MINOR_FENCE (_Asm_fence) (_UP_CALL_FENCE | _UP_SYS_FENCE | \ + _DOWN_CALL_FENCE | _DOWN_SYS_FENCE ) + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + + _Asm_mov_to_ar(_AREG_CCV, *expected, MINOR_FENCE); + /* + * We want a barrier, not just release/acquire semantics. + */ + _Asm_mf(); + /* + * Notes: + * _DOWN_MEM_FENCE | _UP_MEM_FENCE prevents reordering by the compiler + */ + current = _Asm_cmpxchg(_SZ_W, /* word */ + _SEM_REL, + &ptr->value, + newval, _LDHINT_NONE, + _DOWN_MEM_FENCE | _UP_MEM_FENCE); + ret = current == *expected; + *expected = current; + return ret; +} + + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + bool ret; + uint64 current; + + _Asm_mov_to_ar(_AREG_CCV, *expected, MINOR_FENCE); + _Asm_mf(); + current = _Asm_cmpxchg(_SZ_D, /* doubleword */ + _SEM_REL, + &ptr->value, + newval, _LDHINT_NONE, + _DOWN_MEM_FENCE | _UP_MEM_FENCE); + ret = current == *expected; + *expected = current; + return ret; +} + +#undef MINOR_FENCE + +#endif /* defined(HAVE_ATOMICS) */ diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h new file mode 100644 index 0000000..6c566af --- /dev/null +++ b/src/include/port/atomics/generic-gcc.h @@ -0,0 +1,286 @@ +/*------------------------------------------------------------------------- + * + * generic-gcc.h + * Atomic operations, implemented using gcc (or compatible) intrinsics. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * Documentation: + * * Legacy __sync Built-in Functions for Atomic Memory Access + * https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fsync-Builtins.html + * * Built-in functions for memory model aware atomic operations + * https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html + * + * src/include/port/atomics/generic-gcc.h + * + *------------------------------------------------------------------------- + */ + +/* intentionally no include guards, should only be included by atomics.h */ +#ifndef INSIDE_ATOMICS_H +#error "should be included via atomics.h" +#endif + +/* + * An empty asm block should be a sufficient compiler barrier. + */ +#define pg_compiler_barrier_impl() __asm__ __volatile__("" ::: "memory") + +/* + * If we're on GCC 4.1.0 or higher, we should be able to get a memory barrier + * out of this compiler built-in. But we prefer to rely on platform specific + * definitions where possible, and use this only as a fallback. + */ +#if !defined(pg_memory_barrier_impl) +# if defined(HAVE_GCC__ATOMIC_INT32_CAS) +# define pg_memory_barrier_impl() __atomic_thread_fence(__ATOMIC_SEQ_CST) +# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +# define pg_memory_barrier_impl() __sync_synchronize() +# endif +#endif /* !defined(pg_memory_barrier_impl) */ + +#if !defined(pg_read_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS) +/* acquire semantics include read barrier semantics */ +# define pg_read_barrier_impl() __atomic_thread_fence(__ATOMIC_ACQUIRE) +#endif + +#if !defined(pg_write_barrier_impl) && defined(HAVE_GCC__ATOMIC_INT32_CAS) +/* release semantics include write barrier semantics */ +# define pg_write_barrier_impl() __atomic_thread_fence(__ATOMIC_RELEASE) +#endif + + +#ifdef HAVE_ATOMICS + +/* generic gcc based atomic flag implementation */ +#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) \ + && (defined(HAVE_GCC__SYNC_INT32_TAS) || defined(HAVE_GCC__SYNC_CHAR_TAS)) + +#define PG_HAVE_ATOMIC_FLAG_SUPPORT +typedef struct pg_atomic_flag +{ + /* + * If we have a choice, use int-width TAS, because that is more efficient + * and/or more reliably implemented on most non-Intel platforms. (Note + * that this code isn't used on x86[_64]; see arch-x86.h for that.) + */ +#ifdef HAVE_GCC__SYNC_INT32_TAS + volatile int value; +#else + volatile char value; +#endif +} pg_atomic_flag; + +#endif /* !ATOMIC_FLAG_SUPPORT && SYNC_INT32_TAS */ + +/* generic gcc based atomic uint32 implementation */ +#if !defined(PG_HAVE_ATOMIC_U32_SUPPORT) \ + && (defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS)) + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +#endif /* defined(HAVE_GCC__ATOMIC_INT32_CAS) || defined(HAVE_GCC__SYNC_INT32_CAS) */ + +/* generic gcc based atomic uint64 implementation */ +#if !defined(PG_HAVE_ATOMIC_U64_SUPPORT) \ + && !defined(PG_DISABLE_64_BIT_ATOMICS) \ + && (defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS)) + +#define PG_HAVE_ATOMIC_U64_SUPPORT + +typedef struct pg_atomic_uint64 +{ + volatile uint64 value pg_attribute_aligned(8); +} pg_atomic_uint64; + +#endif /* defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS) */ + +#ifdef PG_HAVE_ATOMIC_FLAG_SUPPORT + +#if defined(HAVE_GCC__SYNC_CHAR_TAS) || defined(HAVE_GCC__SYNC_INT32_TAS) + +#ifndef PG_HAVE_ATOMIC_TEST_SET_FLAG +#define PG_HAVE_ATOMIC_TEST_SET_FLAG +static inline bool +pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr) +{ + /* NB: only an acquire barrier, not a full one */ + /* some platform only support a 1 here */ + return __sync_lock_test_and_set(&ptr->value, 1) == 0; +} +#endif + +#endif /* defined(HAVE_GCC__SYNC_*_TAS) */ + +#ifndef PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG +#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG +static inline bool +pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr) +{ + return ptr->value == 0; +} +#endif + +#ifndef PG_HAVE_ATOMIC_CLEAR_FLAG +#define PG_HAVE_ATOMIC_CLEAR_FLAG +static inline void +pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr) +{ + __sync_lock_release(&ptr->value); +} +#endif + +#ifndef PG_HAVE_ATOMIC_INIT_FLAG +#define PG_HAVE_ATOMIC_INIT_FLAG +static inline void +pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr) +{ + pg_atomic_clear_flag_impl(ptr); +} +#endif + +#endif /* defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) */ + +/* prefer __atomic, it has a better API */ +#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__ATOMIC_INT32_CAS) +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + /* FIXME: we can probably use a lower consistency model */ + return __atomic_compare_exchange_n(&ptr->value, expected, newval, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) && defined(HAVE_GCC__SYNC_INT32_CAS) +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + current = __sync_val_compare_and_swap(&ptr->value, *expected, newval); + ret = current == *expected; + *expected = current; + return ret; +} +#endif + +/* if we have 32-bit __sync_val_compare_and_swap, assume we have these too: */ + +#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(HAVE_GCC__SYNC_INT32_CAS) +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +static inline uint32 +pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + return __sync_fetch_and_add(&ptr->value, add_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(HAVE_GCC__SYNC_INT32_CAS) +#define PG_HAVE_ATOMIC_FETCH_SUB_U32 +static inline uint32 +pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_) +{ + return __sync_fetch_and_sub(&ptr->value, sub_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(HAVE_GCC__SYNC_INT32_CAS) +#define PG_HAVE_ATOMIC_FETCH_AND_U32 +static inline uint32 +pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_) +{ + return __sync_fetch_and_and(&ptr->value, and_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(HAVE_GCC__SYNC_INT32_CAS) +#define PG_HAVE_ATOMIC_FETCH_OR_U32 +static inline uint32 +pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_) +{ + return __sync_fetch_and_or(&ptr->value, or_); +} +#endif + + +#if !defined(PG_DISABLE_64_BIT_ATOMICS) + +#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__ATOMIC_INT64_CAS) +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + return __atomic_compare_exchange_n(&ptr->value, expected, newval, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) && defined(HAVE_GCC__SYNC_INT64_CAS) +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + bool ret; + uint64 current; + current = __sync_val_compare_and_swap(&ptr->value, *expected, newval); + ret = current == *expected; + *expected = current; + return ret; +} +#endif + +/* if we have 64-bit __sync_val_compare_and_swap, assume we have these too: */ + +#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(HAVE_GCC__SYNC_INT64_CAS) +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +static inline uint64 +pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + return __sync_fetch_and_add(&ptr->value, add_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(HAVE_GCC__SYNC_INT64_CAS) +#define PG_HAVE_ATOMIC_FETCH_SUB_U64 +static inline uint64 +pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_) +{ + return __sync_fetch_and_sub(&ptr->value, sub_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(HAVE_GCC__SYNC_INT64_CAS) +#define PG_HAVE_ATOMIC_FETCH_AND_U64 +static inline uint64 +pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_) +{ + return __sync_fetch_and_and(&ptr->value, and_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(HAVE_GCC__SYNC_INT64_CAS) +#define PG_HAVE_ATOMIC_FETCH_OR_U64 +static inline uint64 +pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_) +{ + return __sync_fetch_and_or(&ptr->value, or_); +} +#endif + +#endif /* !defined(PG_DISABLE_64_BIT_ATOMICS) */ + +#endif /* defined(HAVE_ATOMICS) */ diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h new file mode 100644 index 0000000..6294162 --- /dev/null +++ b/src/include/port/atomics/generic-msvc.h @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + * + * generic-msvc.h + * Atomic operations support when using MSVC + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES: + * + * Documentation: + * * Interlocked Variable Access + * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx + * + * src/include/port/atomics/generic-msvc.h + * + *------------------------------------------------------------------------- + */ +#include <intrin.h> + +/* intentionally no include guards, should only be included by atomics.h */ +#ifndef INSIDE_ATOMICS_H +#error "should be included via atomics.h" +#endif + +#pragma intrinsic(_ReadWriteBarrier) +#define pg_compiler_barrier_impl() _ReadWriteBarrier() + +#ifndef pg_memory_barrier_impl +#define pg_memory_barrier_impl() MemoryBarrier() +#endif + +#if defined(HAVE_ATOMICS) + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct __declspec(align(8)) pg_atomic_uint64 +{ + volatile uint64 value; +} pg_atomic_uint64; + + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + current = InterlockedCompareExchange(&ptr->value, newval, *expected); + ret = current == *expected; + *expected = current; + return ret; +} + +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +static inline uint32 +pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + return InterlockedExchangeAdd(&ptr->value, add_); +} + +/* + * The non-intrinsics versions are only available in vista upwards, so use the + * intrinsic version. Only supported on >486, but we require XP as a minimum + * baseline, which doesn't support the 486, so we don't need to add checks for + * that case. + */ +#pragma intrinsic(_InterlockedCompareExchange64) + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + bool ret; + uint64 current; + current = _InterlockedCompareExchange64(&ptr->value, newval, *expected); + ret = current == *expected; + *expected = current; + return ret; +} + +/* Only implemented on itanium and 64bit builds */ +#ifdef _WIN64 +#pragma intrinsic(_InterlockedExchangeAdd64) + +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +static inline uint64 +pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + return _InterlockedExchangeAdd64(&ptr->value, add_); +} +#endif /* _WIN64 */ + +#endif /* HAVE_ATOMICS */ diff --git a/src/include/port/atomics/generic-sunpro.h b/src/include/port/atomics/generic-sunpro.h new file mode 100644 index 0000000..da1f8f1 --- /dev/null +++ b/src/include/port/atomics/generic-sunpro.h @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------- + * + * generic-sunpro.h + * Atomic operations for solaris' CC + * + * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group + * + * NOTES: + * + * Documentation: + * * manpage for atomic_cas(3C) + * http://www.unix.com/man-page/opensolaris/3c/atomic_cas/ + * http://docs.oracle.com/cd/E23824_01/html/821-1465/atomic-cas-3c.html + * + * src/include/port/atomics/generic-sunpro.h + * + * ------------------------------------------------------------------------- + */ + +#if defined(HAVE_ATOMICS) + +#ifdef HAVE_MBARRIER_H +#include <mbarrier.h> + +#define pg_compiler_barrier_impl() __compiler_barrier() + +#ifndef pg_memory_barrier_impl +/* + * Despite the name this is actually a full barrier. Expanding to mfence/ + * membar #StoreStore | #LoadStore | #StoreLoad | #LoadLoad on x86/sparc + * respectively. + */ +# define pg_memory_barrier_impl() __machine_rw_barrier() +#endif +#ifndef pg_read_barrier_impl +# define pg_read_barrier_impl() __machine_r_barrier() +#endif +#ifndef pg_write_barrier_impl +# define pg_write_barrier_impl() __machine_w_barrier() +#endif + +#endif /* HAVE_MBARRIER_H */ + +/* Older versions of the compiler don't have atomic.h... */ +#ifdef HAVE_ATOMIC_H + +#include <atomic.h> + +#define PG_HAVE_ATOMIC_U32_SUPPORT +typedef struct pg_atomic_uint32 +{ + volatile uint32 value; +} pg_atomic_uint32; + +#define PG_HAVE_ATOMIC_U64_SUPPORT +typedef struct pg_atomic_uint64 +{ + /* + * Syntax to enforce variable alignment should be supported by versions + * supporting atomic.h, but it's hard to find accurate documentation. If + * it proves to be a problem, we'll have to add more version checks for 64 + * bit support. + */ + volatile uint64 value pg_attribute_aligned(8); +} pg_atomic_uint64; + +#endif /* HAVE_ATOMIC_H */ + +#endif /* defined(HAVE_ATOMICS) */ + + +#if defined(HAVE_ATOMICS) + +#ifdef HAVE_ATOMIC_H + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32 +static inline bool +pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, + uint32 *expected, uint32 newval) +{ + bool ret; + uint32 current; + + current = atomic_cas_32(&ptr->value, *expected, newval); + ret = current == *expected; + *expected = current; + return ret; +} + +#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64 +static inline bool +pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, + uint64 *expected, uint64 newval) +{ + bool ret; + uint64 current; + + current = atomic_cas_64(&ptr->value, *expected, newval); + ret = current == *expected; + *expected = current; + return ret; +} + +#endif /* HAVE_ATOMIC_H */ + +#endif /* defined(HAVE_ATOMICS) */ diff --git a/src/include/port/atomics/generic.h b/src/include/port/atomics/generic.h new file mode 100644 index 0000000..a1f2456 --- /dev/null +++ b/src/include/port/atomics/generic.h @@ -0,0 +1,401 @@ +/*------------------------------------------------------------------------- + * + * generic.h + * Implement higher level operations based on some lower level atomic + * operations. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/atomics/generic.h + * + *------------------------------------------------------------------------- + */ + +/* intentionally no include guards, should only be included by atomics.h */ +#ifndef INSIDE_ATOMICS_H +# error "should be included via atomics.h" +#endif + +/* + * If read or write barriers are undefined, we upgrade them to full memory + * barriers. + */ +#if !defined(pg_read_barrier_impl) +# define pg_read_barrier_impl pg_memory_barrier_impl +#endif +#if !defined(pg_write_barrier_impl) +# define pg_write_barrier_impl pg_memory_barrier_impl +#endif + +#ifndef PG_HAVE_SPIN_DELAY +#define PG_HAVE_SPIN_DELAY +#define pg_spin_delay_impl() ((void)0) +#endif + + +/* provide fallback */ +#if !defined(PG_HAVE_ATOMIC_FLAG_SUPPORT) && defined(PG_HAVE_ATOMIC_U32_SUPPORT) +#define PG_HAVE_ATOMIC_FLAG_SUPPORT +typedef pg_atomic_uint32 pg_atomic_flag; +#endif + +#ifndef PG_HAVE_ATOMIC_READ_U32 +#define PG_HAVE_ATOMIC_READ_U32 +static inline uint32 +pg_atomic_read_u32_impl(volatile pg_atomic_uint32 *ptr) +{ + return ptr->value; +} +#endif + +#ifndef PG_HAVE_ATOMIC_WRITE_U32 +#define PG_HAVE_ATOMIC_WRITE_U32 +static inline void +pg_atomic_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + ptr->value = val; +} +#endif + +#ifndef PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32 +#define PG_HAVE_ATOMIC_UNLOCKED_WRITE_U32 +static inline void +pg_atomic_unlocked_write_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val) +{ + ptr->value = val; +} +#endif + +/* + * provide fallback for test_and_set using atomic_exchange if available + */ +#if !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_EXCHANGE_U32) + +#define PG_HAVE_ATOMIC_INIT_FLAG +static inline void +pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr) +{ + pg_atomic_write_u32_impl(ptr, 0); +} + +#define PG_HAVE_ATOMIC_TEST_SET_FLAG +static inline bool +pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr) +{ + return pg_atomic_exchange_u32_impl(ptr, &value, 1) == 0; +} + +#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG +static inline bool +pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr) +{ + return pg_atomic_read_u32_impl(ptr) == 0; +} + + +#define PG_HAVE_ATOMIC_CLEAR_FLAG +static inline void +pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr) +{ + /* XXX: release semantics suffice? */ + pg_memory_barrier_impl(); + pg_atomic_write_u32_impl(ptr, 0); +} + +/* + * provide fallback for test_and_set using atomic_compare_exchange if + * available. + */ +#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) + +#define PG_HAVE_ATOMIC_INIT_FLAG +static inline void +pg_atomic_init_flag_impl(volatile pg_atomic_flag *ptr) +{ + pg_atomic_write_u32_impl(ptr, 0); +} + +#define PG_HAVE_ATOMIC_TEST_SET_FLAG +static inline bool +pg_atomic_test_set_flag_impl(volatile pg_atomic_flag *ptr) +{ + uint32 value = 0; + return pg_atomic_compare_exchange_u32_impl(ptr, &value, 1); +} + +#define PG_HAVE_ATOMIC_UNLOCKED_TEST_FLAG +static inline bool +pg_atomic_unlocked_test_flag_impl(volatile pg_atomic_flag *ptr) +{ + return pg_atomic_read_u32_impl(ptr) == 0; +} + +#define PG_HAVE_ATOMIC_CLEAR_FLAG +static inline void +pg_atomic_clear_flag_impl(volatile pg_atomic_flag *ptr) +{ + /* + * Use a memory barrier + plain write if we have a native memory + * barrier. But don't do so if memory barriers use spinlocks - that'd lead + * to circularity if flags are used to implement spinlocks. + */ +#ifndef PG_HAVE_MEMORY_BARRIER_EMULATION + /* XXX: release semantics suffice? */ + pg_memory_barrier_impl(); + pg_atomic_write_u32_impl(ptr, 0); +#else + uint32 value = 1; + pg_atomic_compare_exchange_u32_impl(ptr, &value, 0); +#endif +} + +#elif !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) +# error "No pg_atomic_test_and_set provided" +#endif /* !defined(PG_HAVE_ATOMIC_TEST_SET_FLAG) */ + + +#ifndef PG_HAVE_ATOMIC_INIT_U32 +#define PG_HAVE_ATOMIC_INIT_U32 +static inline void +pg_atomic_init_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 val_) +{ + ptr->value = val_; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) +#define PG_HAVE_ATOMIC_EXCHANGE_U32 +static inline uint32 +pg_atomic_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 xchg_) +{ + uint32 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, xchg_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) +#define PG_HAVE_ATOMIC_FETCH_ADD_U32 +static inline uint32 +pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + uint32 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old + add_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) +#define PG_HAVE_ATOMIC_FETCH_SUB_U32 +static inline uint32 +pg_atomic_fetch_sub_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_) +{ + return pg_atomic_fetch_add_u32_impl(ptr, -sub_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) +#define PG_HAVE_ATOMIC_FETCH_AND_U32 +static inline uint32 +pg_atomic_fetch_and_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 and_) +{ + uint32 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old & and_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U32) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32) +#define PG_HAVE_ATOMIC_FETCH_OR_U32 +static inline uint32 +pg_atomic_fetch_or_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 or_) +{ + uint32 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u32_impl(ptr, &old, old | or_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U32) +#define PG_HAVE_ATOMIC_ADD_FETCH_U32 +static inline uint32 +pg_atomic_add_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_) +{ + return pg_atomic_fetch_add_u32_impl(ptr, add_) + add_; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U32) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U32) +#define PG_HAVE_ATOMIC_SUB_FETCH_U32 +static inline uint32 +pg_atomic_sub_fetch_u32_impl(volatile pg_atomic_uint32 *ptr, int32 sub_) +{ + return pg_atomic_fetch_sub_u32_impl(ptr, sub_) - sub_; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_EXCHANGE_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) +#define PG_HAVE_ATOMIC_EXCHANGE_U64 +static inline uint64 +pg_atomic_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 xchg_) +{ + uint64 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, xchg_)) + /* skip */; + return old; +} +#endif + +#ifndef PG_HAVE_ATOMIC_WRITE_U64 +#define PG_HAVE_ATOMIC_WRITE_U64 + +#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \ + !defined(PG_HAVE_ATOMIC_U64_SIMULATION) + +static inline void +pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val) +{ + /* + * On this platform aligned 64bit writes are guaranteed to be atomic, + * except if using the fallback implementation, where can't guarantee the + * required alignment. + */ + AssertPointerAlignment(ptr, 8); + ptr->value = val; +} + +#else + +static inline void +pg_atomic_write_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val) +{ + /* + * 64 bit writes aren't safe on all platforms. In the generic + * implementation implement them as an atomic exchange. + */ + pg_atomic_exchange_u64_impl(ptr, val); +} + +#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */ +#endif /* PG_HAVE_ATOMIC_WRITE_U64 */ + +#ifndef PG_HAVE_ATOMIC_READ_U64 +#define PG_HAVE_ATOMIC_READ_U64 + +#if defined(PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY) && \ + !defined(PG_HAVE_ATOMIC_U64_SIMULATION) + +static inline uint64 +pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr) +{ + /* + * On this platform aligned 64-bit reads are guaranteed to be atomic. + */ + AssertPointerAlignment(ptr, 8); + return ptr->value; +} + +#else + +static inline uint64 +pg_atomic_read_u64_impl(volatile pg_atomic_uint64 *ptr) +{ + uint64 old = 0; + + /* + * 64-bit reads aren't atomic on all platforms. In the generic + * implementation implement them as a compare/exchange with 0. That'll + * fail or succeed, but always return the old value. Possibly might store + * a 0, but only if the previous value also was a 0 - i.e. harmless. + */ + pg_atomic_compare_exchange_u64_impl(ptr, &old, 0); + + return old; +} +#endif /* PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY && !PG_HAVE_ATOMIC_U64_SIMULATION */ +#endif /* PG_HAVE_ATOMIC_READ_U64 */ + +#ifndef PG_HAVE_ATOMIC_INIT_U64 +#define PG_HAVE_ATOMIC_INIT_U64 +static inline void +pg_atomic_init_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 val_) +{ + ptr->value = val_; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) +#define PG_HAVE_ATOMIC_FETCH_ADD_U64 +static inline uint64 +pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + uint64 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old + add_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) +#define PG_HAVE_ATOMIC_FETCH_SUB_U64 +static inline uint64 +pg_atomic_fetch_sub_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_) +{ + return pg_atomic_fetch_add_u64_impl(ptr, -sub_); +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_AND_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) +#define PG_HAVE_ATOMIC_FETCH_AND_U64 +static inline uint64 +pg_atomic_fetch_and_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 and_) +{ + uint64 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old & and_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_FETCH_OR_U64) && defined(PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64) +#define PG_HAVE_ATOMIC_FETCH_OR_U64 +static inline uint64 +pg_atomic_fetch_or_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 or_) +{ + uint64 old; + old = ptr->value; /* ok if read is not atomic */ + while (!pg_atomic_compare_exchange_u64_impl(ptr, &old, old | or_)) + /* skip */; + return old; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_ADD_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_ADD_U64) +#define PG_HAVE_ATOMIC_ADD_FETCH_U64 +static inline uint64 +pg_atomic_add_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_) +{ + return pg_atomic_fetch_add_u64_impl(ptr, add_) + add_; +} +#endif + +#if !defined(PG_HAVE_ATOMIC_SUB_FETCH_U64) && defined(PG_HAVE_ATOMIC_FETCH_SUB_U64) +#define PG_HAVE_ATOMIC_SUB_FETCH_U64 +static inline uint64 +pg_atomic_sub_fetch_u64_impl(volatile pg_atomic_uint64 *ptr, int64 sub_) +{ + return pg_atomic_fetch_sub_u64_impl(ptr, sub_) - sub_; +} +#endif diff --git a/src/include/port/cygwin.h b/src/include/port/cygwin.h new file mode 100644 index 0000000..44bf853 --- /dev/null +++ b/src/include/port/cygwin.h @@ -0,0 +1,23 @@ +/* src/include/port/cygwin.h */ + +/* + * Variables declared in the core backend and referenced by loadable + * modules need to be marked "dllimport" in the core build, but + * "dllexport" when the declaration is read in a loadable module. + * No special markings should be used when compiling frontend code. + */ +#ifndef FRONTEND +#ifdef BUILDING_DLL +#define PGDLLIMPORT __declspec (dllexport) +#else +#define PGDLLIMPORT __declspec (dllimport) +#endif +#endif + +/* + * Cygwin has a strtof() which is literally just (float)strtod(), which means + * we get misrounding _and_ silent over/underflow. Using our wrapper doesn't + * fix the misrounding but does fix the error checks, which cuts down on the + * number of test variant files needed. + */ +#define HAVE_BUGGY_STRTOF 1 diff --git a/src/include/port/darwin.h b/src/include/port/darwin.h new file mode 100644 index 0000000..15fb69d --- /dev/null +++ b/src/include/port/darwin.h @@ -0,0 +1,8 @@ +/* src/include/port/darwin.h */ + +#define __darwin__ 1 + +#if HAVE_DECL_F_FULLFSYNC /* not present before macOS 10.3 */ +#define HAVE_FSYNC_WRITETHROUGH + +#endif diff --git a/src/include/port/freebsd.h b/src/include/port/freebsd.h new file mode 100644 index 0000000..2e2e749 --- /dev/null +++ b/src/include/port/freebsd.h @@ -0,0 +1,10 @@ +/* src/include/port/freebsd.h */ + +/* + * Set the default wal_sync_method to fdatasync. xlogdefs.h's normal rules + * would prefer open_datasync on FreeBSD 13+, but that is not a good choice on + * many systems. + */ +#ifdef HAVE_FDATASYNC +#define PLATFORM_DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC +#endif diff --git a/src/include/port/hpux.h b/src/include/port/hpux.h new file mode 100644 index 0000000..4d1dcea --- /dev/null +++ b/src/include/port/hpux.h @@ -0,0 +1,3 @@ +/* src/include/port/hpux.h */ + +/* nothing needed */ diff --git a/src/include/port/linux.h b/src/include/port/linux.h new file mode 100644 index 0000000..7a6e46c --- /dev/null +++ b/src/include/port/linux.h @@ -0,0 +1,22 @@ +/* src/include/port/linux.h */ + +/* + * As of July 2007, all known versions of the Linux kernel will sometimes + * return EIDRM for a shmctl() operation when EINVAL is correct (it happens + * when the low-order 15 bits of the supplied shm ID match the slot number + * assigned to a newer shmem segment). We deal with this by assuming that + * EIDRM means EINVAL in PGSharedMemoryIsInUse(). This is reasonably safe + * since in fact Linux has no excuse for ever returning EIDRM; it doesn't + * track removed segments in a way that would allow distinguishing them from + * private ones. But someday that code might get upgraded, and we'd have + * to have a kernel version test here. + */ +#define HAVE_LINUX_EIDRM_BUG + +/* + * Set the default wal_sync_method to fdatasync. With recent Linux versions, + * xlogdefs.h's normal rules will prefer open_datasync, which (a) doesn't + * perform better and (b) causes outright failures on ext4 data=journal + * filesystems, because those don't support O_DIRECT. + */ +#define PLATFORM_DEFAULT_SYNC_METHOD SYNC_METHOD_FDATASYNC diff --git a/src/include/port/netbsd.h b/src/include/port/netbsd.h new file mode 100644 index 0000000..590233f --- /dev/null +++ b/src/include/port/netbsd.h @@ -0,0 +1 @@ +/* src/include/port/netbsd.h */ diff --git a/src/include/port/openbsd.h b/src/include/port/openbsd.h new file mode 100644 index 0000000..395319b --- /dev/null +++ b/src/include/port/openbsd.h @@ -0,0 +1 @@ +/* src/include/port/openbsd.h */ diff --git a/src/include/port/pg_bitutils.h b/src/include/port/pg_bitutils.h new file mode 100644 index 0000000..04e58cd --- /dev/null +++ b/src/include/port/pg_bitutils.h @@ -0,0 +1,302 @@ +/*------------------------------------------------------------------------- + * + * pg_bitutils.h + * Miscellaneous functions for bit-wise operations. + * + * + * Copyright (c) 2019-2022, PostgreSQL Global Development Group + * + * src/include/port/pg_bitutils.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_BITUTILS_H +#define PG_BITUTILS_H + +extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]; +extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256]; +extern PGDLLIMPORT const uint8 pg_number_of_ones[256]; + +/* + * pg_leftmost_one_pos32 + * Returns the position of the most significant set bit in "word", + * measured from the least significant bit. word must not be 0. + */ +static inline int +pg_leftmost_one_pos32(uint32 word) +{ +#ifdef HAVE__BUILTIN_CLZ + Assert(word != 0); + + return 31 - __builtin_clz(word); +#else + int shift = 32 - 8; + + Assert(word != 0); + + while ((word >> shift) == 0) + shift -= 8; + + return shift + pg_leftmost_one_pos[(word >> shift) & 255]; +#endif /* HAVE__BUILTIN_CLZ */ +} + +/* + * pg_leftmost_one_pos64 + * As above, but for a 64-bit word. + */ +static inline int +pg_leftmost_one_pos64(uint64 word) +{ +#ifdef HAVE__BUILTIN_CLZ + Assert(word != 0); + +#if defined(HAVE_LONG_INT_64) + return 63 - __builtin_clzl(word); +#elif defined(HAVE_LONG_LONG_INT_64) + return 63 - __builtin_clzll(word); +#else +#error must have a working 64-bit integer datatype +#endif +#else /* !HAVE__BUILTIN_CLZ */ + int shift = 64 - 8; + + Assert(word != 0); + + while ((word >> shift) == 0) + shift -= 8; + + return shift + pg_leftmost_one_pos[(word >> shift) & 255]; +#endif /* HAVE__BUILTIN_CLZ */ +} + +/* + * pg_rightmost_one_pos32 + * Returns the position of the least significant set bit in "word", + * measured from the least significant bit. word must not be 0. + */ +static inline int +pg_rightmost_one_pos32(uint32 word) +{ +#ifdef HAVE__BUILTIN_CTZ + Assert(word != 0); + + return __builtin_ctz(word); +#else + int result = 0; + + Assert(word != 0); + + while ((word & 255) == 0) + { + word >>= 8; + result += 8; + } + result += pg_rightmost_one_pos[word & 255]; + return result; +#endif /* HAVE__BUILTIN_CTZ */ +} + +/* + * pg_rightmost_one_pos64 + * As above, but for a 64-bit word. + */ +static inline int +pg_rightmost_one_pos64(uint64 word) +{ +#ifdef HAVE__BUILTIN_CTZ + Assert(word != 0); + +#if defined(HAVE_LONG_INT_64) + return __builtin_ctzl(word); +#elif defined(HAVE_LONG_LONG_INT_64) + return __builtin_ctzll(word); +#else +#error must have a working 64-bit integer datatype +#endif +#else /* !HAVE__BUILTIN_CTZ */ + int result = 0; + + Assert(word != 0); + + while ((word & 255) == 0) + { + word >>= 8; + result += 8; + } + result += pg_rightmost_one_pos[word & 255]; + return result; +#endif /* HAVE__BUILTIN_CTZ */ +} + +/* + * pg_nextpower2_32 + * Returns the next higher power of 2 above 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT32_MAX / 2 + 1. + */ +static inline uint32 +pg_nextpower2_32(uint32 num) +{ + Assert(num > 0 && num <= PG_UINT32_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint32) 1) << (pg_leftmost_one_pos32(num) + 1); +} + +/* + * pg_nextpower2_64 + * Returns the next higher power of 2 above 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0 or be above PG_UINT64_MAX / 2 + 1. + */ +static inline uint64 +pg_nextpower2_64(uint64 num) +{ + Assert(num > 0 && num <= PG_UINT64_MAX / 2 + 1); + + /* + * A power 2 number has only 1 bit set. Subtracting 1 from such a number + * will turn on all previous bits resulting in no common bits being set + * between num and num-1. + */ + if ((num & (num - 1)) == 0) + return num; /* already power 2 */ + + return ((uint64) 1) << (pg_leftmost_one_pos64(num) + 1); +} + +/* + * pg_nextpower2_size_t + * Returns the next higher power of 2 above 'num', for a size_t input. + */ +#if SIZEOF_SIZE_T == 4 +#define pg_nextpower2_size_t(num) pg_nextpower2_32(num) +#else +#define pg_nextpower2_size_t(num) pg_nextpower2_64(num) +#endif + +/* + * pg_prevpower2_32 + * Returns the next lower power of 2 below 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0. + */ +static inline uint32 +pg_prevpower2_32(uint32 num) +{ + return ((uint32) 1) << pg_leftmost_one_pos32(num); +} + +/* + * pg_prevpower2_64 + * Returns the next lower power of 2 below 'num', or 'num' if it's + * already a power of 2. + * + * 'num' mustn't be 0. + */ +static inline uint64 +pg_prevpower2_64(uint64 num) +{ + return ((uint64) 1) << pg_leftmost_one_pos64(num); +} + +/* + * pg_prevpower2_size_t + * Returns the next lower power of 2 below 'num', for a size_t input. + */ +#if SIZEOF_SIZE_T == 4 +#define pg_prevpower2_size_t(num) pg_prevpower2_32(num) +#else +#define pg_prevpower2_size_t(num) pg_prevpower2_64(num) +#endif + +/* + * pg_ceil_log2_32 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint32 +pg_ceil_log2_32(uint32 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos32(num - 1) + 1; +} + +/* + * pg_ceil_log2_64 + * Returns equivalent of ceil(log2(num)) + */ +static inline uint64 +pg_ceil_log2_64(uint64 num) +{ + if (num < 2) + return 0; + else + return pg_leftmost_one_pos64(num - 1) + 1; +} + +/* + * With MSVC on x86_64 builds, try using native popcnt instructions via the + * __popcnt and __popcnt64 intrinsics. These don't work the same as GCC's + * __builtin_popcount* intrinsic functions as they always emit popcnt + * instructions. + */ +#if defined(_MSC_VER) && defined(_M_AMD64) +#define HAVE_X86_64_POPCNTQ +#endif + +/* + * On x86_64, we can use the hardware popcount instruction, but only if + * we can verify that the CPU supports it via the cpuid instruction. + * + * Otherwise, we fall back to a hand-rolled implementation. + */ +#ifdef HAVE_X86_64_POPCNTQ +#if defined(HAVE__GET_CPUID) || defined(HAVE__CPUID) +#define TRY_POPCNT_FAST 1 +#endif +#endif + +#ifdef TRY_POPCNT_FAST +/* Attempt to use the POPCNT instruction, but perform a runtime check first */ +extern int (*pg_popcount32) (uint32 word); +extern int (*pg_popcount64) (uint64 word); + +#else +/* Use a portable implementation -- no need for a function pointer. */ +extern int pg_popcount32(uint32 word); +extern int pg_popcount64(uint64 word); + +#endif /* TRY_POPCNT_FAST */ + +/* Count the number of one-bits in a byte array */ +extern uint64 pg_popcount(const char *buf, int bytes); + +/* + * Rotate the bits of "word" to the right/left by n bits. + */ +static inline uint32 +pg_rotate_right32(uint32 word, int n) +{ + return (word >> n) | (word << (32 - n)); +} + +static inline uint32 +pg_rotate_left32(uint32 word, int n) +{ + return (word << n) | (word >> (32 - n)); +} + +#endif /* PG_BITUTILS_H */ diff --git a/src/include/port/pg_bswap.h b/src/include/port/pg_bswap.h new file mode 100644 index 0000000..4033d2b --- /dev/null +++ b/src/include/port/pg_bswap.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------- + * + * pg_bswap.h + * Byte swapping. + * + * Macros for reversing the byte order of 16, 32 and 64-bit unsigned integers. + * For example, 0xAABBCCDD becomes 0xDDCCBBAA. These are just wrappers for + * built-in functions provided by the compiler where support exists. + * + * Note that all of these functions accept unsigned integers as arguments and + * return the same. Use caution when using these wrapper macros with signed + * integers. + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * src/include/port/pg_bswap.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_BSWAP_H +#define PG_BSWAP_H + + +/* + * In all supported versions msvc provides _byteswap_* functions in stdlib.h, + * already included by c.h. + */ + + +/* implementation of uint16 pg_bswap16(uint16) */ +#if defined(HAVE__BUILTIN_BSWAP16) + +#define pg_bswap16(x) __builtin_bswap16(x) + +#elif defined(_MSC_VER) + +#define pg_bswap16(x) _byteswap_ushort(x) + +#else + +static inline uint16 +pg_bswap16(uint16 x) +{ + return + ((x << 8) & 0xff00) | + ((x >> 8) & 0x00ff); +} + +#endif /* HAVE__BUILTIN_BSWAP16 */ + + +/* implementation of uint32 pg_bswap32(uint32) */ +#if defined(HAVE__BUILTIN_BSWAP32) + +#define pg_bswap32(x) __builtin_bswap32(x) + +#elif defined(_MSC_VER) + +#define pg_bswap32(x) _byteswap_ulong(x) + +#else + +static inline uint32 +pg_bswap32(uint32 x) +{ + return + ((x << 24) & 0xff000000) | + ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | + ((x >> 24) & 0x000000ff); +} + +#endif /* HAVE__BUILTIN_BSWAP32 */ + + +/* implementation of uint64 pg_bswap64(uint64) */ +#if defined(HAVE__BUILTIN_BSWAP64) + +#define pg_bswap64(x) __builtin_bswap64(x) + + +#elif defined(_MSC_VER) + +#define pg_bswap64(x) _byteswap_uint64(x) + +#else + +static inline uint64 +pg_bswap64(uint64 x) +{ + return + ((x << 56) & UINT64CONST(0xff00000000000000)) | + ((x << 40) & UINT64CONST(0x00ff000000000000)) | + ((x << 24) & UINT64CONST(0x0000ff0000000000)) | + ((x << 8) & UINT64CONST(0x000000ff00000000)) | + ((x >> 8) & UINT64CONST(0x00000000ff000000)) | + ((x >> 24) & UINT64CONST(0x0000000000ff0000)) | + ((x >> 40) & UINT64CONST(0x000000000000ff00)) | + ((x >> 56) & UINT64CONST(0x00000000000000ff)); +} +#endif /* HAVE__BUILTIN_BSWAP64 */ + + +/* + * Portable and fast equivalents for ntohs, ntohl, htons, htonl, + * additionally extended to 64 bits. + */ +#ifdef WORDS_BIGENDIAN + +#define pg_hton16(x) (x) +#define pg_hton32(x) (x) +#define pg_hton64(x) (x) + +#define pg_ntoh16(x) (x) +#define pg_ntoh32(x) (x) +#define pg_ntoh64(x) (x) + +#else + +#define pg_hton16(x) pg_bswap16(x) +#define pg_hton32(x) pg_bswap32(x) +#define pg_hton64(x) pg_bswap64(x) + +#define pg_ntoh16(x) pg_bswap16(x) +#define pg_ntoh32(x) pg_bswap32(x) +#define pg_ntoh64(x) pg_bswap64(x) + +#endif /* WORDS_BIGENDIAN */ + + +/* + * Rearrange the bytes of a Datum from big-endian order into the native byte + * order. On big-endian machines, this does nothing at all. Note that the C + * type Datum is an unsigned integer type on all platforms. + * + * One possible application of the DatumBigEndianToNative() macro is to make + * bitwise comparisons cheaper. A simple 3-way comparison of Datums + * transformed by the macro (based on native, unsigned comparisons) will return + * the same result as a memcmp() of the corresponding original Datums, but can + * be much cheaper. It's generally safe to do this on big-endian systems + * without any special transformation occurring first. + * + * If SIZEOF_DATUM is not defined, then postgres.h wasn't included and these + * macros probably shouldn't be used, so we define nothing. Note that + * SIZEOF_DATUM == 8 would evaluate as 0 == 8 in that case, potentially + * leading to the wrong implementation being selected and confusing errors, so + * defining nothing is safest. + */ +#ifdef SIZEOF_DATUM +#ifdef WORDS_BIGENDIAN +#define DatumBigEndianToNative(x) (x) +#else /* !WORDS_BIGENDIAN */ +#if SIZEOF_DATUM == 8 +#define DatumBigEndianToNative(x) pg_bswap64(x) +#else /* SIZEOF_DATUM != 8 */ +#define DatumBigEndianToNative(x) pg_bswap32(x) +#endif /* SIZEOF_DATUM == 8 */ +#endif /* WORDS_BIGENDIAN */ +#endif /* SIZEOF_DATUM */ + +#endif /* PG_BSWAP_H */ diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h new file mode 100644 index 0000000..d766865 --- /dev/null +++ b/src/include/port/pg_crc32c.h @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + * + * pg_crc32c.h + * Routines for computing CRC-32C checksums. + * + * The speed of CRC-32C calculation has a big impact on performance, so we + * jump through some hoops to get the best implementation for each + * platform. Some CPU architectures have special instructions for speeding + * up CRC calculations (e.g. Intel SSE 4.2), on other platforms we use the + * Slicing-by-8 algorithm which uses lookup tables. + * + * The public interface consists of four macros: + * + * INIT_CRC32C(crc) + * Initialize a CRC accumulator + * + * COMP_CRC32C(crc, data, len) + * Accumulate some (more) bytes into a CRC + * + * FIN_CRC32C(crc) + * Finish a CRC calculation + * + * EQ_CRC32C(c1, c2) + * Check for equality of two CRCs. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/pg_crc32c.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_CRC32C_H +#define PG_CRC32C_H + +#include "port/pg_bswap.h" + +typedef uint32 pg_crc32c; + +/* The INIT and EQ macros are the same for all implementations. */ +#define INIT_CRC32C(crc) ((crc) = 0xFFFFFFFF) +#define EQ_CRC32C(c1, c2) ((c1) == (c2)) + +#if defined(USE_SSE42_CRC32C) +/* Use Intel SSE4.2 instructions. */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_sse42((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len); + +#elif defined(USE_ARMV8_CRC32C) +/* Use ARMv8 CRC Extension instructions. */ + +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_armv8((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len); + +#elif defined(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK) || defined(USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK) + +/* + * Use Intel SSE 4.2 or ARMv8 instructions, but perform a runtime check first + * to check that they are available. + */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c((crc), (data), (len))) +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) + +extern pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len); +extern pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len); + +#ifdef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK +extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len); +#endif +#ifdef USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK +extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len); +#endif + +#else +/* + * Use slicing-by-8 algorithm. + * + * On big-endian systems, the intermediate value is kept in reverse byte + * order, to avoid byte-swapping during the calculation. FIN_CRC32C reverses + * the bytes to the final order. + */ +#define COMP_CRC32C(crc, data, len) \ + ((crc) = pg_comp_crc32c_sb8((crc), (data), (len))) +#ifdef WORDS_BIGENDIAN +#define FIN_CRC32C(crc) ((crc) = pg_bswap32(crc) ^ 0xFFFFFFFF) +#else +#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF) +#endif + +extern pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len); + +#endif + +#endif /* PG_CRC32C_H */ diff --git a/src/include/port/pg_iovec.h b/src/include/port/pg_iovec.h new file mode 100644 index 0000000..f0b1a71 --- /dev/null +++ b/src/include/port/pg_iovec.h @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * pg_iovec.h + * Header for vectored I/O functions, to use in place of <sys/uio.h>. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/pg_iovec.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_IOVEC_H +#define PG_IOVEC_H + +#include <limits.h> + +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +/* If <sys/uio.h> is missing, define our own POSIX-compatible iovec struct. */ +#ifndef HAVE_SYS_UIO_H +struct iovec +{ + void *iov_base; + size_t iov_len; +}; +#endif + +/* + * If <limits.h> didn't define IOV_MAX, define our own. POSIX requires at + * least 16. + */ +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + +/* Define a reasonable maximum that is safe to use on the stack. */ +#define PG_IOV_MAX Min(IOV_MAX, 32) + +#if HAVE_DECL_PREADV +#define pg_preadv preadv +#else +extern ssize_t pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +#if HAVE_DECL_PWRITEV +#define pg_pwritev pwritev +#else +extern ssize_t pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +#endif + +#endif /* PG_IOVEC_H */ diff --git a/src/include/port/pg_pthread.h b/src/include/port/pg_pthread.h new file mode 100644 index 0000000..d102ce9 --- /dev/null +++ b/src/include/port/pg_pthread.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * Declarations for missing POSIX thread components. + * + * Currently this supplies an implementation of pthread_barrier_t for the + * benefit of macOS, which lacks it. These declarations are not in port.h, + * because that'd require <pthread.h> to be included by every translation + * unit. + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_PTHREAD_H +#define PG_PTHREAD_H + +#include <pthread.h> + +#ifndef HAVE_PTHREAD_BARRIER_WAIT + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) +#endif + +typedef struct pg_pthread_barrier +{ + bool sense; /* we only need a one bit phase */ + int count; /* number of threads expected */ + int arrived; /* number of threads that have arrived */ + pthread_mutex_t mutex; + pthread_cond_t cond; +} pthread_barrier_t; + +extern int pthread_barrier_init(pthread_barrier_t *barrier, + const void *attr, + int count); +extern int pthread_barrier_wait(pthread_barrier_t *barrier); +extern int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif + +#endif diff --git a/src/include/port/solaris.h b/src/include/port/solaris.h new file mode 100644 index 0000000..e63a3bd --- /dev/null +++ b/src/include/port/solaris.h @@ -0,0 +1,26 @@ +/* src/include/port/solaris.h */ + +/* + * Sort this out for all operating systems some time. The __xxx + * symbols are defined on both GCC and Solaris CC, although GCC + * doesn't document them. The __xxx__ symbols are only on GCC. + */ +#if defined(__i386) && !defined(__i386__) +#define __i386__ +#endif + +#if defined(__amd64) && !defined(__amd64__) +#define __amd64__ +#endif + +#if defined(__x86_64) && !defined(__x86_64__) +#define __x86_64__ +#endif + +#if defined(__sparc) && !defined(__sparc__) +#define __sparc__ +#endif + +#if defined(__i386__) +#include <sys/isa_defs.h> +#endif diff --git a/src/include/port/win32.h b/src/include/port/win32.h new file mode 100644 index 0000000..c6213c7 --- /dev/null +++ b/src/include/port/win32.h @@ -0,0 +1,79 @@ +/* src/include/port/win32.h */ + +/* + * We always rely on the WIN32 macro being set by our build system, + * but _WIN32 is the compiler pre-defined macro. So make sure we define + * WIN32 whenever _WIN32 is set, to facilitate standalone building. + */ +#if defined(_WIN32) && !defined(WIN32) +#define WIN32 +#endif + +/* + * Make sure _WIN32_WINNT has the minimum required value. + * Leave a higher value in place. When building with at least Visual + * Studio 2015 the minimum requirement is Windows Vista (0x0600) to + * get support for GetLocaleInfoEx() with locales. For everything else + * the minimum version is Windows XP (0x0501). + */ +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#define MIN_WINNT 0x0600 +#else +#define MIN_WINNT 0x0501 +#endif + +#if defined(_WIN32_WINNT) && _WIN32_WINNT < MIN_WINNT +#undef _WIN32_WINNT +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT MIN_WINNT +#endif + +/* + * We need to prevent <crtdefs.h> from defining a symbol conflicting with + * our errcode() function. Since it's likely to get included by standard + * system headers, pre-emptively include it now. + */ +#if defined(_MSC_VER) || defined(HAVE_CRTDEFS_H) +#define errcode __msvc_errcode +#include <crtdefs.h> +#undef errcode +#endif + +/* + * defines for dynamic linking on Win32 platform + */ + +/* + * Variables declared in the core backend and referenced by loadable + * modules need to be marked "dllimport" in the core build, but + * "dllexport" when the declaration is read in a loadable module. + * No special markings should be used when compiling frontend code. + */ +#ifndef FRONTEND +#ifdef BUILDING_DLL +#define PGDLLIMPORT __declspec (dllexport) +#else +#define PGDLLIMPORT __declspec (dllimport) +#endif +#endif + +/* + * Under MSVC, functions exported by a loadable module must be marked + * "dllexport". Other compilers don't need that. + */ +#ifdef _MSC_VER +#define PGDLLEXPORT __declspec (dllexport) +#endif + +/* + * Windows headers don't define this structure, but you can define it yourself + * to use the functionality. + */ +struct sockaddr_un +{ + unsigned short sun_family; + char sun_path[108]; +}; +#define HAVE_STRUCT_SOCKADDR_UN 1 diff --git a/src/include/port/win32/arpa/inet.h b/src/include/port/win32/arpa/inet.h new file mode 100644 index 0000000..ad18031 --- /dev/null +++ b/src/include/port/win32/arpa/inet.h @@ -0,0 +1,3 @@ +/* src/include/port/win32/arpa/inet.h */ + +#include <sys/socket.h> diff --git a/src/include/port/win32/dlfcn.h b/src/include/port/win32/dlfcn.h new file mode 100644 index 0000000..b6e43c0 --- /dev/null +++ b/src/include/port/win32/dlfcn.h @@ -0,0 +1 @@ +/* src/include/port/win32/dlfcn.h */ diff --git a/src/include/port/win32/grp.h b/src/include/port/win32/grp.h new file mode 100644 index 0000000..8b4f213 --- /dev/null +++ b/src/include/port/win32/grp.h @@ -0,0 +1 @@ +/* src/include/port/win32/grp.h */ diff --git a/src/include/port/win32/netdb.h b/src/include/port/win32/netdb.h new file mode 100644 index 0000000..ad0627e --- /dev/null +++ b/src/include/port/win32/netdb.h @@ -0,0 +1 @@ +/* src/include/port/win32/netdb.h */ diff --git a/src/include/port/win32/netinet/in.h b/src/include/port/win32/netinet/in.h new file mode 100644 index 0000000..a4e22f8 --- /dev/null +++ b/src/include/port/win32/netinet/in.h @@ -0,0 +1,3 @@ +/* src/include/port/win32/netinet/in.h */ + +#include <sys/socket.h> diff --git a/src/include/port/win32/pwd.h b/src/include/port/win32/pwd.h new file mode 100644 index 0000000..b8c7178 --- /dev/null +++ b/src/include/port/win32/pwd.h @@ -0,0 +1,3 @@ +/* + * src/include/port/win32/pwd.h + */ diff --git a/src/include/port/win32/sys/socket.h b/src/include/port/win32/sys/socket.h new file mode 100644 index 0000000..9b2cdf3 --- /dev/null +++ b/src/include/port/win32/sys/socket.h @@ -0,0 +1,33 @@ +/* + * src/include/port/win32/sys/socket.h + */ +#ifndef WIN32_SYS_SOCKET_H +#define WIN32_SYS_SOCKET_H + +/* + * Unfortunately, <wingdi.h> of VC++ also defines ERROR. + * To avoid the conflict, we include <windows.h> here and undefine ERROR + * immediately. + * + * Note: Don't include <wingdi.h> directly. It causes compile errors. + */ +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> + +#undef ERROR +#undef small + +/* Restore old ERROR value */ +#ifdef PGERROR +#define ERROR PGERROR +#endif + +/* + * we can't use the windows gai_strerror{AW} functions because + * they are defined inline in the MS header files. So we'll use our + * own + */ +#undef gai_strerror + +#endif /* WIN32_SYS_SOCKET_H */ diff --git a/src/include/port/win32/sys/wait.h b/src/include/port/win32/sys/wait.h new file mode 100644 index 0000000..eaeb566 --- /dev/null +++ b/src/include/port/win32/sys/wait.h @@ -0,0 +1,3 @@ +/* + * src/include/port/win32/sys/wait.h + */ diff --git a/src/include/port/win32_msvc/dirent.h b/src/include/port/win32_msvc/dirent.h new file mode 100644 index 0000000..62799db --- /dev/null +++ b/src/include/port/win32_msvc/dirent.h @@ -0,0 +1,34 @@ +/* + * Headers for port/dirent.c, win32 native implementation of dirent functions + * + * src/include/port/win32_msvc/dirent.h + */ + +#ifndef _WIN32VC_DIRENT_H +#define _WIN32VC_DIRENT_H +struct dirent +{ + long d_ino; + unsigned short d_reclen; + unsigned char d_type; + unsigned short d_namlen; + char d_name[MAX_PATH]; +}; + +typedef struct DIR DIR; + +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int closedir(DIR *); + +/* File types for 'd_type'. */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +#endif diff --git a/src/include/port/win32_msvc/sys/file.h b/src/include/port/win32_msvc/sys/file.h new file mode 100644 index 0000000..76be3e7 --- /dev/null +++ b/src/include/port/win32_msvc/sys/file.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/file.h */ diff --git a/src/include/port/win32_msvc/sys/param.h b/src/include/port/win32_msvc/sys/param.h new file mode 100644 index 0000000..160df3b --- /dev/null +++ b/src/include/port/win32_msvc/sys/param.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/param.h */ diff --git a/src/include/port/win32_msvc/sys/time.h b/src/include/port/win32_msvc/sys/time.h new file mode 100644 index 0000000..9d943ec --- /dev/null +++ b/src/include/port/win32_msvc/sys/time.h @@ -0,0 +1 @@ +/* src/include/port/win32_msvc/sys/time.h */ diff --git a/src/include/port/win32_msvc/unistd.h b/src/include/port/win32_msvc/unistd.h new file mode 100644 index 0000000..b7795ba --- /dev/null +++ b/src/include/port/win32_msvc/unistd.h @@ -0,0 +1,9 @@ +/* src/include/port/win32_msvc/unistd.h */ + +/* + * MSVC does not define these, nor does _fileno(stdin) etc reliably work + * (returns -1 if stdin/out/err are closed). + */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 diff --git a/src/include/port/win32_msvc/utime.h b/src/include/port/win32_msvc/utime.h new file mode 100644 index 0000000..c78e79c --- /dev/null +++ b/src/include/port/win32_msvc/utime.h @@ -0,0 +1,3 @@ +/* src/include/port/win32_msvc/utime.h */ + +#include <sys/utime.h> /* for non-unicode version */ diff --git a/src/include/port/win32_port.h b/src/include/port/win32_port.h new file mode 100644 index 0000000..d1e89f3 --- /dev/null +++ b/src/include/port/win32_port.h @@ -0,0 +1,559 @@ +/*------------------------------------------------------------------------- + * + * win32_port.h + * Windows-specific compatibility stuff. + * + * Note this is read in MinGW as well as native Windows builds, + * but not in Cygwin builds. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/win32_port.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_WIN32_PORT_H +#define PG_WIN32_PORT_H + +/* + * Always build with SSPI support. Keep it as a #define in case + * we want a switch to disable it sometime in the future. + */ +#define ENABLE_SSPI 1 + +/* undefine and redefine after #include */ +#undef mkdir + +#undef ERROR + +/* + * VS2013 and later issue warnings about using the old Winsock API, + * which we don't really want to hear about. + */ +#ifdef _MSC_VER +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +/* + * The MinGW64 headers choke if this is already defined - they + * define it themselves. + */ +#if !defined(__MINGW64_VERSION_MAJOR) || defined(_MSC_VER) +#define _WINSOCKAPI_ +#endif + +/* + * windows.h includes a lot of other headers, slowing down compilation + * significantly. WIN32_LEAN_AND_MEAN reduces that a bit. It'd be better to + * remove the include of windows.h (as well as indirect inclusions of it) from + * such a central place, but until then... + */ +#define WIN32_LEAN_AND_MEAN + +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#undef small +#include <process.h> +#include <signal.h> +#include <direct.h> +#undef near + +/* needed before sys/stat hacking below: */ +#define fstat microsoft_native_fstat +#define stat microsoft_native_stat +#include <sys/stat.h> +#undef fstat +#undef stat + +/* Must be here to avoid conflicting with prototype in windows.h */ +#define mkdir(a,b) mkdir(a) + +#define ftruncate(a,b) chsize(a,b) + +/* Windows doesn't have fsync() as such, use _commit() */ +#define fsync(fd) _commit(fd) + +/* + * For historical reasons, we allow setting wal_sync_method to + * fsync_writethrough on Windows, even though it's really identical to fsync + * (both code paths wind up at _commit()). + */ +#define HAVE_FSYNC_WRITETHROUGH +#define FSYNC_WRITETHROUGH_IS_FSYNC + +#define USES_WINSOCK + +/* + * IPC defines + */ +#undef HAVE_UNION_SEMUN +#define HAVE_UNION_SEMUN 1 + +#define IPC_RMID 256 +#define IPC_CREAT 512 +#define IPC_EXCL 1024 +#define IPC_PRIVATE 234564 +#define IPC_NOWAIT 2048 +#define IPC_STAT 4096 + +#define EACCESS 2048 +#ifndef EIDRM +#define EIDRM 4096 +#endif + +#define SETALL 8192 +#define GETNCNT 16384 +#define GETVAL 65536 +#define SETVAL 131072 +#define GETPID 262144 + + +/* + * Signal stuff + * + * For WIN32, there is no wait() call so there are no wait() macros + * to interpret the return value of system(). Instead, system() + * return values < 0x100 are used for exit() termination, and higher + * values are used to indicate non-exit() termination, which is + * similar to a unix-style signal exit (think SIGSEGV == + * STATUS_ACCESS_VIOLATION). Return values are broken up into groups: + * + * https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values + * + * NT_SUCCESS 0 - 0x3FFFFFFF + * NT_INFORMATION 0x40000000 - 0x7FFFFFFF + * NT_WARNING 0x80000000 - 0xBFFFFFFF + * NT_ERROR 0xC0000000 - 0xFFFFFFFF + * + * Effectively, we don't care on the severity of the return value from + * system(), we just need to know if it was because of exit() or generated + * by the system, and it seems values >= 0x100 are system-generated. + * See this URL for a list of WIN32 STATUS_* values: + * + * Wine (URL used in our error messages) - + * http://source.winehq.org/source/include/ntstatus.h + * Descriptions - + * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 + * + * The comprehensive exception list is included in ntstatus.h from the + * Windows Driver Kit (WDK). A subset of the list is also included in + * winnt.h from the Windows SDK. Defining WIN32_NO_STATUS before including + * windows.h helps to avoid any conflicts. + * + * Some day we might want to print descriptions for the most common + * exceptions, rather than printing an include file name. We could use + * RtlNtStatusToDosError() and pass to FormatMessage(), which can print + * the text of error values, but MinGW does not support + * RtlNtStatusToDosError(). + */ +#define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0) +#define WIFSIGNALED(w) (!WIFEXITED(w)) +#define WEXITSTATUS(w) (w) +#define WTERMSIG(w) (w) + +#define sigmask(sig) ( 1 << ((sig)-1) ) + +/* Signal function return values */ +#undef SIG_DFL +#undef SIG_ERR +#undef SIG_IGN +#define SIG_DFL ((pqsigfunc)0) +#define SIG_ERR ((pqsigfunc)-1) +#define SIG_IGN ((pqsigfunc)1) + +/* Some extra signals */ +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGABRT 22 /* Set to match W32 value -- not UNIX value */ +#define SIGKILL 9 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGWINCH 28 +#define SIGUSR1 30 +#define SIGUSR2 31 + +/* + * New versions of MinGW have gettimeofday() and also declare + * struct timezone to support it. + */ +#ifndef HAVE_GETTIMEOFDAY +struct timezone +{ + int tz_minuteswest; /* Minutes west of GMT. */ + int tz_dsttime; /* Nonzero if DST is ever in effect. */ +}; +#endif + +/* for setitimer in backend/port/win32/timer.c */ +#define ITIMER_REAL 0 +struct itimerval +{ + struct timeval it_interval; + struct timeval it_value; +}; + +int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); + +/* Convenience wrapper for GetFileType() */ +extern DWORD pgwin32_get_file_type(HANDLE hFile); + +/* + * WIN32 does not provide 64-bit off_t, but does provide the functions operating + * with 64-bit offsets. Also, fseek() might not give an error for unseekable + * streams, so harden that function with our version. + */ +#define pgoff_t __int64 + +#ifdef _MSC_VER +extern int _pgfseeko64(FILE *stream, pgoff_t offset, int origin); +extern pgoff_t _pgftello64(FILE *stream); +#define fseeko(stream, offset, origin) _pgfseeko64(stream, offset, origin) +#define ftello(stream) _pgftello64(stream) +#else +#ifndef fseeko +#define fseeko(stream, offset, origin) fseeko64(stream, offset, origin) +#endif +#ifndef ftello +#define ftello(stream) ftello64(stream) +#endif +#endif + +/* + * Win32 also doesn't have symlinks, but we can emulate them with + * junction points on newer Win32 versions. + * + * Cygwin has its own symlinks which work on Win95/98/ME where + * junction points don't, so use those instead. We have no way of + * knowing what type of system Cygwin binaries will be run on. + * Note: Some CYGWIN includes might #define WIN32. + */ +extern int pgsymlink(const char *oldpath, const char *newpath); +extern int pgreadlink(const char *path, char *buf, size_t size); +extern bool pgwin32_is_junction(const char *path); + +#define symlink(oldpath, newpath) pgsymlink(oldpath, newpath) +#define readlink(path, buf, size) pgreadlink(path, buf, size) + +/* + * Supplement to <sys/types.h>. + * + * Perl already has typedefs for uid_t and gid_t. + */ +#ifndef PLPERL_HAVE_UID_GID +typedef int uid_t; +typedef int gid_t; +#endif +typedef long key_t; + +#ifdef _MSC_VER +typedef int pid_t; +#endif + +/* + * Supplement to <sys/stat.h>. + * + * We must pull in sys/stat.h before this part, else our overrides lose. + * + * stat() is not guaranteed to set the st_size field on win32, so we + * redefine it to our own implementation. See src/port/win32stat.c. + * + * The struct stat is 32 bit in MSVC, so we redefine it as a copy of + * struct __stat64. This also fixes the struct size for MINGW builds. + */ +struct stat /* This should match struct __stat64 */ +{ + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; +}; + +extern int _pgfstat64(int fileno, struct stat *buf); +extern int _pgstat64(const char *name, struct stat *buf); + +#define fstat(fileno, sb) _pgfstat64(fileno, sb) +#define stat(path, sb) _pgstat64(path, sb) +#define lstat(path, sb) _pgstat64(path, sb) + +/* These macros are not provided by older MinGW, nor by MSVC */ +#ifndef S_IRUSR +#define S_IRUSR _S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR _S_IWRITE +#endif +#ifndef S_IXUSR +#define S_IXUSR _S_IEXEC +#endif +#ifndef S_IRWXU +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif +#ifndef S_IRGRP +#define S_IRGRP 0 +#endif +#ifndef S_IWGRP +#define S_IWGRP 0 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0 +#endif +#ifndef S_IRWXG +#define S_IRWXG 0 +#endif +#ifndef S_IROTH +#define S_IROTH 0 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0 +#endif +#ifndef S_IRWXO +#define S_IRWXO 0 +#endif +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +/* + * Supplement to <fcntl.h>. + * This is the same value as _O_NOINHERIT in the MS header file. This is + * to ensure that we don't collide with a future definition. It means + * we cannot use _O_NOINHERIT ourselves. + */ +#define O_DSYNC 0x0080 + +/* + * Supplement to <errno.h>. + * + * We redefine network-related Berkeley error symbols as the corresponding WSA + * constants. This allows strerror.c to recognize them as being in the Winsock + * error code range and pass them off to win32_socket_strerror(), since + * Windows' version of plain strerror() won't cope. Note that this will break + * if these names are used for anything else besides Windows Sockets errors. + * See TranslateSocketError() when changing this list. + */ +#undef EAGAIN +#define EAGAIN WSAEWOULDBLOCK +#undef EINTR +#define EINTR WSAEINTR +#undef EMSGSIZE +#define EMSGSIZE WSAEMSGSIZE +#undef EAFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#undef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#undef ECONNRESET +#define ECONNRESET WSAECONNRESET +#undef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#undef EISCONN +#define EISCONN WSAEISCONN +#undef ENOBUFS +#define ENOBUFS WSAENOBUFS +#undef EPROTONOSUPPORT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#undef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#undef ENOTSOCK +#define ENOTSOCK WSAENOTSOCK +#undef EOPNOTSUPP +#define EOPNOTSUPP WSAEOPNOTSUPP +#undef EADDRINUSE +#define EADDRINUSE WSAEADDRINUSE +#undef EADDRNOTAVAIL +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#undef EHOSTDOWN +#define EHOSTDOWN WSAEHOSTDOWN +#undef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#undef ENETDOWN +#define ENETDOWN WSAENETDOWN +#undef ENETRESET +#define ENETRESET WSAENETRESET +#undef ENETUNREACH +#define ENETUNREACH WSAENETUNREACH +#undef ENOTCONN +#define ENOTCONN WSAENOTCONN +#undef ETIMEDOUT +#define ETIMEDOUT WSAETIMEDOUT + +/* + * Locale stuff. + * + * Extended locale functions with gratuitous underscore prefixes. + * (These APIs are nevertheless fully documented by Microsoft.) + */ +#define locale_t _locale_t +#define tolower_l _tolower_l +#define toupper_l _toupper_l +#define towlower_l _towlower_l +#define towupper_l _towupper_l +#define isdigit_l _isdigit_l +#define iswdigit_l _iswdigit_l +#define isalpha_l _isalpha_l +#define iswalpha_l _iswalpha_l +#define isalnum_l _isalnum_l +#define iswalnum_l _iswalnum_l +#define isupper_l _isupper_l +#define iswupper_l _iswupper_l +#define islower_l _islower_l +#define iswlower_l _iswlower_l +#define isgraph_l _isgraph_l +#define iswgraph_l _iswgraph_l +#define isprint_l _isprint_l +#define iswprint_l _iswprint_l +#define ispunct_l _ispunct_l +#define iswpunct_l _iswpunct_l +#define isspace_l _isspace_l +#define iswspace_l _iswspace_l +#define strcoll_l _strcoll_l +#define strxfrm_l _strxfrm_l +#define wcscoll_l _wcscoll_l +#define wcstombs_l _wcstombs_l +#define mbstowcs_l _mbstowcs_l + +/* + * Versions of libintl >= 0.18? try to replace setlocale() with a macro + * to their own versions. Remove the macro, if it exists, because it + * ends up calling the wrong version when the backend and libintl use + * different versions of msvcrt. + */ +#if defined(setlocale) +#undef setlocale +#endif + +/* + * Define our own wrapper macro around setlocale() to work around bugs in + * Windows' native setlocale() function. + */ +extern char *pgwin32_setlocale(int category, const char *locale); + +#define setlocale(a,b) pgwin32_setlocale(a,b) + + +/* In backend/port/win32/signal.c */ +extern PGDLLIMPORT volatile int pg_signal_queue; +extern PGDLLIMPORT int pg_signal_mask; +extern PGDLLIMPORT HANDLE pgwin32_signal_event; +extern PGDLLIMPORT HANDLE pgwin32_initial_signal_pipe; + +#define UNBLOCKED_SIGNAL_QUEUE() (pg_signal_queue & ~pg_signal_mask) +#define PG_SIGNAL_COUNT 32 + +extern void pgwin32_signal_initialize(void); +extern HANDLE pgwin32_create_signal_listener(pid_t pid); +extern void pgwin32_dispatch_queued_signals(void); +extern void pg_queue_signal(int signum); + +/* In src/port/kill.c */ +#define kill(pid,sig) pgkill(pid,sig) +extern int pgkill(int pid, int sig); + +/* In backend/port/win32/socket.c */ +#ifndef FRONTEND +#define socket(af, type, protocol) pgwin32_socket(af, type, protocol) +#define bind(s, addr, addrlen) pgwin32_bind(s, addr, addrlen) +#define listen(s, backlog) pgwin32_listen(s, backlog) +#define accept(s, addr, addrlen) pgwin32_accept(s, addr, addrlen) +#define connect(s, name, namelen) pgwin32_connect(s, name, namelen) +#define select(n, r, w, e, timeout) pgwin32_select(n, r, w, e, timeout) +#define recv(s, buf, len, flags) pgwin32_recv(s, buf, len, flags) +#define send(s, buf, len, flags) pgwin32_send(s, buf, len, flags) + +extern SOCKET pgwin32_socket(int af, int type, int protocol); +extern int pgwin32_bind(SOCKET s, struct sockaddr *addr, int addrlen); +extern int pgwin32_listen(SOCKET s, int backlog); +extern SOCKET pgwin32_accept(SOCKET s, struct sockaddr *addr, int *addrlen); +extern int pgwin32_connect(SOCKET s, const struct sockaddr *name, int namelen); +extern int pgwin32_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout); +extern int pgwin32_recv(SOCKET s, char *buf, int len, int flags); +extern int pgwin32_send(SOCKET s, const void *buf, int len, int flags); +extern int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); + +extern PGDLLIMPORT int pgwin32_noblock; + +#endif /* FRONTEND */ + +/* in backend/port/win32_shmem.c */ +extern int pgwin32_ReserveSharedMemoryRegion(HANDLE); + +/* in backend/port/win32/crashdump.c */ +extern void pgwin32_install_crashdump_handler(void); + +/* in port/win32error.c */ +extern void _dosmaperr(unsigned long); + +/* in port/win32env.c */ +extern int pgwin32_putenv(const char *); +extern int pgwin32_setenv(const char *name, const char *value, int overwrite); +extern int pgwin32_unsetenv(const char *name); + +#define putenv(x) pgwin32_putenv(x) +#define setenv(x,y,z) pgwin32_setenv(x,y,z) +#define unsetenv(x) pgwin32_unsetenv(x) + +/* in port/win32security.c */ +extern int pgwin32_is_service(void); +extern int pgwin32_is_admin(void); + +/* Windows security token manipulation (in src/common/exec.c) */ +extern BOOL AddUserToTokenDacl(HANDLE hToken); + +/* Things that exist in MinGW headers, but need to be added to MSVC */ +#ifdef _MSC_VER + +#ifndef _WIN64 +typedef long ssize_t; +#else +typedef __int64 ssize_t; +#endif + +typedef unsigned short mode_t; + +#define F_OK 0 +#define W_OK 2 +#define R_OK 4 + +#endif /* _MSC_VER */ + +#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || \ + defined(__MINGW32__) || defined(__MINGW64__) +/* + * VS2013 has a strtof() that seems to give correct answers for valid input, + * even on the rounding edge cases, but which doesn't handle out-of-range + * input correctly. Work around that. + * + * Mingw claims to have a strtof, and my reading of its source code suggests + * that it ought to work (and not need this hack), but the regression test + * results disagree with me; whether this is a version issue or not is not + * clear. However, using our wrapper (and the misrounded-input variant file, + * already required for supporting ancient systems) can't make things any + * worse, except for a tiny performance loss when reading zeros. + * + * See also cygwin.h for another instance of this. + */ +#define HAVE_BUGGY_STRTOF 1 +#endif + +#endif /* PG_WIN32_PORT_H */ diff --git a/src/include/port/win32ntdll.h b/src/include/port/win32ntdll.h new file mode 100644 index 0000000..291b067 --- /dev/null +++ b/src/include/port/win32ntdll.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * win32ntdll.h + * Dynamically loaded Windows NT functions. + * + * Portions Copyright (c) 2021-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/port/win32ntdll.h + * + *------------------------------------------------------------------------- + */ + +#ifndef WIN32NTDLL_H +#define WIN32NTDLL_H + +/* + * Because this includes NT headers that normally conflict with Win32 headers, + * any translation unit that includes it should #define UMDF_USING_NTSTATUS + * before including <windows.h>. + */ + +#include <ntstatus.h> +#include <winternl.h> + +typedef NTSTATUS (__stdcall * RtlGetLastNtStatus_t) (void); + +extern PGDLLIMPORT RtlGetLastNtStatus_t pg_RtlGetLastNtStatus; + +extern int initialize_ntdll(void); + +#endif /* WIN32NTDLL_H */ diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h new file mode 100644 index 0000000..ca09a16 --- /dev/null +++ b/src/include/portability/instr_time.h @@ -0,0 +1,256 @@ +/*------------------------------------------------------------------------- + * + * instr_time.h + * portable high-precision interval timing + * + * This file provides an abstraction layer to hide portability issues in + * interval timing. On Unix we use clock_gettime() if available, else + * gettimeofday(). On Windows, gettimeofday() gives a low-precision result + * so we must use QueryPerformanceCounter() instead. These macros also give + * some breathing room to use other high-precision-timing APIs. + * + * The basic data type is instr_time, which all callers should treat as an + * opaque typedef. instr_time can store either an absolute time (of + * unspecified reference time) or an interval. The operations provided + * for it are: + * + * INSTR_TIME_IS_ZERO(t) is t equal to zero? + * + * INSTR_TIME_SET_ZERO(t) set t to zero (memset is acceptable too) + * + * INSTR_TIME_SET_CURRENT(t) set t to current time + * + * INSTR_TIME_SET_CURRENT_LAZY(t) set t to current time if t is zero, + * evaluates to whether t changed + * + * INSTR_TIME_ADD(x, y) x += y + * + * INSTR_TIME_SUBTRACT(x, y) x -= y + * + * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z) + * + * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds) + * + * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds) + * + * INSTR_TIME_GET_MICROSEC(t) convert t to uint64 (in microseconds) + * + * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert + * absolute times to intervals. The INSTR_TIME_GET_xxx operations are + * only useful on intervals. + * + * When summing multiple measurements, it's recommended to leave the + * running sum in instr_time form (ie, use INSTR_TIME_ADD or + * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end. + * + * Beware of multiple evaluations of the macro arguments. + * + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/portability/instr_time.h + * + *------------------------------------------------------------------------- + */ +#ifndef INSTR_TIME_H +#define INSTR_TIME_H + +#ifndef WIN32 + +#ifdef HAVE_CLOCK_GETTIME + +/* Use clock_gettime() */ + +#include <time.h> + +/* + * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC, + * since that will give reliable interval timing even in the face of changes + * to the system clock. However, POSIX doesn't require implementations to + * provide anything except CLOCK_REALTIME, so fall back to that if we don't + * find CLOCK_MONOTONIC. + * + * Also, some implementations have nonstandard clockids with better properties + * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides + * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than + * their version of CLOCK_MONOTONIC. + */ +#if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW +#elif defined(CLOCK_MONOTONIC) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC +#else +#define PG_INSTR_CLOCK CLOCK_REALTIME +#endif + +typedef struct timespec instr_time; + +#define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0) + +#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0) + +#define INSTR_TIME_SET_CURRENT(t) ((void) clock_gettime(PG_INSTR_CLOCK, &(t))) + +#define INSTR_TIME_ADD(x,y) \ + do { \ + (x).tv_sec += (y).tv_sec; \ + (x).tv_nsec += (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_SUBTRACT(x,y) \ + do { \ + (x).tv_sec -= (y).tv_sec; \ + (x).tv_nsec -= (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + } while (0) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + do { \ + (x).tv_sec += (y).tv_sec - (z).tv_sec; \ + (x).tv_nsec += (y).tv_nsec - (z).tv_nsec; \ + /* Normalize after each add to avoid overflow/underflow of tv_nsec */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_GET_DOUBLE(t) \ + (((double) (t).tv_sec) + ((double) (t).tv_nsec) / 1000000000.0) + +#define INSTR_TIME_GET_MILLISEC(t) \ + (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_nsec) / 1000000.0) + +#define INSTR_TIME_GET_MICROSEC(t) \ + (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) ((t).tv_nsec / 1000)) + +#else /* !HAVE_CLOCK_GETTIME */ + +/* Use gettimeofday() */ + +#include <sys/time.h> + +typedef struct timeval instr_time; + +#define INSTR_TIME_IS_ZERO(t) ((t).tv_usec == 0 && (t).tv_sec == 0) + +#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_usec = 0) + +#define INSTR_TIME_SET_CURRENT(t) gettimeofday(&(t), NULL) + +#define INSTR_TIME_ADD(x,y) \ + do { \ + (x).tv_sec += (y).tv_sec; \ + (x).tv_usec += (y).tv_usec; \ + /* Normalize */ \ + while ((x).tv_usec >= 1000000) \ + { \ + (x).tv_usec -= 1000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_SUBTRACT(x,y) \ + do { \ + (x).tv_sec -= (y).tv_sec; \ + (x).tv_usec -= (y).tv_usec; \ + /* Normalize */ \ + while ((x).tv_usec < 0) \ + { \ + (x).tv_usec += 1000000; \ + (x).tv_sec--; \ + } \ + } while (0) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + do { \ + (x).tv_sec += (y).tv_sec - (z).tv_sec; \ + (x).tv_usec += (y).tv_usec - (z).tv_usec; \ + /* Normalize after each add to avoid overflow/underflow of tv_usec */ \ + while ((x).tv_usec < 0) \ + { \ + (x).tv_usec += 1000000; \ + (x).tv_sec--; \ + } \ + while ((x).tv_usec >= 1000000) \ + { \ + (x).tv_usec -= 1000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_GET_DOUBLE(t) \ + (((double) (t).tv_sec) + ((double) (t).tv_usec) / 1000000.0) + +#define INSTR_TIME_GET_MILLISEC(t) \ + (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_usec) / 1000.0) + +#define INSTR_TIME_GET_MICROSEC(t) \ + (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) (t).tv_usec) + +#endif /* HAVE_CLOCK_GETTIME */ + +#else /* WIN32 */ + +/* Use QueryPerformanceCounter() */ + +typedef LARGE_INTEGER instr_time; + +#define INSTR_TIME_IS_ZERO(t) ((t).QuadPart == 0) + +#define INSTR_TIME_SET_ZERO(t) ((t).QuadPart = 0) + +#define INSTR_TIME_SET_CURRENT(t) QueryPerformanceCounter(&(t)) + +#define INSTR_TIME_ADD(x,y) \ + ((x).QuadPart += (y).QuadPart) + +#define INSTR_TIME_SUBTRACT(x,y) \ + ((x).QuadPart -= (y).QuadPart) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + ((x).QuadPart += (y).QuadPart - (z).QuadPart) + +#define INSTR_TIME_GET_DOUBLE(t) \ + (((double) (t).QuadPart) / GetTimerFrequency()) + +#define INSTR_TIME_GET_MILLISEC(t) \ + (((double) (t).QuadPart * 1000.0) / GetTimerFrequency()) + +#define INSTR_TIME_GET_MICROSEC(t) \ + ((uint64) (((double) (t).QuadPart * 1000000.0) / GetTimerFrequency())) + +static inline double +GetTimerFrequency(void) +{ + LARGE_INTEGER f; + + QueryPerformanceFrequency(&f); + return (double) f.QuadPart; +} + +#endif /* WIN32 */ + +/* same macro on all platforms */ + +#define INSTR_TIME_SET_CURRENT_LAZY(t) \ + (INSTR_TIME_IS_ZERO(t) ? INSTR_TIME_SET_CURRENT(t), true : false) + +#endif /* INSTR_TIME_H */ diff --git a/src/include/portability/mem.h b/src/include/portability/mem.h new file mode 100644 index 0000000..b553b40 --- /dev/null +++ b/src/include/portability/mem.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * mem.h + * portability definitions for various memory operations + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/portability/mem.h + * + *------------------------------------------------------------------------- + */ +#ifndef MEM_H +#define MEM_H + +#define IPCProtection (0600) /* access/modify by user only */ + +#ifdef SHM_SHARE_MMU /* use intimate shared memory on Solaris */ +#define PG_SHMAT_FLAGS SHM_SHARE_MMU +#else +#define PG_SHMAT_FLAGS 0 +#endif + +/* Linux prefers MAP_ANONYMOUS, but the flag is called MAP_ANON on other systems. */ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* BSD-derived systems have MAP_HASSEMAPHORE, but it's not present (or needed) on Linux. */ +#ifndef MAP_HASSEMAPHORE +#define MAP_HASSEMAPHORE 0 +#endif + +/* + * BSD-derived systems use the MAP_NOSYNC flag to prevent dirty mmap(2) + * pages from being gratuitously flushed to disk. + */ +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif + +#define PG_MMAP_FLAGS (MAP_SHARED|MAP_ANONYMOUS|MAP_HASSEMAPHORE) + +/* Some really old systems don't define MAP_FAILED. */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + +#endif /* MEM_H */ diff --git a/src/include/postgres.h b/src/include/postgres.h new file mode 100644 index 0000000..3135811 --- /dev/null +++ b/src/include/postgres.h @@ -0,0 +1,808 @@ +/*------------------------------------------------------------------------- + * + * postgres.h + * Primary include file for PostgreSQL server .c files + * + * This should be the first file included by PostgreSQL backend modules. + * Client-side code should include postgres_fe.h instead. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1995, Regents of the University of California + * + * src/include/postgres.h + * + *------------------------------------------------------------------------- + */ +/* + *---------------------------------------------------------------- + * TABLE OF CONTENTS + * + * When adding stuff to this file, please try to put stuff + * into the relevant section, or add new sections as appropriate. + * + * section description + * ------- ------------------------------------------------ + * 1) variable-length datatypes (TOAST support) + * 2) Datum type + support macros + * + * NOTES + * + * In general, this file should contain declarations that are widely needed + * in the backend environment, but are of no interest outside the backend. + * + * Simple type definitions live in c.h, where they are shared with + * postgres_fe.h. We do that since those type definitions are needed by + * frontend modules that want to deal with binary data transmission to or + * from the backend. Type definitions in this file should be for + * representations that never escape the backend, such as Datum or + * TOASTed varlena objects. + * + *---------------------------------------------------------------- + */ +#ifndef POSTGRES_H +#define POSTGRES_H + +#include "c.h" +#include "utils/elog.h" +#include "utils/palloc.h" + +/* ---------------------------------------------------------------- + * Section 1: variable-length datatypes (TOAST support) + * ---------------------------------------------------------------- + */ + +/* + * struct varatt_external is a traditional "TOAST pointer", that is, the + * information needed to fetch a Datum stored out-of-line in a TOAST table. + * The data is compressed if and only if the external size stored in + * va_extinfo is less than va_rawsize - VARHDRSZ. + * + * This struct must not contain any padding, because we sometimes compare + * these pointers using memcmp. + * + * Note that this information is stored unaligned within actual tuples, so + * you need to memcpy from the tuple into a local struct variable before + * you can look at these fields! (The reason we use memcmp is to avoid + * having to do that just to detect equality of two TOAST pointers...) + */ +typedef struct varatt_external +{ + int32 va_rawsize; /* Original data size (includes header) */ + uint32 va_extinfo; /* External saved size (without header) and + * compression method */ + Oid va_valueid; /* Unique ID of value within TOAST table */ + Oid va_toastrelid; /* RelID of TOAST table containing it */ +} varatt_external; + +/* + * These macros define the "saved size" portion of va_extinfo. Its remaining + * two high-order bits identify the compression method. + */ +#define VARLENA_EXTSIZE_BITS 30 +#define VARLENA_EXTSIZE_MASK ((1U << VARLENA_EXTSIZE_BITS) - 1) + +/* + * struct varatt_indirect is a "TOAST pointer" representing an out-of-line + * Datum that's stored in memory, not in an external toast relation. + * The creator of such a Datum is entirely responsible that the referenced + * storage survives for as long as referencing pointer Datums can exist. + * + * Note that just as for struct varatt_external, this struct is stored + * unaligned within any containing tuple. + */ +typedef struct varatt_indirect +{ + struct varlena *pointer; /* Pointer to in-memory varlena */ +} varatt_indirect; + +/* + * struct varatt_expanded is a "TOAST pointer" representing an out-of-line + * Datum that is stored in memory, in some type-specific, not necessarily + * physically contiguous format that is convenient for computation not + * storage. APIs for this, in particular the definition of struct + * ExpandedObjectHeader, are in src/include/utils/expandeddatum.h. + * + * Note that just as for struct varatt_external, this struct is stored + * unaligned within any containing tuple. + */ +typedef struct ExpandedObjectHeader ExpandedObjectHeader; + +typedef struct varatt_expanded +{ + ExpandedObjectHeader *eohptr; +} varatt_expanded; + +/* + * Type tag for the various sorts of "TOAST pointer" datums. The peculiar + * value for VARTAG_ONDISK comes from a requirement for on-disk compatibility + * with a previous notion that the tag field was the pointer datum's length. + */ +typedef enum vartag_external +{ + VARTAG_INDIRECT = 1, + VARTAG_EXPANDED_RO = 2, + VARTAG_EXPANDED_RW = 3, + VARTAG_ONDISK = 18 +} vartag_external; + +/* this test relies on the specific tag values above */ +#define VARTAG_IS_EXPANDED(tag) \ + (((tag) & ~1) == VARTAG_EXPANDED_RO) + +#define VARTAG_SIZE(tag) \ + ((tag) == VARTAG_INDIRECT ? sizeof(varatt_indirect) : \ + VARTAG_IS_EXPANDED(tag) ? sizeof(varatt_expanded) : \ + (tag) == VARTAG_ONDISK ? sizeof(varatt_external) : \ + TrapMacro(true, "unrecognized TOAST vartag")) + +/* + * These structs describe the header of a varlena object that may have been + * TOASTed. Generally, don't reference these structs directly, but use the + * macros below. + * + * We use separate structs for the aligned and unaligned cases because the + * compiler might otherwise think it could generate code that assumes + * alignment while touching fields of a 1-byte-header varlena. + */ +typedef union +{ + struct /* Normal varlena (4-byte length) */ + { + uint32 va_header; + char va_data[FLEXIBLE_ARRAY_MEMBER]; + } va_4byte; + struct /* Compressed-in-line format */ + { + uint32 va_header; + uint32 va_tcinfo; /* Original data size (excludes header) and + * compression method; see va_extinfo */ + char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Compressed data */ + } va_compressed; +} varattrib_4b; + +typedef struct +{ + uint8 va_header; + char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Data begins here */ +} varattrib_1b; + +/* TOAST pointers are a subset of varattrib_1b with an identifying tag byte */ +typedef struct +{ + uint8 va_header; /* Always 0x80 or 0x01 */ + uint8 va_tag; /* Type of datum */ + char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Type-specific data */ +} varattrib_1b_e; + +/* + * Bit layouts for varlena headers on big-endian machines: + * + * 00xxxxxx 4-byte length word, aligned, uncompressed data (up to 1G) + * 01xxxxxx 4-byte length word, aligned, *compressed* data (up to 1G) + * 10000000 1-byte length word, unaligned, TOAST pointer + * 1xxxxxxx 1-byte length word, unaligned, uncompressed data (up to 126b) + * + * Bit layouts for varlena headers on little-endian machines: + * + * xxxxxx00 4-byte length word, aligned, uncompressed data (up to 1G) + * xxxxxx10 4-byte length word, aligned, *compressed* data (up to 1G) + * 00000001 1-byte length word, unaligned, TOAST pointer + * xxxxxxx1 1-byte length word, unaligned, uncompressed data (up to 126b) + * + * The "xxx" bits are the length field (which includes itself in all cases). + * In the big-endian case we mask to extract the length, in the little-endian + * case we shift. Note that in both cases the flag bits are in the physically + * first byte. Also, it is not possible for a 1-byte length word to be zero; + * this lets us disambiguate alignment padding bytes from the start of an + * unaligned datum. (We now *require* pad bytes to be filled with zero!) + * + * In TOAST pointers the va_tag field (see varattrib_1b_e) is used to discern + * the specific type and length of the pointer datum. + */ + +/* + * Endian-dependent macros. These are considered internal --- use the + * external macros below instead of using these directly. + * + * Note: IS_1B is true for external toast records but VARSIZE_1B will return 0 + * for such records. Hence you should usually check for IS_EXTERNAL before + * checking for IS_1B. + */ + +#ifdef WORDS_BIGENDIAN + +#define VARATT_IS_4B(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x00) +#define VARATT_IS_4B_U(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x00) +#define VARATT_IS_4B_C(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x40) +#define VARATT_IS_1B(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x80) +#define VARATT_IS_1B_E(PTR) \ + ((((varattrib_1b *) (PTR))->va_header) == 0x80) +#define VARATT_NOT_PAD_BYTE(PTR) \ + (*((uint8 *) (PTR)) != 0) + +/* VARSIZE_4B() should only be used on known-aligned data */ +#define VARSIZE_4B(PTR) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header & 0x3FFFFFFF) +#define VARSIZE_1B(PTR) \ + (((varattrib_1b *) (PTR))->va_header & 0x7F) +#define VARTAG_1B_E(PTR) \ + (((varattrib_1b_e *) (PTR))->va_tag) + +#define SET_VARSIZE_4B(PTR,len) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header = (len) & 0x3FFFFFFF) +#define SET_VARSIZE_4B_C(PTR,len) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header = ((len) & 0x3FFFFFFF) | 0x40000000) +#define SET_VARSIZE_1B(PTR,len) \ + (((varattrib_1b *) (PTR))->va_header = (len) | 0x80) +#define SET_VARTAG_1B_E(PTR,tag) \ + (((varattrib_1b_e *) (PTR))->va_header = 0x80, \ + ((varattrib_1b_e *) (PTR))->va_tag = (tag)) + +#else /* !WORDS_BIGENDIAN */ + +#define VARATT_IS_4B(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x00) +#define VARATT_IS_4B_U(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x00) +#define VARATT_IS_4B_C(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x02) +#define VARATT_IS_1B(PTR) \ + ((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x01) +#define VARATT_IS_1B_E(PTR) \ + ((((varattrib_1b *) (PTR))->va_header) == 0x01) +#define VARATT_NOT_PAD_BYTE(PTR) \ + (*((uint8 *) (PTR)) != 0) + +/* VARSIZE_4B() should only be used on known-aligned data */ +#define VARSIZE_4B(PTR) \ + ((((varattrib_4b *) (PTR))->va_4byte.va_header >> 2) & 0x3FFFFFFF) +#define VARSIZE_1B(PTR) \ + ((((varattrib_1b *) (PTR))->va_header >> 1) & 0x7F) +#define VARTAG_1B_E(PTR) \ + (((varattrib_1b_e *) (PTR))->va_tag) + +#define SET_VARSIZE_4B(PTR,len) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2)) +#define SET_VARSIZE_4B_C(PTR,len) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2) | 0x02) +#define SET_VARSIZE_1B(PTR,len) \ + (((varattrib_1b *) (PTR))->va_header = (((uint8) (len)) << 1) | 0x01) +#define SET_VARTAG_1B_E(PTR,tag) \ + (((varattrib_1b_e *) (PTR))->va_header = 0x01, \ + ((varattrib_1b_e *) (PTR))->va_tag = (tag)) + +#endif /* WORDS_BIGENDIAN */ + +#define VARDATA_4B(PTR) (((varattrib_4b *) (PTR))->va_4byte.va_data) +#define VARDATA_4B_C(PTR) (((varattrib_4b *) (PTR))->va_compressed.va_data) +#define VARDATA_1B(PTR) (((varattrib_1b *) (PTR))->va_data) +#define VARDATA_1B_E(PTR) (((varattrib_1b_e *) (PTR))->va_data) + +/* + * Externally visible TOAST macros begin here. + */ + +#define VARHDRSZ_EXTERNAL offsetof(varattrib_1b_e, va_data) +#define VARHDRSZ_COMPRESSED offsetof(varattrib_4b, va_compressed.va_data) +#define VARHDRSZ_SHORT offsetof(varattrib_1b, va_data) + +#define VARATT_SHORT_MAX 0x7F +#define VARATT_CAN_MAKE_SHORT(PTR) \ + (VARATT_IS_4B_U(PTR) && \ + (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) <= VARATT_SHORT_MAX) +#define VARATT_CONVERTED_SHORT_SIZE(PTR) \ + (VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) + +/* + * In consumers oblivious to data alignment, call PG_DETOAST_DATUM_PACKED(), + * VARDATA_ANY(), VARSIZE_ANY() and VARSIZE_ANY_EXHDR(). Elsewhere, call + * PG_DETOAST_DATUM(), VARDATA() and VARSIZE(). Directly fetching an int16, + * int32 or wider field in the struct representing the datum layout requires + * aligned data. memcpy() is alignment-oblivious, as are most operations on + * datatypes, such as text, whose layout struct contains only char fields. + * + * Code assembling a new datum should call VARDATA() and SET_VARSIZE(). + * (Datums begin life untoasted.) + * + * Other macros here should usually be used only by tuple assembly/disassembly + * code and code that specifically wants to work with still-toasted Datums. + */ +#define VARDATA(PTR) VARDATA_4B(PTR) +#define VARSIZE(PTR) VARSIZE_4B(PTR) + +#define VARSIZE_SHORT(PTR) VARSIZE_1B(PTR) +#define VARDATA_SHORT(PTR) VARDATA_1B(PTR) + +#define VARTAG_EXTERNAL(PTR) VARTAG_1B_E(PTR) +#define VARSIZE_EXTERNAL(PTR) (VARHDRSZ_EXTERNAL + VARTAG_SIZE(VARTAG_EXTERNAL(PTR))) +#define VARDATA_EXTERNAL(PTR) VARDATA_1B_E(PTR) + +#define VARATT_IS_COMPRESSED(PTR) VARATT_IS_4B_C(PTR) +#define VARATT_IS_EXTERNAL(PTR) VARATT_IS_1B_E(PTR) +#define VARATT_IS_EXTERNAL_ONDISK(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_ONDISK) +#define VARATT_IS_EXTERNAL_INDIRECT(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_INDIRECT) +#define VARATT_IS_EXTERNAL_EXPANDED_RO(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RO) +#define VARATT_IS_EXTERNAL_EXPANDED_RW(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && VARTAG_EXTERNAL(PTR) == VARTAG_EXPANDED_RW) +#define VARATT_IS_EXTERNAL_EXPANDED(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR))) +#define VARATT_IS_EXTERNAL_NON_EXPANDED(PTR) \ + (VARATT_IS_EXTERNAL(PTR) && !VARTAG_IS_EXPANDED(VARTAG_EXTERNAL(PTR))) +#define VARATT_IS_SHORT(PTR) VARATT_IS_1B(PTR) +#define VARATT_IS_EXTENDED(PTR) (!VARATT_IS_4B_U(PTR)) + +#define SET_VARSIZE(PTR, len) SET_VARSIZE_4B(PTR, len) +#define SET_VARSIZE_SHORT(PTR, len) SET_VARSIZE_1B(PTR, len) +#define SET_VARSIZE_COMPRESSED(PTR, len) SET_VARSIZE_4B_C(PTR, len) + +#define SET_VARTAG_EXTERNAL(PTR, tag) SET_VARTAG_1B_E(PTR, tag) + +#define VARSIZE_ANY(PTR) \ + (VARATT_IS_1B_E(PTR) ? VARSIZE_EXTERNAL(PTR) : \ + (VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR) : \ + VARSIZE_4B(PTR))) + +/* Size of a varlena data, excluding header */ +#define VARSIZE_ANY_EXHDR(PTR) \ + (VARATT_IS_1B_E(PTR) ? VARSIZE_EXTERNAL(PTR)-VARHDRSZ_EXTERNAL : \ + (VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR)-VARHDRSZ_SHORT : \ + VARSIZE_4B(PTR)-VARHDRSZ)) + +/* caution: this will not work on an external or compressed-in-line Datum */ +/* caution: this will return a possibly unaligned pointer */ +#define VARDATA_ANY(PTR) \ + (VARATT_IS_1B(PTR) ? VARDATA_1B(PTR) : VARDATA_4B(PTR)) + +/* Decompressed size and compression method of a compressed-in-line Datum */ +#define VARDATA_COMPRESSED_GET_EXTSIZE(PTR) \ + (((varattrib_4b *) (PTR))->va_compressed.va_tcinfo & VARLENA_EXTSIZE_MASK) +#define VARDATA_COMPRESSED_GET_COMPRESS_METHOD(PTR) \ + (((varattrib_4b *) (PTR))->va_compressed.va_tcinfo >> VARLENA_EXTSIZE_BITS) + +/* Same for external Datums; but note argument is a struct varatt_external */ +#define VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer) \ + ((toast_pointer).va_extinfo & VARLENA_EXTSIZE_MASK) +#define VARATT_EXTERNAL_GET_COMPRESS_METHOD(toast_pointer) \ + ((toast_pointer).va_extinfo >> VARLENA_EXTSIZE_BITS) + +#define VARATT_EXTERNAL_SET_SIZE_AND_COMPRESS_METHOD(toast_pointer, len, cm) \ + do { \ + Assert((cm) == TOAST_PGLZ_COMPRESSION_ID || \ + (cm) == TOAST_LZ4_COMPRESSION_ID); \ + ((toast_pointer).va_extinfo = \ + (len) | ((uint32) (cm) << VARLENA_EXTSIZE_BITS)); \ + } while (0) + +/* + * Testing whether an externally-stored value is compressed now requires + * comparing size stored in va_extinfo (the actual length of the external data) + * to rawsize (the original uncompressed datum's size). The latter includes + * VARHDRSZ overhead, the former doesn't. We never use compression unless it + * actually saves space, so we expect either equality or less-than. + */ +#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \ + (VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer) < \ + (toast_pointer).va_rawsize - VARHDRSZ) + + +/* ---------------------------------------------------------------- + * Section 2: Datum type + support macros + * ---------------------------------------------------------------- + */ + +/* + * A Datum contains either a value of a pass-by-value type or a pointer to a + * value of a pass-by-reference type. Therefore, we require: + * + * sizeof(Datum) == sizeof(void *) == 4 or 8 + * + * The macros below and the analogous macros for other types should be used to + * convert between a Datum and the appropriate C type. + */ + +typedef uintptr_t Datum; + +/* + * A NullableDatum is used in places where both a Datum and its nullness needs + * to be stored. This can be more efficient than storing datums and nullness + * in separate arrays, due to better spatial locality, even if more space may + * be wasted due to padding. + */ +typedef struct NullableDatum +{ +#define FIELDNO_NULLABLE_DATUM_DATUM 0 + Datum value; +#define FIELDNO_NULLABLE_DATUM_ISNULL 1 + bool isnull; + /* due to alignment padding this could be used for flags for free */ +} NullableDatum; + +#define SIZEOF_DATUM SIZEOF_VOID_P + +/* + * DatumGetBool + * Returns boolean value of a datum. + * + * Note: any nonzero value will be considered true. + */ + +#define DatumGetBool(X) ((bool) ((X) != 0)) + +/* + * BoolGetDatum + * Returns datum representation for a boolean. + * + * Note: any nonzero value will be considered true. + */ + +#define BoolGetDatum(X) ((Datum) ((X) ? 1 : 0)) + +/* + * DatumGetChar + * Returns character value of a datum. + */ + +#define DatumGetChar(X) ((char) (X)) + +/* + * CharGetDatum + * Returns datum representation for a character. + */ + +#define CharGetDatum(X) ((Datum) (X)) + +/* + * Int8GetDatum + * Returns datum representation for an 8-bit integer. + */ + +#define Int8GetDatum(X) ((Datum) (X)) + +/* + * DatumGetUInt8 + * Returns 8-bit unsigned integer value of a datum. + */ + +#define DatumGetUInt8(X) ((uint8) (X)) + +/* + * UInt8GetDatum + * Returns datum representation for an 8-bit unsigned integer. + */ + +#define UInt8GetDatum(X) ((Datum) (X)) + +/* + * DatumGetInt16 + * Returns 16-bit integer value of a datum. + */ + +#define DatumGetInt16(X) ((int16) (X)) + +/* + * Int16GetDatum + * Returns datum representation for a 16-bit integer. + */ + +#define Int16GetDatum(X) ((Datum) (X)) + +/* + * DatumGetUInt16 + * Returns 16-bit unsigned integer value of a datum. + */ + +#define DatumGetUInt16(X) ((uint16) (X)) + +/* + * UInt16GetDatum + * Returns datum representation for a 16-bit unsigned integer. + */ + +#define UInt16GetDatum(X) ((Datum) (X)) + +/* + * DatumGetInt32 + * Returns 32-bit integer value of a datum. + */ + +#define DatumGetInt32(X) ((int32) (X)) + +/* + * Int32GetDatum + * Returns datum representation for a 32-bit integer. + */ + +#define Int32GetDatum(X) ((Datum) (X)) + +/* + * DatumGetUInt32 + * Returns 32-bit unsigned integer value of a datum. + */ + +#define DatumGetUInt32(X) ((uint32) (X)) + +/* + * UInt32GetDatum + * Returns datum representation for a 32-bit unsigned integer. + */ + +#define UInt32GetDatum(X) ((Datum) (X)) + +/* + * DatumGetObjectId + * Returns object identifier value of a datum. + */ + +#define DatumGetObjectId(X) ((Oid) (X)) + +/* + * ObjectIdGetDatum + * Returns datum representation for an object identifier. + */ + +#define ObjectIdGetDatum(X) ((Datum) (X)) + +/* + * DatumGetTransactionId + * Returns transaction identifier value of a datum. + */ + +#define DatumGetTransactionId(X) ((TransactionId) (X)) + +/* + * TransactionIdGetDatum + * Returns datum representation for a transaction identifier. + */ + +#define TransactionIdGetDatum(X) ((Datum) (X)) + +/* + * MultiXactIdGetDatum + * Returns datum representation for a multixact identifier. + */ + +#define MultiXactIdGetDatum(X) ((Datum) (X)) + +/* + * DatumGetCommandId + * Returns command identifier value of a datum. + */ + +#define DatumGetCommandId(X) ((CommandId) (X)) + +/* + * CommandIdGetDatum + * Returns datum representation for a command identifier. + */ + +#define CommandIdGetDatum(X) ((Datum) (X)) + +/* + * DatumGetPointer + * Returns pointer value of a datum. + */ + +#define DatumGetPointer(X) ((Pointer) (X)) + +/* + * PointerGetDatum + * Returns datum representation for a pointer. + */ + +#define PointerGetDatum(X) ((Datum) (X)) + +/* + * DatumGetCString + * Returns C string (null-terminated string) value of a datum. + * + * Note: C string is not a full-fledged Postgres type at present, + * but type input functions use this conversion for their inputs. + */ + +#define DatumGetCString(X) ((char *) DatumGetPointer(X)) + +/* + * CStringGetDatum + * Returns datum representation for a C string (null-terminated string). + * + * Note: C string is not a full-fledged Postgres type at present, + * but type output functions use this conversion for their outputs. + * Note: CString is pass-by-reference; caller must ensure the pointed-to + * value has adequate lifetime. + */ + +#define CStringGetDatum(X) PointerGetDatum(X) + +/* + * DatumGetName + * Returns name value of a datum. + */ + +#define DatumGetName(X) ((Name) DatumGetPointer(X)) + +/* + * NameGetDatum + * Returns datum representation for a name. + * + * Note: Name is pass-by-reference; caller must ensure the pointed-to + * value has adequate lifetime. + */ + +#define NameGetDatum(X) CStringGetDatum(NameStr(*(X))) + +/* + * DatumGetInt64 + * Returns 64-bit integer value of a datum. + * + * Note: this macro hides whether int64 is pass by value or by reference. + */ + +#ifdef USE_FLOAT8_BYVAL +#define DatumGetInt64(X) ((int64) (X)) +#else +#define DatumGetInt64(X) (* ((int64 *) DatumGetPointer(X))) +#endif + +/* + * Int64GetDatum + * Returns datum representation for a 64-bit integer. + * + * Note: if int64 is pass by reference, this function returns a reference + * to palloc'd space. + */ + +#ifdef USE_FLOAT8_BYVAL +#define Int64GetDatum(X) ((Datum) (X)) +#else +extern Datum Int64GetDatum(int64 X); +#endif + +/* + * DatumGetUInt64 + * Returns 64-bit unsigned integer value of a datum. + * + * Note: this macro hides whether int64 is pass by value or by reference. + */ + +#ifdef USE_FLOAT8_BYVAL +#define DatumGetUInt64(X) ((uint64) (X)) +#else +#define DatumGetUInt64(X) (* ((uint64 *) DatumGetPointer(X))) +#endif + +/* + * UInt64GetDatum + * Returns datum representation for a 64-bit unsigned integer. + * + * Note: if int64 is pass by reference, this function returns a reference + * to palloc'd space. + */ + +#ifdef USE_FLOAT8_BYVAL +#define UInt64GetDatum(X) ((Datum) (X)) +#else +#define UInt64GetDatum(X) Int64GetDatum((int64) (X)) +#endif + +/* + * Float <-> Datum conversions + * + * These have to be implemented as inline functions rather than macros, when + * passing by value, because many machines pass int and float function + * parameters/results differently; so we need to play weird games with unions. + */ + +/* + * DatumGetFloat4 + * Returns 4-byte floating point value of a datum. + */ +static inline float4 +DatumGetFloat4(Datum X) +{ + union + { + int32 value; + float4 retval; + } myunion; + + myunion.value = DatumGetInt32(X); + return myunion.retval; +} + +/* + * Float4GetDatum + * Returns datum representation for a 4-byte floating point number. + */ +static inline Datum +Float4GetDatum(float4 X) +{ + union + { + float4 value; + int32 retval; + } myunion; + + myunion.value = X; + return Int32GetDatum(myunion.retval); +} + +/* + * DatumGetFloat8 + * Returns 8-byte floating point value of a datum. + * + * Note: this macro hides whether float8 is pass by value or by reference. + */ + +#ifdef USE_FLOAT8_BYVAL +static inline float8 +DatumGetFloat8(Datum X) +{ + union + { + int64 value; + float8 retval; + } myunion; + + myunion.value = DatumGetInt64(X); + return myunion.retval; +} +#else +#define DatumGetFloat8(X) (* ((float8 *) DatumGetPointer(X))) +#endif + +/* + * Float8GetDatum + * Returns datum representation for an 8-byte floating point number. + * + * Note: if float8 is pass by reference, this function returns a reference + * to palloc'd space. + */ + +#ifdef USE_FLOAT8_BYVAL +static inline Datum +Float8GetDatum(float8 X) +{ + union + { + float8 value; + int64 retval; + } myunion; + + myunion.value = X; + return Int64GetDatum(myunion.retval); +} +#else +extern Datum Float8GetDatum(float8 X); +#endif + + +/* + * Int64GetDatumFast + * Float8GetDatumFast + * + * These macros are intended to allow writing code that does not depend on + * whether int64 and float8 are pass-by-reference types, while not + * sacrificing performance when they are. The argument must be a variable + * that will exist and have the same value for as long as the Datum is needed. + * In the pass-by-ref case, the address of the variable is taken to use as + * the Datum. In the pass-by-val case, these will be the same as the non-Fast + * macros. + */ + +#ifdef USE_FLOAT8_BYVAL +#define Int64GetDatumFast(X) Int64GetDatum(X) +#define Float8GetDatumFast(X) Float8GetDatum(X) +#else +#define Int64GetDatumFast(X) PointerGetDatum(&(X)) +#define Float8GetDatumFast(X) PointerGetDatum(&(X)) +#endif + +#endif /* POSTGRES_H */ diff --git a/src/include/postgres_ext.h b/src/include/postgres_ext.h new file mode 100644 index 0000000..fdb61b7 --- /dev/null +++ b/src/include/postgres_ext.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * postgres_ext.h + * + * This file contains declarations of things that are visible everywhere + * in PostgreSQL *and* are visible to clients of frontend interface libraries. + * For example, the Oid type is part of the API of libpq and other libraries. + * + * Declarations which are specific to a particular interface should + * go in the header file for that interface (such as libpq-fe.h). This + * file is only for fundamental Postgres declarations. + * + * User-written C functions don't count as "external to Postgres." + * Those function much as local modifications to the backend itself, and + * use header files that are otherwise internal to Postgres to interface + * with the backend. + * + * src/include/postgres_ext.h + * + *------------------------------------------------------------------------- + */ + +#ifndef POSTGRES_EXT_H +#define POSTGRES_EXT_H + +#include "pg_config_ext.h" + +/* + * Object ID is a fundamental type in Postgres. + */ +typedef unsigned int Oid; + +#ifdef __cplusplus +#define InvalidOid (Oid(0)) +#else +#define InvalidOid ((Oid) 0) +#endif + +#define OID_MAX UINT_MAX +/* you will need to include <limits.h> to use the above #define */ + +#define atooid(x) ((Oid) strtoul((x), NULL, 10)) +/* the above needs <stdlib.h> */ + + +/* Define a signed 64-bit integer type for use in client API declarations. */ +typedef PG_INT64_TYPE pg_int64; + + +/* + * Identifiers of error message fields. Kept here to keep common + * between frontend and backend, and also to export them to libpq + * applications. + */ +#define PG_DIAG_SEVERITY 'S' +#define PG_DIAG_SEVERITY_NONLOCALIZED 'V' +#define PG_DIAG_SQLSTATE 'C' +#define PG_DIAG_MESSAGE_PRIMARY 'M' +#define PG_DIAG_MESSAGE_DETAIL 'D' +#define PG_DIAG_MESSAGE_HINT 'H' +#define PG_DIAG_STATEMENT_POSITION 'P' +#define PG_DIAG_INTERNAL_POSITION 'p' +#define PG_DIAG_INTERNAL_QUERY 'q' +#define PG_DIAG_CONTEXT 'W' +#define PG_DIAG_SCHEMA_NAME 's' +#define PG_DIAG_TABLE_NAME 't' +#define PG_DIAG_COLUMN_NAME 'c' +#define PG_DIAG_DATATYPE_NAME 'd' +#define PG_DIAG_CONSTRAINT_NAME 'n' +#define PG_DIAG_SOURCE_FILE 'F' +#define PG_DIAG_SOURCE_LINE 'L' +#define PG_DIAG_SOURCE_FUNCTION 'R' + +#endif /* POSTGRES_EXT_H */ diff --git a/src/include/postgres_fe.h b/src/include/postgres_fe.h new file mode 100644 index 0000000..ece853c --- /dev/null +++ b/src/include/postgres_fe.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * postgres_fe.h + * Primary include file for PostgreSQL client-side .c files + * + * This should be the first file included by PostgreSQL client libraries and + * application programs --- but not by backend modules, which should include + * postgres.h. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1995, Regents of the University of California + * + * src/include/postgres_fe.h + * + *------------------------------------------------------------------------- + */ +#ifndef POSTGRES_FE_H +#define POSTGRES_FE_H + +#ifndef FRONTEND +#define FRONTEND 1 +#endif + +#include "c.h" + +#include "common/fe_memutils.h" + +#endif /* POSTGRES_FE_H */ diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h new file mode 100644 index 0000000..9d40fd6 --- /dev/null +++ b/src/include/postmaster/autovacuum.h @@ -0,0 +1,83 @@ +/*------------------------------------------------------------------------- + * + * autovacuum.h + * header file for integrated autovacuum daemon + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/postmaster/autovacuum.h + * + *------------------------------------------------------------------------- + */ +#ifndef AUTOVACUUM_H +#define AUTOVACUUM_H + +#include "storage/block.h" + +/* + * Other processes can request specific work from autovacuum, identified by + * AutoVacuumWorkItem elements. + */ +typedef enum +{ + AVW_BRINSummarizeRange +} AutoVacuumWorkItemType; + + +/* GUC variables */ +extern PGDLLIMPORT bool autovacuum_start_daemon; +extern PGDLLIMPORT int autovacuum_max_workers; +extern PGDLLIMPORT int autovacuum_work_mem; +extern PGDLLIMPORT int autovacuum_naptime; +extern PGDLLIMPORT int autovacuum_vac_thresh; +extern PGDLLIMPORT double autovacuum_vac_scale; +extern PGDLLIMPORT int autovacuum_vac_ins_thresh; +extern PGDLLIMPORT double autovacuum_vac_ins_scale; +extern PGDLLIMPORT int autovacuum_anl_thresh; +extern PGDLLIMPORT double autovacuum_anl_scale; +extern PGDLLIMPORT int autovacuum_freeze_max_age; +extern PGDLLIMPORT int autovacuum_multixact_freeze_max_age; +extern PGDLLIMPORT double autovacuum_vac_cost_delay; +extern PGDLLIMPORT int autovacuum_vac_cost_limit; + +/* autovacuum launcher PID, only valid when worker is shutting down */ +extern PGDLLIMPORT int AutovacuumLauncherPid; + +extern PGDLLIMPORT int Log_autovacuum_min_duration; + +/* Status inquiry functions */ +extern bool AutoVacuumingActive(void); +extern bool IsAutoVacuumLauncherProcess(void); +extern bool IsAutoVacuumWorkerProcess(void); + +#define IsAnyAutoVacuumProcess() \ + (IsAutoVacuumLauncherProcess() || IsAutoVacuumWorkerProcess()) + +/* Functions to start autovacuum process, called from postmaster */ +extern void autovac_init(void); +extern int StartAutoVacLauncher(void); +extern int StartAutoVacWorker(void); + +/* called from postmaster when a worker could not be forked */ +extern void AutoVacWorkerFailed(void); + +/* autovacuum cost-delay balancer */ +extern void AutoVacuumUpdateDelay(void); + +#ifdef EXEC_BACKEND +extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern void AutovacuumWorkerIAm(void); +extern void AutovacuumLauncherIAm(void); +#endif + +extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type, + Oid relationId, BlockNumber blkno); + +/* shared memory stuff */ +extern Size AutoVacuumShmemSize(void); +extern void AutoVacuumShmemInit(void); + +#endif /* AUTOVACUUM_H */ diff --git a/src/include/postmaster/auxprocess.h b/src/include/postmaster/auxprocess.h new file mode 100644 index 0000000..e3789fb --- /dev/null +++ b/src/include/postmaster/auxprocess.h @@ -0,0 +1,20 @@ +/*------------------------------------------------------------------------- + * auxprocess.h + * include file for functions related to auxiliary processes. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/postmaster/auxprocess.h + *------------------------------------------------------------------------- + */ +#ifndef AUXPROCESS_H +#define AUXPROCESS_H + +#include "miscadmin.h" + +extern void AuxiliaryProcessMain(AuxProcType auxtype) pg_attribute_noreturn(); + +#endif /* AUXPROCESS_H */ diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h new file mode 100644 index 0000000..96975bd --- /dev/null +++ b/src/include/postmaster/bgworker.h @@ -0,0 +1,162 @@ +/*-------------------------------------------------------------------- + * bgworker.h + * POSTGRES pluggable background workers interface + * + * A background worker is a process able to run arbitrary, user-supplied code, + * including normal transactions. + * + * Any external module loaded via shared_preload_libraries can register a + * worker. Workers can also be registered dynamically at runtime. In either + * case, the worker process is forked from the postmaster and runs the + * user-supplied "main" function. This code may connect to a database and + * run transactions. Workers can remain active indefinitely, but will be + * terminated if a shutdown or crash occurs. + * + * If the fork() call fails in the postmaster, it will try again later. Note + * that the failure can only be transient (fork failure due to high load, + * memory pressure, too many processes, etc); more permanent problems, like + * failure to connect to a database, are detected later in the worker and dealt + * with just by having the worker exit normally. A worker which exits with + * a return code of 0 will never be restarted and will be removed from worker + * list. A worker which exits with a return code of 1 will be restarted after + * the configured restart interval (unless that interval is BGW_NEVER_RESTART). + * The TerminateBackgroundWorker() function can be used to terminate a + * dynamically registered background worker; the worker will be sent a SIGTERM + * and will not be restarted after it exits. Whenever the postmaster knows + * that a worker will not be restarted, it unregisters the worker, freeing up + * that worker's slot for use by a new worker. + * + * Note that there might be more than one worker in a database concurrently, + * and the same module may request more than one worker running the same (or + * different) code. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/postmaster/bgworker.h + *-------------------------------------------------------------------- + */ +#ifndef BGWORKER_H +#define BGWORKER_H + +/*--------------------------------------------------------------------- + * External module API. + *--------------------------------------------------------------------- + */ + +/* + * Pass this flag to have your worker be able to connect to shared memory. + * This flag is required. + */ +#define BGWORKER_SHMEM_ACCESS 0x0001 + +/* + * This flag means the bgworker requires a database connection. The connection + * is not established automatically; the worker must establish it later. + * It requires that BGWORKER_SHMEM_ACCESS was passed too. + */ +#define BGWORKER_BACKEND_DATABASE_CONNECTION 0x0002 + +/* + * This class is used internally for parallel queries, to keep track of the + * number of active parallel workers and make sure we never launch more than + * max_parallel_workers parallel workers at the same time. Third party + * background workers should not use this class. + */ +#define BGWORKER_CLASS_PARALLEL 0x0010 +/* add additional bgworker classes here */ + + +typedef void (*bgworker_main_type) (Datum main_arg); + +/* + * Points in time at which a bgworker can request to be started + */ +typedef enum +{ + BgWorkerStart_PostmasterStart, + BgWorkerStart_ConsistentState, + BgWorkerStart_RecoveryFinished +} BgWorkerStartTime; + +#define BGW_DEFAULT_RESTART_INTERVAL 60 +#define BGW_NEVER_RESTART -1 +#define BGW_MAXLEN 96 +#define BGW_EXTRALEN 128 + +typedef struct BackgroundWorker +{ + char bgw_name[BGW_MAXLEN]; + char bgw_type[BGW_MAXLEN]; + int bgw_flags; + BgWorkerStartTime bgw_start_time; + int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */ + char bgw_library_name[BGW_MAXLEN]; + char bgw_function_name[BGW_MAXLEN]; + Datum bgw_main_arg; + char bgw_extra[BGW_EXTRALEN]; + pid_t bgw_notify_pid; /* SIGUSR1 this backend on start/stop */ +} BackgroundWorker; + +typedef enum BgwHandleStatus +{ + BGWH_STARTED, /* worker is running */ + BGWH_NOT_YET_STARTED, /* worker hasn't been started yet */ + BGWH_STOPPED, /* worker has exited */ + BGWH_POSTMASTER_DIED /* postmaster died; worker status unclear */ +} BgwHandleStatus; + +struct BackgroundWorkerHandle; +typedef struct BackgroundWorkerHandle BackgroundWorkerHandle; + +/* Register a new bgworker during shared_preload_libraries */ +extern void RegisterBackgroundWorker(BackgroundWorker *worker); + +/* Register a new bgworker from a regular backend */ +extern bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, + BackgroundWorkerHandle **handle); + +/* Query the status of a bgworker */ +extern BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, + pid_t *pidp); +extern BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pid); +extern BgwHandleStatus + WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *); +extern const char *GetBackgroundWorkerTypeByPid(pid_t pid); + +/* Terminate a bgworker */ +extern void TerminateBackgroundWorker(BackgroundWorkerHandle *handle); + +/* This is valid in a running worker */ +extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry; + +/* + * Connect to the specified database, as the specified user. Only a worker + * that passed BGWORKER_BACKEND_DATABASE_CONNECTION during registration may + * call this. + * + * If username is NULL, bootstrapping superuser is used. + * If dbname is NULL, connection is made to no specific database; + * only shared catalogs can be accessed. + */ +extern void BackgroundWorkerInitializeConnection(const char *dbname, const char *username, uint32 flags); + +/* Just like the above, but specifying database and user by OID. */ +extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags); + +/* + * Flags to BackgroundWorkerInitializeConnection et al + * + * + * Allow bypassing datallowconn restrictions when connecting to database + */ +#define BGWORKER_BYPASS_ALLOWCONN 1 + + +/* Block/unblock signals in a background worker process */ +extern void BackgroundWorkerBlockSignals(void); +extern void BackgroundWorkerUnblockSignals(void); + +#endif /* BGWORKER_H */ diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h new file mode 100644 index 0000000..3876835 --- /dev/null +++ b/src/include/postmaster/bgworker_internals.h @@ -0,0 +1,64 @@ +/*-------------------------------------------------------------------- + * bgworker_internals.h + * POSTGRES pluggable background workers internals + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/postmaster/bgworker_internals.h + *-------------------------------------------------------------------- + */ +#ifndef BGWORKER_INTERNALS_H +#define BGWORKER_INTERNALS_H + +#include "datatype/timestamp.h" +#include "lib/ilist.h" +#include "postmaster/bgworker.h" + +/* GUC options */ + +/* + * Maximum possible value of parallel workers. + */ +#define MAX_PARALLEL_WORKER_LIMIT 1024 + +/* + * List of background workers, private to postmaster. + * + * A worker that requests a database connection during registration will have + * rw_backend set, and will be present in BackendList. Note: do not rely on + * rw_backend being non-NULL for shmem-connected workers! + */ +typedef struct RegisteredBgWorker +{ + BackgroundWorker rw_worker; /* its registry entry */ + struct bkend *rw_backend; /* its BackendList entry, or NULL */ + pid_t rw_pid; /* 0 if not running */ + int rw_child_slot; + TimestampTz rw_crashed_at; /* if not 0, time it last crashed */ + int rw_shmem_slot; + bool rw_terminate; + slist_node rw_lnode; /* list link */ +} RegisteredBgWorker; + +extern PGDLLIMPORT slist_head BackgroundWorkerList; + +extern Size BackgroundWorkerShmemSize(void); +extern void BackgroundWorkerShmemInit(void); +extern void BackgroundWorkerStateChange(bool allow_new_workers); +extern void ForgetBackgroundWorker(slist_mutable_iter *cur); +extern void ReportBackgroundWorkerPID(RegisteredBgWorker *); +extern void ReportBackgroundWorkerExit(slist_mutable_iter *cur); +extern void BackgroundWorkerStopNotifications(pid_t pid); +extern void ForgetUnstartedBackgroundWorkers(void); +extern void ResetBackgroundWorkerCrashTimes(void); + +/* Function to start a background worker, called from postmaster.c */ +extern void StartBackgroundWorker(void) pg_attribute_noreturn(); + +#ifdef EXEC_BACKEND +extern BackgroundWorker *BackgroundWorkerEntry(int slotno); +#endif + +#endif /* BGWORKER_INTERNALS_H */ diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h new file mode 100644 index 0000000..2511ef4 --- /dev/null +++ b/src/include/postmaster/bgwriter.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * bgwriter.h + * Exports from postmaster/bgwriter.c and postmaster/checkpointer.c. + * + * The bgwriter process used to handle checkpointing duties too. Now + * there is a separate process, but we did not bother to split this header. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/postmaster/bgwriter.h + * + *------------------------------------------------------------------------- + */ +#ifndef _BGWRITER_H +#define _BGWRITER_H + +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "storage/smgr.h" +#include "storage/sync.h" + + +/* GUC options */ +extern PGDLLIMPORT int BgWriterDelay; +extern PGDLLIMPORT int CheckPointTimeout; +extern PGDLLIMPORT int CheckPointWarning; +extern PGDLLIMPORT double CheckPointCompletionTarget; + +extern void BackgroundWriterMain(void) pg_attribute_noreturn(); +extern void CheckpointerMain(void) pg_attribute_noreturn(); + +extern void RequestCheckpoint(int flags); +extern void CheckpointWriteDelay(int flags, double progress); + +extern bool ForwardSyncRequest(const FileTag *ftag, SyncRequestType type); + +extern void AbsorbSyncRequests(void); + +extern Size CheckpointerShmemSize(void); +extern void CheckpointerShmemInit(void); + +extern bool FirstCallSinceLastCheckpoint(void); + +#endif /* _BGWRITER_H */ diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h new file mode 100644 index 0000000..5fc8490 --- /dev/null +++ b/src/include/postmaster/fork_process.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * fork_process.h + * Exports from postmaster/fork_process.c. + * + * Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/postmaster/fork_process.h + * + *------------------------------------------------------------------------- + */ +#ifndef FORK_PROCESS_H +#define FORK_PROCESS_H + +extern pid_t fork_process(void); + +#endif /* FORK_PROCESS_H */ diff --git a/src/include/postmaster/interrupt.h b/src/include/postmaster/interrupt.h new file mode 100644 index 0000000..289e045 --- /dev/null +++ b/src/include/postmaster/interrupt.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * interrupt.h + * Interrupt handling routines. + * + * Responses to interrupts are fairly varied and many types of backends + * have their own implementations, but we provide a few generic things + * here to facilitate code reuse. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/postmaster/interrupt.h + * + *------------------------------------------------------------------------- + */ + +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include <signal.h> + +extern PGDLLIMPORT volatile sig_atomic_t ConfigReloadPending; +extern PGDLLIMPORT volatile sig_atomic_t ShutdownRequestPending; + +extern void HandleMainLoopInterrupts(void); +extern void SignalHandlerForConfigReload(SIGNAL_ARGS); +extern void SignalHandlerForCrashExit(SIGNAL_ARGS); +extern void SignalHandlerForShutdownRequest(SIGNAL_ARGS); + +#endif diff --git a/src/include/postmaster/pgarch.h b/src/include/postmaster/pgarch.h new file mode 100644 index 0000000..f366a15 --- /dev/null +++ b/src/include/postmaster/pgarch.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * pgarch.h + * Exports from postmaster/pgarch.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/postmaster/pgarch.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PGARCH_H +#define _PGARCH_H + +/* ---------- + * Archiver control info. + * + * We expect that archivable files within pg_wal will have names between + * MIN_XFN_CHARS and MAX_XFN_CHARS in length, consisting only of characters + * appearing in VALID_XFN_CHARS. The status files in archive_status have + * corresponding names with ".ready" or ".done" appended. + * ---------- + */ +#define MIN_XFN_CHARS 16 +#define MAX_XFN_CHARS 40 +#define VALID_XFN_CHARS "0123456789ABCDEF.history.backup.partial" + +extern Size PgArchShmemSize(void); +extern void PgArchShmemInit(void); +extern bool PgArchCanRestart(void); +extern void PgArchiverMain(void) pg_attribute_noreturn(); +extern void PgArchWakeup(void); +extern void PgArchForceDirScan(void); + +/* + * The value of the archive_library GUC. + */ +extern PGDLLIMPORT char *XLogArchiveLibrary; + +/* + * Archive module callbacks + * + * These callback functions should be defined by archive libraries and returned + * via _PG_archive_module_init(). ArchiveFileCB is the only required callback. + * For more information about the purpose of each callback, refer to the + * archive modules documentation. + */ +typedef bool (*ArchiveCheckConfiguredCB) (void); +typedef bool (*ArchiveFileCB) (const char *file, const char *path); +typedef void (*ArchiveShutdownCB) (void); + +typedef struct ArchiveModuleCallbacks +{ + ArchiveCheckConfiguredCB check_configured_cb; + ArchiveFileCB archive_file_cb; + ArchiveShutdownCB shutdown_cb; +} ArchiveModuleCallbacks; + +/* + * Type of the shared library symbol _PG_archive_module_init that is looked + * up when loading an archive library. + */ +typedef void (*ArchiveModuleInit) (ArchiveModuleCallbacks *cb); + +/* + * Since the logic for archiving via a shell command is in the core server + * and does not need to be loaded via a shared library, it has a special + * initialization function. + */ +extern void shell_archive_init(ArchiveModuleCallbacks *cb); + +#endif /* _PGARCH_H */ diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h new file mode 100644 index 0000000..90e333c --- /dev/null +++ b/src/include/postmaster/postmaster.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + * + * postmaster.h + * Exports from postmaster/postmaster.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/postmaster/postmaster.h + * + *------------------------------------------------------------------------- + */ +#ifndef _POSTMASTER_H +#define _POSTMASTER_H + +/* GUC options */ +extern PGDLLIMPORT bool EnableSSL; +extern PGDLLIMPORT int ReservedBackends; +extern PGDLLIMPORT int PostPortNumber; +extern PGDLLIMPORT int Unix_socket_permissions; +extern PGDLLIMPORT char *Unix_socket_group; +extern PGDLLIMPORT char *Unix_socket_directories; +extern PGDLLIMPORT char *ListenAddresses; +extern PGDLLIMPORT bool ClientAuthInProgress; +extern PGDLLIMPORT int PreAuthDelay; +extern PGDLLIMPORT int AuthenticationTimeout; +extern PGDLLIMPORT bool Log_connections; +extern PGDLLIMPORT bool log_hostname; +extern PGDLLIMPORT bool enable_bonjour; +extern PGDLLIMPORT char *bonjour_name; +extern PGDLLIMPORT bool restart_after_crash; +extern PGDLLIMPORT bool remove_temp_files_after_crash; + +#ifdef WIN32 +extern PGDLLIMPORT HANDLE PostmasterHandle; +#else +extern PGDLLIMPORT int postmaster_alive_fds[2]; + +/* + * Constants that represent which of postmaster_alive_fds is held by + * postmaster, and which is used in children to check for postmaster death. + */ +#define POSTMASTER_FD_WATCH 0 /* used in children to check for + * postmaster death */ +#define POSTMASTER_FD_OWN 1 /* kept open by postmaster only */ +#endif + +extern PGDLLIMPORT const char *progname; + +extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); +extern void ClosePostmasterPorts(bool am_syslogger); +extern void InitProcessGlobals(void); + +extern int MaxLivePostmasterChildren(void); + +extern bool PostmasterMarkPIDForWorkerNotify(int); + +#ifdef EXEC_BACKEND +extern pid_t postmaster_forkexec(int argc, char *argv[]); +extern void SubPostmasterMain(int argc, char *argv[]) pg_attribute_noreturn(); + +extern Size ShmemBackendArraySize(void); +extern void ShmemBackendArrayAllocation(void); +#endif + +/* + * Note: MAX_BACKENDS is limited to 2^18-1 because that's the width reserved + * for buffer references in buf_internals.h. This limitation could be lifted + * by using a 64bit state; but it's unlikely to be worthwhile as 2^18-1 + * backends exceed currently realistic configurations. Even if that limitation + * were removed, we still could not a) exceed 2^23-1 because inval.c stores + * the backend ID as a 3-byte signed integer, b) INT_MAX/4 because some places + * compute 4*MaxBackends without any overflow check. This is rechecked in the + * relevant GUC check hooks and in RegisterBackgroundWorker(). + */ +#define MAX_BACKENDS 0x3FFFF + +#endif /* _POSTMASTER_H */ diff --git a/src/include/postmaster/startup.h b/src/include/postmaster/startup.h new file mode 100644 index 0000000..1289753 --- /dev/null +++ b/src/include/postmaster/startup.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * startup.h + * Exports from postmaster/startup.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/postmaster/startup.h + * + *------------------------------------------------------------------------- + */ +#ifndef _STARTUP_H +#define _STARTUP_H + +/* + * Log the startup progress message if a timer has expired. + */ +#define ereport_startup_progress(msg, ...) \ + do { \ + long secs; \ + int usecs; \ + if (has_startup_progress_timeout_expired(&secs, &usecs)) \ + ereport(LOG, errmsg(msg, secs, (usecs / 10000), __VA_ARGS__ )); \ + } while(0) + +extern PGDLLIMPORT int log_startup_progress_interval; + +extern void HandleStartupProcInterrupts(void); +extern void StartupProcessMain(void) pg_attribute_noreturn(); +extern void PreRestoreCommand(void); +extern void PostRestoreCommand(void); +extern bool IsPromoteSignaled(void); +extern void ResetPromoteSignaled(void); + +extern void enable_startup_progress_timeout(void); +extern void disable_startup_progress_timeout(void); +extern void begin_startup_progress_phase(void); +extern void startup_progress_timeout_handler(void); +extern bool has_startup_progress_timeout_expired(long *secs, int *usecs); + +#endif /* _STARTUP_H */ diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h new file mode 100644 index 0000000..6436724 --- /dev/null +++ b/src/include/postmaster/syslogger.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------- + * + * syslogger.h + * Exports from postmaster/syslogger.c. + * + * Copyright (c) 2004-2022, PostgreSQL Global Development Group + * + * src/include/postmaster/syslogger.h + * + *------------------------------------------------------------------------- + */ +#ifndef _SYSLOGGER_H +#define _SYSLOGGER_H + +#include <limits.h> /* for PIPE_BUF */ + + +/* + * Primitive protocol structure for writing to syslogger pipe(s). The idea + * here is to divide long messages into chunks that are not more than + * PIPE_BUF bytes long, which according to POSIX spec must be written into + * the pipe atomically. The pipe reader then uses the protocol headers to + * reassemble the parts of a message into a single string. The reader can + * also cope with non-protocol data coming down the pipe, though we cannot + * guarantee long strings won't get split apart. + * + * We use non-nul bytes in is_last to make the protocol a tiny bit + * more robust against finding a false double nul byte prologue. But + * we still might find it in the len and/or pid bytes unless we're careful. + */ + +#ifdef PIPE_BUF +/* Are there any systems with PIPE_BUF > 64K? Unlikely, but ... */ +#if PIPE_BUF > 65536 +#define PIPE_CHUNK_SIZE 65536 +#else +#define PIPE_CHUNK_SIZE ((int) PIPE_BUF) +#endif +#else /* not defined */ +/* POSIX says the value of PIPE_BUF must be at least 512, so use that */ +#define PIPE_CHUNK_SIZE 512 +#endif + +typedef struct +{ + char nuls[2]; /* always \0\0 */ + uint16 len; /* size of this chunk (counts data only) */ + int32 pid; /* writer's pid */ + bits8 flags; /* bitmask of PIPE_PROTO_* */ + char data[FLEXIBLE_ARRAY_MEMBER]; /* data payload starts here */ +} PipeProtoHeader; + +typedef union +{ + PipeProtoHeader proto; + char filler[PIPE_CHUNK_SIZE]; +} PipeProtoChunk; + +#define PIPE_HEADER_SIZE offsetof(PipeProtoHeader, data) +#define PIPE_MAX_PAYLOAD ((int) (PIPE_CHUNK_SIZE - PIPE_HEADER_SIZE)) + +/* flag bits for PipeProtoHeader->flags */ +#define PIPE_PROTO_IS_LAST 0x01 /* last chunk of message? */ +/* log destinations */ +#define PIPE_PROTO_DEST_STDERR 0x10 +#define PIPE_PROTO_DEST_CSVLOG 0x20 +#define PIPE_PROTO_DEST_JSONLOG 0x40 + +/* GUC options */ +extern PGDLLIMPORT bool Logging_collector; +extern PGDLLIMPORT int Log_RotationAge; +extern PGDLLIMPORT int Log_RotationSize; +extern PGDLLIMPORT char *Log_directory; +extern PGDLLIMPORT char *Log_filename; +extern PGDLLIMPORT bool Log_truncate_on_rotation; +extern PGDLLIMPORT int Log_file_mode; + +#ifndef WIN32 +extern PGDLLIMPORT int syslogPipe[2]; +#else +extern PGDLLIMPORT HANDLE syslogPipe[2]; +#endif + + +extern int SysLogger_Start(void); + +extern void write_syslogger_file(const char *buffer, int count, int dest); + +#ifdef EXEC_BACKEND +extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn(); +#endif + +extern bool CheckLogrotateSignal(void); +extern void RemoveLogrotateSignalFiles(void); + +/* + * Name of files saving meta-data information about the log + * files currently in use by the syslogger + */ +#define LOG_METAINFO_DATAFILE "current_logfiles" +#define LOG_METAINFO_DATAFILE_TMP LOG_METAINFO_DATAFILE ".tmp" + +#endif /* _SYSLOGGER_H */ diff --git a/src/include/postmaster/walwriter.h b/src/include/postmaster/walwriter.h new file mode 100644 index 0000000..ddc9436 --- /dev/null +++ b/src/include/postmaster/walwriter.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * walwriter.h + * Exports from postmaster/walwriter.c. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/postmaster/walwriter.h + * + *------------------------------------------------------------------------- + */ +#ifndef _WALWRITER_H +#define _WALWRITER_H + +/* GUC options */ +extern PGDLLIMPORT int WalWriterDelay; +extern PGDLLIMPORT int WalWriterFlushAfter; + +extern void WalWriterMain(void) pg_attribute_noreturn(); + +#endif /* _WALWRITER_H */ diff --git a/src/include/regex/regcustom.h b/src/include/regex/regcustom.h new file mode 100644 index 0000000..100c52d --- /dev/null +++ b/src/include/regex/regcustom.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. + * + * Development of this software was funded, in part, by Cray Research Inc., + * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics + * Corporation, none of whom are responsible for the results. The author + * thanks all of them. + * + * Redistribution and use in source and binary forms -- with or without + * modification -- are permitted for any purpose, provided that + * redistributions in source form retain this entire copyright notice and + * indicate the origin and nature of any modifications. + * + * I'd appreciate being given credit for this package in the documentation + * of software which uses it, but that is not a requirement. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * src/include/regex/regcustom.h + */ + +/* headers if any */ + +/* + * It's against Postgres coding conventions to include postgres.h in a + * header file, but we allow the violation here because the regexp library + * files specifically intend this file to supply application-dependent + * headers, and are careful to include this file before anything else. + */ +#include "postgres.h" + +#include <ctype.h> +#include <limits.h> + +/* + * towlower() and friends should be in <wctype.h>, but some pre-C99 systems + * declare them in <wchar.h>, so include that too. + */ +#include <wchar.h> +#ifdef HAVE_WCTYPE_H +#include <wctype.h> +#endif + +#include "mb/pg_wchar.h" + +#include "miscadmin.h" /* needed by rcancelrequested/rstacktoodeep */ + + +/* overrides for regguts.h definitions, if any */ +#define FUNCPTR(name, args) (*name) args +#define MALLOC(n) malloc(n) +#define FREE(p) free(VS(p)) +#define REALLOC(p,n) realloc(VS(p),n) +#define assert(x) Assert(x) + +/* internal character type and related */ +typedef pg_wchar chr; /* the type itself */ +typedef unsigned uchr; /* unsigned type that will hold a chr */ + +#define CHR(c) ((unsigned char) (c)) /* turn char literal into chr literal */ +#define DIGITVAL(c) ((c)-'0') /* turn chr digit into its value */ +#define CHRBITS 32 /* bits in a chr; must not use sizeof */ +#define CHR_MIN 0x00000000 /* smallest and largest chr; the value */ +#define CHR_MAX 0x7ffffffe /* CHR_MAX-CHR_MIN+1 must fit in an int, and + * CHR_MAX+1 must fit in a chr variable */ + +/* + * Check if a chr value is in range. Ideally we'd just write this as + * ((c) >= CHR_MIN && (c) <= CHR_MAX) + * However, if chr is unsigned and CHR_MIN is zero, the first part of that + * is a no-op, and certain overly-nannyish compilers give warnings about it. + * So we leave that out here. If you want to make chr signed and/or CHR_MIN + * not zero, redefine this macro as above. Callers should assume that the + * macro may multiply evaluate its argument, even though it does not today. + */ +#define CHR_IS_IN_RANGE(c) ((c) <= CHR_MAX) + +/* + * MAX_SIMPLE_CHR is the cutoff between "simple" and "complicated" processing + * in the color map logic. It should usually be chosen high enough to ensure + * that all common characters are <= MAX_SIMPLE_CHR. However, very large + * values will be counterproductive since they cause more regex setup time. + * Also, small values can be helpful for testing the high-color-map logic + * with plain old ASCII input. + */ +#define MAX_SIMPLE_CHR 0x7FF /* suitable value for Unicode */ + +/* functions operating on chr */ +#define iscalnum(x) pg_wc_isalnum(x) +#define iscalpha(x) pg_wc_isalpha(x) +#define iscdigit(x) pg_wc_isdigit(x) +#define iscspace(x) pg_wc_isspace(x) + +/* and pick up the standard header */ +#include "regex.h" diff --git a/src/include/regex/regerrs.h b/src/include/regex/regerrs.h new file mode 100644 index 0000000..41e25f7 --- /dev/null +++ b/src/include/regex/regerrs.h @@ -0,0 +1,87 @@ +/* + * src/include/regex/regerrs.h + */ + +{ + REG_OKAY, "REG_OKAY", "no errors detected" +}, + +{ + REG_NOMATCH, "REG_NOMATCH", "failed to match" +}, + +{ + REG_BADPAT, "REG_BADPAT", "invalid regexp (reg version 0.8)" +}, + +{ + REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" +}, + +{ + REG_ECTYPE, "REG_ECTYPE", "invalid character class" +}, + +{ + REG_EESCAPE, "REG_EESCAPE", "invalid escape \\ sequence" +}, + +{ + REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" +}, + +{ + REG_EBRACK, "REG_EBRACK", "brackets [] not balanced" +}, + +{ + REG_EPAREN, "REG_EPAREN", "parentheses () not balanced" +}, + +{ + REG_EBRACE, "REG_EBRACE", "braces {} not balanced" +}, + +{ + REG_BADBR, "REG_BADBR", "invalid repetition count(s)" +}, + +{ + REG_ERANGE, "REG_ERANGE", "invalid character range" +}, + +{ + REG_ESPACE, "REG_ESPACE", "out of memory" +}, + +{ + REG_BADRPT, "REG_BADRPT", "quantifier operand invalid" +}, + +{ + REG_ASSERT, "REG_ASSERT", "\"cannot happen\" -- you found a bug" +}, + +{ + REG_INVARG, "REG_INVARG", "invalid argument to regex function" +}, + +{ + REG_MIXED, "REG_MIXED", "character widths of regex and string differ" +}, + +{ + REG_BADOPT, "REG_BADOPT", "invalid embedded option" +}, + +{ + REG_ETOOBIG, "REG_ETOOBIG", "regular expression is too complex" +}, + +{ + REG_ECOLORS, "REG_ECOLORS", "too many colors" +}, + +{ + REG_CANCEL, "REG_CANCEL", "operation cancelled" +}, diff --git a/src/include/regex/regex.h b/src/include/regex/regex.h new file mode 100644 index 0000000..0455ae8 --- /dev/null +++ b/src/include/regex/regex.h @@ -0,0 +1,186 @@ +#ifndef _REGEX_H_ +#define _REGEX_H_ /* never again */ +/* + * regular expressions + * + * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. + * + * Development of this software was funded, in part, by Cray Research Inc., + * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics + * Corporation, none of whom are responsible for the results. The author + * thanks all of them. + * + * Redistribution and use in source and binary forms -- with or without + * modification -- are permitted for any purpose, provided that + * redistributions in source form retain this entire copyright notice and + * indicate the origin and nature of any modifications. + * + * I'd appreciate being given credit for this package in the documentation + * of software which uses it, but that is not a requirement. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * src/include/regex/regex.h + */ + +/* + * Add your own defines, if needed, here. + */ +#include "mb/pg_wchar.h" + +/* + * interface types etc. + */ + +/* + * regoff_t has to be large enough to hold either off_t or ssize_t, + * and must be signed; it's only a guess that long is suitable. + */ +typedef long regoff_t; + +/* + * other interface types + */ + +/* the biggie, a compiled RE (or rather, a front end to same) */ +typedef struct +{ + int re_magic; /* magic number */ + size_t re_nsub; /* number of subexpressions */ + long re_info; /* bitmask of the following flags: */ +#define REG_UBACKREF 000001 /* has back-reference (\n) */ +#define REG_ULOOKAROUND 000002 /* has lookahead/lookbehind constraint */ +#define REG_UBOUNDS 000004 /* has bounded quantifier ({m,n}) */ +#define REG_UBRACES 000010 /* has { that doesn't begin a quantifier */ +#define REG_UBSALNUM 000020 /* has backslash-alphanumeric in non-ARE */ +#define REG_UPBOTCH 000040 /* has unmatched right paren in ERE (legal + * per spec, but that was a mistake) */ +#define REG_UBBS 000100 /* has backslash within bracket expr */ +#define REG_UNONPOSIX 000200 /* has any construct that extends POSIX */ +#define REG_UUNSPEC 000400 /* has any case disallowed by POSIX, e.g. + * an empty branch */ +#define REG_UUNPORT 001000 /* has numeric character code dependency */ +#define REG_ULOCALE 002000 /* has locale dependency */ +#define REG_UEMPTYMATCH 004000 /* can match a zero-length string */ +#define REG_UIMPOSSIBLE 010000 /* provably cannot match anything */ +#define REG_USHORTEST 020000 /* has non-greedy quantifier */ + int re_csize; /* sizeof(character) */ + char *re_endp; /* backward compatibility kludge */ + Oid re_collation; /* Collation that defines LC_CTYPE behavior */ + /* the rest is opaque pointers to hidden innards */ + char *re_guts; /* `char *' is more portable than `void *' */ + char *re_fns; +} regex_t; + +/* result reporting (may acquire more fields later) */ +typedef struct +{ + regoff_t rm_so; /* start of substring */ + regoff_t rm_eo; /* end of substring */ +} regmatch_t; + +/* supplementary control and reporting */ +typedef struct +{ + regmatch_t rm_extend; /* see REG_EXPECT */ +} rm_detail_t; + + + +/* + * regex compilation flags + */ +#define REG_BASIC 000000 /* BREs (convenience) */ +#define REG_EXTENDED 000001 /* EREs */ +#define REG_ADVF 000002 /* advanced features in EREs */ +#define REG_ADVANCED 000003 /* AREs (which are also EREs) */ +#define REG_QUOTE 000004 /* no special characters, none */ +#define REG_NOSPEC REG_QUOTE /* historical synonym */ +#define REG_ICASE 000010 /* ignore case */ +#define REG_NOSUB 000020 /* caller doesn't need subexpr match data */ +#define REG_EXPANDED 000040 /* expanded format, white space & comments */ +#define REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */ +#define REG_NLANCH 000200 /* ^ matches after \n, $ before */ +#define REG_NEWLINE 000300 /* newlines are line terminators */ +#define REG_PEND 000400 /* ugh -- backward-compatibility hack */ +#define REG_EXPECT 001000 /* report details on partial/limited matches */ +#define REG_BOSONLY 002000 /* temporary kludge for BOS-only matches */ +#define REG_DUMP 004000 /* none of your business :-) */ +#define REG_FAKE 010000 /* none of your business :-) */ +#define REG_PROGRESS 020000 /* none of your business :-) */ + + + +/* + * regex execution flags + */ +#define REG_NOTBOL 0001 /* BOS is not BOL */ +#define REG_NOTEOL 0002 /* EOS is not EOL */ +#define REG_STARTEND 0004 /* backward compatibility kludge */ +#define REG_FTRACE 0010 /* none of your business */ +#define REG_MTRACE 0020 /* none of your business */ +#define REG_SMALL 0040 /* none of your business */ + + +/* + * error reporting + * Be careful if modifying the list of error codes -- the table used by + * regerror() is generated automatically from this file! + */ +#define REG_OKAY 0 /* no errors detected */ +#define REG_NOMATCH 1 /* failed to match */ +#define REG_BADPAT 2 /* invalid regexp */ +#define REG_ECOLLATE 3 /* invalid collating element */ +#define REG_ECTYPE 4 /* invalid character class */ +#define REG_EESCAPE 5 /* invalid escape \ sequence */ +#define REG_ESUBREG 6 /* invalid backreference number */ +#define REG_EBRACK 7 /* brackets [] not balanced */ +#define REG_EPAREN 8 /* parentheses () not balanced */ +#define REG_EBRACE 9 /* braces {} not balanced */ +#define REG_BADBR 10 /* invalid repetition count(s) */ +#define REG_ERANGE 11 /* invalid character range */ +#define REG_ESPACE 12 /* out of memory */ +#define REG_BADRPT 13 /* quantifier operand invalid */ +#define REG_ASSERT 15 /* "can't happen" -- you found a bug */ +#define REG_INVARG 16 /* invalid argument to regex function */ +#define REG_MIXED 17 /* character widths of regex and string differ */ +#define REG_BADOPT 18 /* invalid embedded option */ +#define REG_ETOOBIG 19 /* regular expression is too complex */ +#define REG_ECOLORS 20 /* too many colors */ +#define REG_CANCEL 21 /* operation cancelled */ +/* two specials for debugging and testing */ +#define REG_ATOI 101 /* convert error-code name to number */ +#define REG_ITOA 102 /* convert error-code number to name */ +/* non-error result codes for pg_regprefix */ +#define REG_PREFIX (-1) /* identified a common prefix */ +#define REG_EXACT (-2) /* identified an exact match */ + + + +/* + * the prototypes for exported functions + */ + +/* regcomp.c */ +extern int pg_regcomp(regex_t *, const pg_wchar *, size_t, int, Oid); +extern int pg_regexec(regex_t *, const pg_wchar *, size_t, size_t, rm_detail_t *, size_t, regmatch_t[], int); +extern int pg_regprefix(regex_t *, pg_wchar **, size_t *); +extern void pg_regfree(regex_t *); +extern size_t pg_regerror(int, const regex_t *, char *, size_t); + +/* regexp.c */ +extern regex_t *RE_compile_and_cache(text *text_re, int cflags, Oid collation); +extern bool RE_compile_and_execute(text *text_re, char *dat, int dat_len, + int cflags, Oid collation, + int nmatch, regmatch_t *pmatch); + +#endif /* _REGEX_H_ */ diff --git a/src/include/regex/regexport.h b/src/include/regex/regexport.h new file mode 100644 index 0000000..4ac1064 --- /dev/null +++ b/src/include/regex/regexport.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * regexport.h + * Declarations for exporting info about a regex's NFA (nondeterministic + * finite automaton) + * + * The functions declared here provide accessors to extract the NFA state + * graph and color character sets of a successfully-compiled regex. + * + * An NFA contains one or more states, numbered 0..N-1. There is an initial + * state, as well as a final state --- reaching the final state denotes + * successful matching of an input string. Each state except the final one + * has some out-arcs that lead to successor states, each arc being labeled + * with a color that represents one or more concrete character codes. + * (The colors of a state's out-arcs need not be distinct, since this is an + * NFA not a DFA.) There are also "pseudocolors" representing start/end of + * line and start/end of string. Colors are numbered 0..C-1, but note that + * color 0 is "white" (all unused characters) and can generally be ignored. + * + * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1998, 1999 Henry Spencer + * + * IDENTIFICATION + * src/include/regex/regexport.h + * + *------------------------------------------------------------------------- + */ +#ifndef _REGEXPORT_H_ +#define _REGEXPORT_H_ + +#include "regex/regex.h" + +/* These macros must match corresponding ones in regguts.h: */ +#define COLOR_WHITE 0 /* color for chars not appearing in regex */ +#define COLOR_RAINBOW (-2) /* represents all colors except pseudocolors */ + +/* information about one arc of a regex's NFA */ +typedef struct +{ + int co; /* label (character-set color) of arc */ + int to; /* next state number */ +} regex_arc_t; + + +/* Functions for gathering information about NFA states and arcs */ +extern int pg_reg_getnumstates(const regex_t *regex); +extern int pg_reg_getinitialstate(const regex_t *regex); +extern int pg_reg_getfinalstate(const regex_t *regex); +extern int pg_reg_getnumoutarcs(const regex_t *regex, int st); +extern void pg_reg_getoutarcs(const regex_t *regex, int st, + regex_arc_t *arcs, int arcs_len); + +/* Functions for gathering information about colors */ +extern int pg_reg_getnumcolors(const regex_t *regex); +extern int pg_reg_colorisbegin(const regex_t *regex, int co); +extern int pg_reg_colorisend(const regex_t *regex, int co); +extern int pg_reg_getnumcharacters(const regex_t *regex, int co); +extern void pg_reg_getcharacters(const regex_t *regex, int co, + pg_wchar *chars, int chars_len); + +#endif /* _REGEXPORT_H_ */ diff --git a/src/include/regex/regguts.h b/src/include/regex/regguts.h new file mode 100644 index 0000000..91a5284 --- /dev/null +++ b/src/include/regex/regguts.h @@ -0,0 +1,547 @@ +/* + * Internal interface definitions, etc., for the reg package + * + * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. + * + * Development of this software was funded, in part, by Cray Research Inc., + * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics + * Corporation, none of whom are responsible for the results. The author + * thanks all of them. + * + * Redistribution and use in source and binary forms -- with or without + * modification -- are permitted for any purpose, provided that + * redistributions in source form retain this entire copyright notice and + * indicate the origin and nature of any modifications. + * + * I'd appreciate being given credit for this package in the documentation + * of software which uses it, but that is not a requirement. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * src/include/regex/regguts.h + */ + + + +/* + * Environmental customization. It should not (I hope) be necessary to + * alter the file you are now reading -- regcustom.h should handle it all, + * given care here and elsewhere. + */ +#include "regcustom.h" + + + +/* + * Things that regcustom.h might override. + */ + +/* assertions */ +#ifndef assert +#ifndef REG_DEBUG +#define NDEBUG /* no assertions */ +#endif +#include <assert.h> +#endif + +/* voids */ +#ifndef DISCARD +#define DISCARD void /* for throwing values away */ +#endif +#ifndef VS +#define VS(x) ((void *)(x)) /* cast something to generic ptr */ +#endif + +/* function-pointer declarator */ +#ifndef FUNCPTR +#define FUNCPTR(name, args) (*(name)) args +#endif + +/* memory allocation */ +#ifndef MALLOC +#define MALLOC(n) malloc(n) +#endif +#ifndef REALLOC +#define REALLOC(p, n) realloc(VS(p), n) +#endif +#ifndef FREE +#define FREE(p) free(VS(p)) +#endif + +/* want size of a char in bits, and max value in bounded quantifiers */ +#ifndef _POSIX2_RE_DUP_MAX +#define _POSIX2_RE_DUP_MAX 255 /* normally from <limits.h> */ +#endif + + + +/* + * misc + */ + +#define NOTREACHED 0 + +#define DUPMAX _POSIX2_RE_DUP_MAX +#define DUPINF (DUPMAX+1) + +#define REMAGIC 0xfed7 /* magic number for main struct */ + +/* Type codes for lookaround constraints */ +#define LATYPE_AHEAD_POS 03 /* positive lookahead */ +#define LATYPE_AHEAD_NEG 02 /* negative lookahead */ +#define LATYPE_BEHIND_POS 01 /* positive lookbehind */ +#define LATYPE_BEHIND_NEG 00 /* negative lookbehind */ +#define LATYPE_IS_POS(la) ((la) & 01) +#define LATYPE_IS_AHEAD(la) ((la) & 02) + + +/* + * debugging facilities + */ +#ifdef REG_DEBUG +/* FDEBUG does finite-state tracing */ +#define FDEBUG(arglist) { if (v->eflags®_FTRACE) printf arglist; } +/* MDEBUG does higher-level tracing */ +#define MDEBUG(arglist) { if (v->eflags®_MTRACE) printf arglist; } +#else +#define FDEBUG(arglist) {} +#define MDEBUG(arglist) {} +#endif + + + +/* + * bitmap manipulation + */ +#define UBITS (CHAR_BIT * sizeof(unsigned)) +#define BSET(uv, sn) ((uv)[(sn)/UBITS] |= (unsigned)1 << ((sn)%UBITS)) +#define ISBSET(uv, sn) ((uv)[(sn)/UBITS] & ((unsigned)1 << ((sn)%UBITS))) + + +/* + * known character classes + */ +enum char_classes +{ + CC_ALNUM, CC_ALPHA, CC_ASCII, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH, + CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_XDIGIT, CC_WORD +}; + +#define NUM_CCLASSES 14 + + +/* + * As soon as possible, we map chrs into equivalence classes -- "colors" -- + * which are of much more manageable number. + * + * To further reduce the number of arcs in NFAs and DFAs, we also have a + * special RAINBOW "color" that can be assigned to an arc. This is not a + * real color, in that it has no entry in color maps. + */ +typedef short color; /* colors of characters */ + +#define MAX_COLOR 32767 /* max color (must fit in 'color' datatype) */ +#define COLORLESS (-1) /* impossible color */ +#define RAINBOW (-2) /* represents all colors except pseudocolors */ +#define WHITE 0 /* default color, parent of all others */ +/* Note: various places in the code know that WHITE is zero */ + + +/* + * Per-color data structure for the compile-time color machinery + * + * If "sub" is not NOSUB then it is the number of the color's current + * subcolor, i.e. we are in process of dividing this color (character + * equivalence class) into two colors. See src/backend/regex/README for + * discussion of subcolors. + * + * Currently-unused colors have the FREECOL bit set and are linked into a + * freelist using their "sub" fields, but only if their color numbers are + * less than colormap.max. Any array entries beyond "max" are just garbage. + */ +struct colordesc +{ + int nschrs; /* number of simple chars of this color */ + int nuchrs; /* number of upper map entries of this color */ + color sub; /* open subcolor, if any; or free-chain ptr */ +#define NOSUB COLORLESS /* value of "sub" when no open subcolor */ + struct arc *arcs; /* chain of all arcs of this color */ + chr firstchr; /* simple char first assigned to this color */ + int flags; /* bitmask of the following flags: */ +#define FREECOL 01 /* currently free */ +#define PSEUDO 02 /* pseudocolor, no real chars */ +#define COLMARK 04 /* temporary marker used in some functions */ +}; + +#define UNUSEDCOLOR(cd) ((cd)->flags & FREECOL) + +/* + * The color map itself + * + * This struct holds both data used only at compile time, and the chr to + * color mapping information, used at both compile and run time. The latter + * is the bulk of the space, so it's not really worth separating out the + * compile-only portion. + * + * Ideally, the mapping data would just be an array of colors indexed by + * chr codes; but for large character sets that's impractical. Fortunately, + * common characters have smaller codes, so we can use a simple array for chr + * codes up to MAX_SIMPLE_CHR, and do something more complex for codes above + * that, without much loss of performance. The "something more complex" is a + * 2-D array of color entries, where row indexes correspond to individual chrs + * or chr ranges that have been mentioned in the regex (with row zero + * representing all other chrs), and column indexes correspond to different + * sets of locale-dependent character classes such as "isalpha". The + * classbits[k] entry is zero if we do not care about the k'th character class + * in this regex, and otherwise it is the bit to be OR'd into the column index + * if the character in question is a member of that class. We find the color + * of a high-valued chr by identifying which colormaprange it is in to get + * the row index (use row zero if it's in none of them), identifying which of + * the interesting cclasses it's in to get the column index, and then indexing + * into the 2-D hicolormap array. + * + * The colormapranges are required to be nonempty, nonoverlapping, and to + * appear in increasing chr-value order. + */ + +typedef struct colormaprange +{ + chr cmin; /* range represents cmin..cmax inclusive */ + chr cmax; + int rownum; /* row index in hicolormap array (>= 1) */ +} colormaprange; + +struct colormap +{ + int magic; +#define CMMAGIC 0x876 + struct vars *v; /* for compile error reporting */ + size_t ncds; /* allocated length of colordescs array */ + size_t max; /* highest color number currently in use */ + color free; /* beginning of free chain (if non-0) */ + struct colordesc *cd; /* pointer to array of colordescs */ +#define CDEND(cm) (&(cm)->cd[(cm)->max + 1]) + + /* mapping data for chrs <= MAX_SIMPLE_CHR: */ + color *locolormap; /* simple array indexed by chr code */ + + /* mapping data for chrs > MAX_SIMPLE_CHR: */ + int classbits[NUM_CCLASSES]; /* see comment above */ + int numcmranges; /* number of colormapranges */ + colormaprange *cmranges; /* ranges of high chrs */ + color *hicolormap; /* 2-D array of color entries */ + int maxarrayrows; /* number of array rows allocated */ + int hiarrayrows; /* number of array rows in use */ + int hiarraycols; /* number of array columns (2^N) */ + + /* If we need up to NINLINECDS, we store them here to save a malloc */ +#define NINLINECDS ((size_t) 10) + struct colordesc cdspace[NINLINECDS]; +}; + +/* fetch color for chr; beware of multiple evaluation of c argument */ +#define GETCOLOR(cm, c) \ + ((c) <= MAX_SIMPLE_CHR ? (cm)->locolormap[(c) - CHR_MIN] : pg_reg_getcolor(cm, c)) + + +/* + * Interface definitions for locale-interface functions in regc_locale.c. + */ + +/* + * Representation of a set of characters. chrs[] represents individual + * code points, ranges[] represents ranges in the form min..max inclusive. + * + * If the cvec represents a locale-specific character class, eg [[:alpha:]], + * then the chrs[] and ranges[] arrays contain only members of that class + * up to MAX_SIMPLE_CHR (inclusive). cclasscode is set to regc_locale.c's + * code for the class, rather than being -1 as it is in an ordinary cvec. + * + * Note that in cvecs gotten from newcvec() and intended to be freed by + * freecvec(), both arrays of chrs are after the end of the struct, not + * separately malloc'd; so chrspace and rangespace are effectively immutable. + */ +struct cvec +{ + int nchrs; /* number of chrs */ + int chrspace; /* number of chrs allocated in chrs[] */ + chr *chrs; /* pointer to vector of chrs */ + int nranges; /* number of ranges (chr pairs) */ + int rangespace; /* number of ranges allocated in ranges[] */ + chr *ranges; /* pointer to vector of chr pairs */ + int cclasscode; /* value of "enum classes", or -1 */ +}; + + +/* + * definitions for NFA internal representation + */ +struct state; + +struct arc +{ + int type; /* 0 if free, else an NFA arc type code */ + color co; /* color the arc matches (possibly RAINBOW) */ + struct state *from; /* where it's from */ + struct state *to; /* where it's to */ + struct arc *outchain; /* link in *from's outs chain or free chain */ + struct arc *outchainRev; /* back-link in *from's outs chain */ +#define freechain outchain /* we do not maintain "freechainRev" */ + struct arc *inchain; /* link in *to's ins chain */ + struct arc *inchainRev; /* back-link in *to's ins chain */ + /* these fields are not used when co == RAINBOW: */ + struct arc *colorchain; /* link in color's arc chain */ + struct arc *colorchainRev; /* back-link in color's arc chain */ +}; + +struct arcbatch +{ /* for bulk allocation of arcs */ + struct arcbatch *next; /* chain link */ + size_t narcs; /* number of arcs allocated in this arcbatch */ + struct arc a[FLEXIBLE_ARRAY_MEMBER]; +}; +#define ARCBATCHSIZE(n) ((n) * sizeof(struct arc) + offsetof(struct arcbatch, a)) +/* first batch will have FIRSTABSIZE arcs; then double it until MAXABSIZE */ +#define FIRSTABSIZE 64 +#define MAXABSIZE 1024 + +struct state +{ + int no; /* state number, zero and up; or FREESTATE */ +#define FREESTATE (-1) + char flag; /* marks special states */ + int nins; /* number of inarcs */ + int nouts; /* number of outarcs */ + struct arc *ins; /* chain of inarcs */ + struct arc *outs; /* chain of outarcs */ + struct state *tmp; /* temporary for traversal algorithms */ + struct state *next; /* chain for traversing all live states */ + /* the "next" field is also used to chain free states together */ + struct state *prev; /* back-link in chain of all live states */ +}; + +struct statebatch +{ /* for bulk allocation of states */ + struct statebatch *next; /* chain link */ + size_t nstates; /* number of states allocated in this batch */ + struct state s[FLEXIBLE_ARRAY_MEMBER]; +}; +#define STATEBATCHSIZE(n) ((n) * sizeof(struct state) + offsetof(struct statebatch, s)) +/* first batch will have FIRSTSBSIZE states; then double it until MAXSBSIZE */ +#define FIRSTSBSIZE 32 +#define MAXSBSIZE 1024 + +struct nfa +{ + struct state *pre; /* pre-initial state */ + struct state *init; /* initial state */ + struct state *final; /* final state */ + struct state *post; /* post-final state */ + int nstates; /* for numbering states */ + struct state *states; /* chain of live states */ + struct state *slast; /* tail of the chain */ + struct state *freestates; /* chain of free states */ + struct arc *freearcs; /* chain of free arcs */ + struct statebatch *lastsb; /* chain of statebatches */ + struct arcbatch *lastab; /* chain of arcbatches */ + size_t lastsbused; /* number of states consumed from *lastsb */ + size_t lastabused; /* number of arcs consumed from *lastab */ + struct colormap *cm; /* the color map */ + color bos[2]; /* colors, if any, assigned to BOS and BOL */ + color eos[2]; /* colors, if any, assigned to EOS and EOL */ + int flags; /* flags to pass forward to cNFA */ + int minmatchall; /* min number of chrs to match, if matchall */ + int maxmatchall; /* max number of chrs to match, or DUPINF */ + struct vars *v; /* simplifies compile error reporting */ + struct nfa *parent; /* parent NFA, if any */ +}; + + + +/* + * definitions for compacted NFA + * + * The main space savings in a compacted NFA is from making the arcs as small + * as possible. We store only the transition color and next-state number for + * each arc. The list of out arcs for each state is an array beginning at + * cnfa.states[statenumber], and terminated by a dummy carc struct with + * co == COLORLESS. + * + * The non-dummy carc structs are of two types: plain arcs and LACON arcs. + * Plain arcs just store the transition color number as "co". LACON arcs + * store the lookaround constraint number plus cnfa.ncolors as "co". LACON + * arcs can be distinguished from plain by testing for co >= cnfa.ncolors. + * + * Note that in a plain arc, "co" can be RAINBOW; since that's negative, + * it doesn't break the rule about how to recognize LACON arcs. + * + * We have special markings for "trivial" NFAs that can match any string + * (possibly with limits on the number of characters therein). In such a + * case, flags & MATCHALL is set (and HASLACONS can't be set). Then the + * fields minmatchall and maxmatchall give the minimum and maximum numbers + * of characters to match. For example, ".*" produces minmatchall = 0 + * and maxmatchall = DUPINF, while ".+" produces minmatchall = 1 and + * maxmatchall = DUPINF. + */ +struct carc +{ + color co; /* COLORLESS is list terminator */ + int to; /* next-state number */ +}; + +struct cnfa +{ + int nstates; /* number of states */ + int ncolors; /* number of colors (max color in use + 1) */ + int flags; /* bitmask of the following flags: */ +#define HASLACONS 01 /* uses lookaround constraints */ +#define MATCHALL 02 /* matches all strings of a range of lengths */ + int pre; /* setup state number */ + int post; /* teardown state number */ + color bos[2]; /* colors, if any, assigned to BOS and BOL */ + color eos[2]; /* colors, if any, assigned to EOS and EOL */ + char *stflags; /* vector of per-state flags bytes */ +#define CNFA_NOPROGRESS 01 /* flag bit for a no-progress state */ + struct carc **states; /* vector of pointers to outarc lists */ + /* states[n] are pointers into a single malloc'd array of arcs */ + struct carc *arcs; /* the area for the lists */ + /* these fields are used only in a MATCHALL NFA (else they're -1): */ + int minmatchall; /* min number of chrs to match */ + int maxmatchall; /* max number of chrs to match, or DUPINF */ +}; + +/* + * When debugging, it's helpful if an un-filled CNFA is all-zeroes. + * In production, though, we only require nstates to be zero. + */ +#ifdef REG_DEBUG +#define ZAPCNFA(cnfa) memset(&(cnfa), 0, sizeof(cnfa)) +#else +#define ZAPCNFA(cnfa) ((cnfa).nstates = 0) +#endif +#define NULLCNFA(cnfa) ((cnfa).nstates == 0) + +/* + * This symbol limits the transient heap space used by the regex compiler, + * and thereby also the maximum complexity of NFAs that we'll deal with. + * Currently we only count NFA states and arcs against this; the other + * transient data is generally not large enough to notice compared to those. + * Note that we do not charge anything for the final output data structures + * (the compacted NFA and the colormap). + * The scaling here is based on an empirical measurement that very large + * NFAs tend to have about 4 arcs/state. + */ +#ifndef REG_MAX_COMPILE_SPACE +#define REG_MAX_COMPILE_SPACE \ + (500000 * (sizeof(struct state) + 4 * sizeof(struct arc))) +#endif + +/* + * subexpression tree + * + * "op" is one of: + * '=' plain regex without interesting substructure (implemented as DFA) + * 'b' back-reference (has no substructure either) + * '(' no-op capture node: captures the match of its single child + * '.' concatenation: matches a match for first child, then second child + * '|' alternation: matches a match for any of its children + * '*' iteration: matches some number of matches of its single child + * + * An alternation node can have any number of children (but at least two), + * linked through their sibling fields. + * + * A concatenation node must have exactly two children. It might be useful + * to support more, but that would complicate the executor. Note that it is + * the first child's greediness that determines the node's preference for + * where to split a match. + * + * Note: when a backref is directly quantified, we stick the min/max counts + * into the backref rather than plastering an iteration node on top. This is + * for efficiency: there is no need to search for possible division points. + */ +struct subre +{ + char op; /* see type codes above */ + char flags; +#define LONGER 01 /* prefers longer match */ +#define SHORTER 02 /* prefers shorter match */ +#define MIXED 04 /* mixed preference below */ +#define CAP 010 /* capturing parens here or below */ +#define BACKR 020 /* back reference here or below */ +#define BRUSE 040 /* is referenced by a back reference */ +#define INUSE 0100 /* in use in final tree */ +#define UPPROP (MIXED|CAP|BACKR) /* flags which should propagate up */ +#define LMIX(f) ((f)<<2) /* LONGER -> MIXED */ +#define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */ +#define UP(f) (((f)&UPPROP) | (LMIX(f) & SMIX(f) & MIXED)) +#define MESSY(f) ((f)&(MIXED|CAP|BACKR)) +#define PREF(f) ((f)&(LONGER|SHORTER)) +#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2)) +#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2)) + char latype; /* LATYPE code, if lookaround constraint */ + int id; /* ID of subre (1..ntree-1) */ + int capno; /* if capture node, subno to capture into */ + int backno; /* if backref node, subno it refers to */ + short min; /* min repetitions for iteration or backref */ + short max; /* max repetitions for iteration or backref */ + struct subre *child; /* first child, if any (also freelist chain) */ + struct subre *sibling; /* next child of same parent, if any */ + struct state *begin; /* outarcs from here... */ + struct state *end; /* ...ending in inarcs here */ + struct cnfa cnfa; /* compacted NFA, if any */ + struct subre *chain; /* for bookkeeping and error cleanup */ +}; + + + +/* + * table of function pointers for generic manipulation functions + * A regex_t's re_fns points to one of these. + */ +struct fns +{ + void FUNCPTR(free, (regex_t *)); + int FUNCPTR(cancel_requested, (void)); + int FUNCPTR(stack_too_deep, (void)); +}; + +#define CANCEL_REQUESTED(re) \ + ((*((struct fns *) (re)->re_fns)->cancel_requested) ()) + +#define STACK_TOO_DEEP(re) \ + ((*((struct fns *) (re)->re_fns)->stack_too_deep) ()) + + +/* + * the insides of a regex_t, hidden behind a void * + */ +struct guts +{ + int magic; +#define GUTSMAGIC 0xfed9 + int cflags; /* copy of compile flags */ + long info; /* copy of re_info */ + size_t nsub; /* copy of re_nsub */ + struct subre *tree; + struct cnfa search; /* for fast preliminary search */ + int ntree; /* number of subre's, plus one */ + struct colormap cmap; + int FUNCPTR(compare, (const chr *, const chr *, size_t)); + struct subre *lacons; /* lookaround-constraint vector */ + int nlacons; /* size of lacons[]; note that only slots + * numbered 1 .. nlacons-1 are used */ +}; + + +/* prototypes for functions that are exported from regcomp.c to regexec.c */ +extern void pg_set_regex_collation(Oid collation); +extern color pg_reg_getcolor(struct colormap *cm, chr c); diff --git a/src/include/replication/decode.h b/src/include/replication/decode.h new file mode 100644 index 0000000..741bf65 --- /dev/null +++ b/src/include/replication/decode.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * decode.h + * PostgreSQL WAL to logical transformation + * + * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ +#ifndef DECODE_H +#define DECODE_H + +#include "access/xlogreader.h" +#include "access/xlogrecord.h" +#include "replication/logical.h" +#include "replication/reorderbuffer.h" + +typedef struct XLogRecordBuffer +{ + XLogRecPtr origptr; + XLogRecPtr endptr; + XLogReaderState *record; +} XLogRecordBuffer; + +extern void xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +extern void heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +extern void heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +extern void xact_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +extern void standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); +extern void logicalmsg_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf); + +extern void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, + XLogReaderState *record); + +#endif diff --git a/src/include/replication/logical.h b/src/include/replication/logical.h new file mode 100644 index 0000000..edadacd --- /dev/null +++ b/src/include/replication/logical.h @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------- + * logical.h + * PostgreSQL logical decoding coordination + * + * Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICAL_H +#define LOGICAL_H + +#include "access/xlog.h" +#include "access/xlogreader.h" +#include "replication/output_plugin.h" +#include "replication/slot.h" + +struct LogicalDecodingContext; + +typedef void (*LogicalOutputPluginWriterWrite) (struct LogicalDecodingContext *lr, + XLogRecPtr Ptr, + TransactionId xid, + bool last_write +); + +typedef LogicalOutputPluginWriterWrite LogicalOutputPluginWriterPrepareWrite; + +typedef void (*LogicalOutputPluginWriterUpdateProgress) (struct LogicalDecodingContext *lr, + XLogRecPtr Ptr, + TransactionId xid, + bool skipped_xact +); + +typedef struct LogicalDecodingContext +{ + /* memory context this is all allocated in */ + MemoryContext context; + + /* The associated replication slot */ + ReplicationSlot *slot; + + /* infrastructure pieces for decoding */ + XLogReaderState *reader; + struct ReorderBuffer *reorder; + struct SnapBuild *snapshot_builder; + + /* + * Marks the logical decoding context as fast forward decoding one. Such a + * context does not have plugin loaded so most of the following properties + * are unused. + */ + bool fast_forward; + + OutputPluginCallbacks callbacks; + OutputPluginOptions options; + + /* + * User specified options + */ + List *output_plugin_options; + + /* + * User-Provided callback for writing/streaming out data. + */ + LogicalOutputPluginWriterPrepareWrite prepare_write; + LogicalOutputPluginWriterWrite write; + LogicalOutputPluginWriterUpdateProgress update_progress; + + /* + * Output buffer. + */ + StringInfo out; + + /* + * Private data pointer of the output plugin. + */ + void *output_plugin_private; + + /* + * Private data pointer for the data writer. + */ + void *output_writer_private; + + /* + * Does the output plugin support streaming, and is it enabled? + */ + bool streaming; + + /* + * Does the output plugin support two-phase decoding, and is it enabled? + */ + bool twophase; + + /* + * Is two-phase option given by output plugin? + * + * This flag indicates that the plugin passed in the two-phase option as + * part of the START_STREAMING command. We can't rely solely on the + * twophase flag which only tells whether the plugin provided all the + * necessary two-phase callbacks. + */ + bool twophase_opt_given; + + /* + * State for writing output. + */ + bool accept_writes; + bool prepared_write; + XLogRecPtr write_location; + TransactionId write_xid; + /* Are we processing the end LSN of a transaction? */ + bool end_xact; +} LogicalDecodingContext; + + +extern void CheckLogicalDecodingRequirements(void); + +extern LogicalDecodingContext *CreateInitDecodingContext(const char *plugin, + List *output_plugin_options, + bool need_full_snapshot, + XLogRecPtr restart_lsn, + XLogReaderRoutine *xl_routine, + LogicalOutputPluginWriterPrepareWrite prepare_write, + LogicalOutputPluginWriterWrite do_write, + LogicalOutputPluginWriterUpdateProgress update_progress); +extern LogicalDecodingContext *CreateDecodingContext(XLogRecPtr start_lsn, + List *output_plugin_options, + bool fast_forward, + XLogReaderRoutine *xl_routine, + LogicalOutputPluginWriterPrepareWrite prepare_write, + LogicalOutputPluginWriterWrite do_write, + LogicalOutputPluginWriterUpdateProgress update_progress); +extern void DecodingContextFindStartpoint(LogicalDecodingContext *ctx); +extern bool DecodingContextReady(LogicalDecodingContext *ctx); +extern void FreeDecodingContext(LogicalDecodingContext *ctx); + +extern void LogicalIncreaseXminForSlot(XLogRecPtr lsn, TransactionId xmin); +extern void LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, + XLogRecPtr restart_lsn); +extern void LogicalConfirmReceivedLocation(XLogRecPtr lsn); + +extern bool filter_prepare_cb_wrapper(LogicalDecodingContext *ctx, + TransactionId xid, const char *gid); +extern bool filter_by_origin_cb_wrapper(LogicalDecodingContext *ctx, RepOriginId origin_id); +extern void ResetLogicalStreamingState(void); +extern void UpdateDecodingStats(LogicalDecodingContext *ctx); + +#endif diff --git a/src/include/replication/logicallauncher.h b/src/include/replication/logicallauncher.h new file mode 100644 index 0000000..f1e2821 --- /dev/null +++ b/src/include/replication/logicallauncher.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * logicallauncher.h + * Exports for logical replication launcher. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/replication/logicallauncher.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALLAUNCHER_H +#define LOGICALLAUNCHER_H + +extern PGDLLIMPORT int max_logical_replication_workers; +extern PGDLLIMPORT int max_sync_workers_per_subscription; + +extern void ApplyLauncherRegister(void); +extern void ApplyLauncherMain(Datum main_arg); + +extern Size ApplyLauncherShmemSize(void); +extern void ApplyLauncherShmemInit(void); + +extern void ApplyLauncherWakeupAtCommit(void); +extern void AtEOXact_ApplyLauncher(bool isCommit); + +extern bool IsLogicalLauncher(void); + +#endif /* LOGICALLAUNCHER_H */ diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h new file mode 100644 index 0000000..8cdc04a --- /dev/null +++ b/src/include/replication/logicalproto.h @@ -0,0 +1,254 @@ +/*------------------------------------------------------------------------- + * + * logicalproto.h + * logical replication protocol + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/replication/logicalproto.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICAL_PROTO_H +#define LOGICAL_PROTO_H + +#include "access/xact.h" +#include "executor/tuptable.h" +#include "replication/reorderbuffer.h" +#include "utils/rel.h" + +/* + * Protocol capabilities + * + * LOGICALREP_PROTO_VERSION_NUM is our native protocol. + * LOGICALREP_PROTO_MAX_VERSION_NUM is the greatest version we can support. + * LOGICALREP_PROTO_MIN_VERSION_NUM is the oldest version we + * have backwards compatibility for. The client requests protocol version at + * connect time. + * + * LOGICALREP_PROTO_STREAM_VERSION_NUM is the minimum protocol version with + * support for streaming large transactions. Introduced in PG14. + * + * LOGICALREP_PROTO_TWOPHASE_VERSION_NUM is the minimum protocol version with + * support for two-phase commit decoding (at prepare time). Introduced in PG15. + */ +#define LOGICALREP_PROTO_MIN_VERSION_NUM 1 +#define LOGICALREP_PROTO_VERSION_NUM 1 +#define LOGICALREP_PROTO_STREAM_VERSION_NUM 2 +#define LOGICALREP_PROTO_TWOPHASE_VERSION_NUM 3 +#define LOGICALREP_PROTO_MAX_VERSION_NUM LOGICALREP_PROTO_TWOPHASE_VERSION_NUM + +/* + * Logical message types + * + * Used by logical replication wire protocol. + * + * Note: though this is an enum, the values are used to identify message types + * in logical replication protocol, which uses a single byte to identify a + * message type. Hence the values should be single-byte wide and preferably + * human-readable characters. + */ +typedef enum LogicalRepMsgType +{ + LOGICAL_REP_MSG_BEGIN = 'B', + LOGICAL_REP_MSG_COMMIT = 'C', + LOGICAL_REP_MSG_ORIGIN = 'O', + LOGICAL_REP_MSG_INSERT = 'I', + LOGICAL_REP_MSG_UPDATE = 'U', + LOGICAL_REP_MSG_DELETE = 'D', + LOGICAL_REP_MSG_TRUNCATE = 'T', + LOGICAL_REP_MSG_RELATION = 'R', + LOGICAL_REP_MSG_TYPE = 'Y', + LOGICAL_REP_MSG_MESSAGE = 'M', + LOGICAL_REP_MSG_BEGIN_PREPARE = 'b', + LOGICAL_REP_MSG_PREPARE = 'P', + LOGICAL_REP_MSG_COMMIT_PREPARED = 'K', + LOGICAL_REP_MSG_ROLLBACK_PREPARED = 'r', + LOGICAL_REP_MSG_STREAM_START = 'S', + LOGICAL_REP_MSG_STREAM_STOP = 'E', + LOGICAL_REP_MSG_STREAM_COMMIT = 'c', + LOGICAL_REP_MSG_STREAM_ABORT = 'A', + LOGICAL_REP_MSG_STREAM_PREPARE = 'p' +} LogicalRepMsgType; + +/* + * This struct stores a tuple received via logical replication. + * Keep in mind that the columns correspond to the *remote* table. + */ +typedef struct LogicalRepTupleData +{ + /* Array of StringInfos, one per column; some may be unused */ + StringInfoData *colvalues; + /* Array of markers for null/unchanged/text/binary, one per column */ + char *colstatus; + /* Length of above arrays */ + int ncols; +} LogicalRepTupleData; + +/* Possible values for LogicalRepTupleData.colstatus[colnum] */ +/* These values are also used in the on-the-wire protocol */ +#define LOGICALREP_COLUMN_NULL 'n' +#define LOGICALREP_COLUMN_UNCHANGED 'u' +#define LOGICALREP_COLUMN_TEXT 't' +#define LOGICALREP_COLUMN_BINARY 'b' /* added in PG14 */ + +typedef uint32 LogicalRepRelId; + +/* Relation information */ +typedef struct LogicalRepRelation +{ + /* Info coming from the remote side. */ + LogicalRepRelId remoteid; /* unique id of the relation */ + char *nspname; /* schema name */ + char *relname; /* relation name */ + int natts; /* number of columns */ + char **attnames; /* column names */ + Oid *atttyps; /* column types */ + char replident; /* replica identity */ + char relkind; /* remote relation kind */ + Bitmapset *attkeys; /* Bitmap of key columns */ +} LogicalRepRelation; + +/* Type mapping info */ +typedef struct LogicalRepTyp +{ + Oid remoteid; /* unique id of the remote type */ + char *nspname; /* schema name of remote type */ + char *typname; /* name of the remote type */ +} LogicalRepTyp; + +/* Transaction info */ +typedef struct LogicalRepBeginData +{ + XLogRecPtr final_lsn; + TimestampTz committime; + TransactionId xid; +} LogicalRepBeginData; + +typedef struct LogicalRepCommitData +{ + XLogRecPtr commit_lsn; + XLogRecPtr end_lsn; + TimestampTz committime; +} LogicalRepCommitData; + +/* + * Prepared transaction protocol information for begin_prepare, and prepare. + */ +typedef struct LogicalRepPreparedTxnData +{ + XLogRecPtr prepare_lsn; + XLogRecPtr end_lsn; + TimestampTz prepare_time; + TransactionId xid; + char gid[GIDSIZE]; +} LogicalRepPreparedTxnData; + +/* + * Prepared transaction protocol information for commit prepared. + */ +typedef struct LogicalRepCommitPreparedTxnData +{ + XLogRecPtr commit_lsn; + XLogRecPtr end_lsn; + TimestampTz commit_time; + TransactionId xid; + char gid[GIDSIZE]; +} LogicalRepCommitPreparedTxnData; + +/* + * Rollback Prepared transaction protocol information. The prepare information + * prepare_end_lsn and prepare_time are used to check if the downstream has + * received this prepared transaction in which case it can apply the rollback, + * otherwise, it can skip the rollback operation. The gid alone is not + * sufficient because the downstream node can have a prepared transaction with + * same identifier. + */ +typedef struct LogicalRepRollbackPreparedTxnData +{ + XLogRecPtr prepare_end_lsn; + XLogRecPtr rollback_end_lsn; + TimestampTz prepare_time; + TimestampTz rollback_time; + TransactionId xid; + char gid[GIDSIZE]; +} LogicalRepRollbackPreparedTxnData; + +extern void logicalrep_write_begin(StringInfo out, ReorderBufferTXN *txn); +extern void logicalrep_read_begin(StringInfo in, + LogicalRepBeginData *begin_data); +extern void logicalrep_write_commit(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +extern void logicalrep_read_commit(StringInfo in, + LogicalRepCommitData *commit_data); +extern void logicalrep_write_begin_prepare(StringInfo out, ReorderBufferTXN *txn); +extern void logicalrep_read_begin_prepare(StringInfo in, + LogicalRepPreparedTxnData *begin_data); +extern void logicalrep_write_prepare(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); +extern void logicalrep_read_prepare(StringInfo in, + LogicalRepPreparedTxnData *prepare_data); +extern void logicalrep_write_commit_prepared(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +extern void logicalrep_read_commit_prepared(StringInfo in, + LogicalRepCommitPreparedTxnData *prepare_data); +extern void logicalrep_write_rollback_prepared(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); +extern void logicalrep_read_rollback_prepared(StringInfo in, + LogicalRepRollbackPreparedTxnData *rollback_data); +extern void logicalrep_write_stream_prepare(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); +extern void logicalrep_read_stream_prepare(StringInfo in, + LogicalRepPreparedTxnData *prepare_data); + +extern void logicalrep_write_origin(StringInfo out, const char *origin, + XLogRecPtr origin_lsn); +extern char *logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn); +extern void logicalrep_write_insert(StringInfo out, TransactionId xid, + Relation rel, + TupleTableSlot *newslot, + bool binary, Bitmapset *columns); +extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup); +extern void logicalrep_write_update(StringInfo out, TransactionId xid, + Relation rel, + TupleTableSlot *oldslot, + TupleTableSlot *newslot, bool binary, Bitmapset *columns); +extern LogicalRepRelId logicalrep_read_update(StringInfo in, + bool *has_oldtuple, LogicalRepTupleData *oldtup, + LogicalRepTupleData *newtup); +extern void logicalrep_write_delete(StringInfo out, TransactionId xid, + Relation rel, TupleTableSlot *oldtuple, + bool binary, Bitmapset *columns); +extern LogicalRepRelId logicalrep_read_delete(StringInfo in, + LogicalRepTupleData *oldtup); +extern void logicalrep_write_truncate(StringInfo out, TransactionId xid, + int nrelids, Oid relids[], + bool cascade, bool restart_seqs); +extern List *logicalrep_read_truncate(StringInfo in, + bool *cascade, bool *restart_seqs); +extern void logicalrep_write_message(StringInfo out, TransactionId xid, XLogRecPtr lsn, + bool transactional, const char *prefix, Size sz, const char *message); +extern void logicalrep_write_rel(StringInfo out, TransactionId xid, + Relation rel, Bitmapset *columns); +extern LogicalRepRelation *logicalrep_read_rel(StringInfo in); +extern void logicalrep_write_typ(StringInfo out, TransactionId xid, + Oid typoid); +extern void logicalrep_read_typ(StringInfo out, LogicalRepTyp *ltyp); +extern void logicalrep_write_stream_start(StringInfo out, TransactionId xid, + bool first_segment); +extern TransactionId logicalrep_read_stream_start(StringInfo in, + bool *first_segment); +extern void logicalrep_write_stream_stop(StringInfo out); +extern void logicalrep_write_stream_commit(StringInfo out, ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); +extern TransactionId logicalrep_read_stream_commit(StringInfo out, + LogicalRepCommitData *commit_data); +extern void logicalrep_write_stream_abort(StringInfo out, TransactionId xid, + TransactionId subxid); +extern void logicalrep_read_stream_abort(StringInfo in, TransactionId *xid, + TransactionId *subxid); +extern const char *logicalrep_message_type(LogicalRepMsgType action); + +#endif /* LOGICAL_PROTO_H */ diff --git a/src/include/replication/logicalrelation.h b/src/include/replication/logicalrelation.h new file mode 100644 index 0000000..78cd7e7 --- /dev/null +++ b/src/include/replication/logicalrelation.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * logicalrelation.h + * Relation definitions for logical replication relation mapping. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/replication/logicalrelation.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALRELATION_H +#define LOGICALRELATION_H + +#include "access/attmap.h" +#include "replication/logicalproto.h" + +typedef struct LogicalRepRelMapEntry +{ + LogicalRepRelation remoterel; /* key is remoterel.remoteid */ + + /* + * Validity flag -- when false, revalidate all derived info at next + * logicalrep_rel_open. (While the localrel is open, we assume our lock + * on that rel ensures the info remains good.) + */ + bool localrelvalid; + + /* Mapping to local relation. */ + Oid localreloid; /* local relation id */ + Relation localrel; /* relcache entry (NULL when closed) */ + AttrMap *attrmap; /* map of local attributes to remote ones */ + bool updatable; /* Can apply updates/deletes? */ + + /* Sync state. */ + char state; + XLogRecPtr statelsn; +} LogicalRepRelMapEntry; + +extern void logicalrep_relmap_update(LogicalRepRelation *remoterel); +extern void logicalrep_partmap_reset_relmap(LogicalRepRelation *remoterel); + +extern LogicalRepRelMapEntry *logicalrep_rel_open(LogicalRepRelId remoteid, + LOCKMODE lockmode); +extern LogicalRepRelMapEntry *logicalrep_partition_open(LogicalRepRelMapEntry *root, + Relation partrel, AttrMap *map); +extern void logicalrep_rel_close(LogicalRepRelMapEntry *rel, + LOCKMODE lockmode); + +#endif /* LOGICALRELATION_H */ diff --git a/src/include/replication/logicalworker.h b/src/include/replication/logicalworker.h new file mode 100644 index 0000000..cd1b6e8 --- /dev/null +++ b/src/include/replication/logicalworker.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * logicalworker.h + * Exports for logical replication workers. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/replication/logicalworker.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOGICALWORKER_H +#define LOGICALWORKER_H + +extern void ApplyWorkerMain(Datum main_arg); + +extern bool IsLogicalWorker(void); + +#endif /* LOGICALWORKER_H */ diff --git a/src/include/replication/message.h b/src/include/replication/message.h new file mode 100644 index 0000000..0b396c5 --- /dev/null +++ b/src/include/replication/message.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * message.h + * Exports from replication/logical/message.c + * + * Copyright (c) 2013-2022, PostgreSQL Global Development Group + * + * src/include/replication/message.h + *------------------------------------------------------------------------- + */ +#ifndef PG_LOGICAL_MESSAGE_H +#define PG_LOGICAL_MESSAGE_H + +#include "access/xlog.h" +#include "access/xlogdefs.h" +#include "access/xlogreader.h" + +/* + * Generic logical decoding message wal record. + */ +typedef struct xl_logical_message +{ + Oid dbId; /* database Oid emitted from */ + bool transactional; /* is message transactional? */ + Size prefix_size; /* length of prefix */ + Size message_size; /* size of the message */ + /* payload, including null-terminated prefix of length prefix_size */ + char message[FLEXIBLE_ARRAY_MEMBER]; +} xl_logical_message; + +#define SizeOfLogicalMessage (offsetof(xl_logical_message, message)) + +extern XLogRecPtr LogLogicalMessage(const char *prefix, const char *message, + size_t size, bool transactional); + +/* RMGR API */ +#define XLOG_LOGICAL_MESSAGE 0x00 +extern void logicalmsg_redo(XLogReaderState *record); +extern void logicalmsg_desc(StringInfo buf, XLogReaderState *record); +extern const char *logicalmsg_identify(uint8 info); + +#endif /* PG_LOGICAL_MESSAGE_H */ diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h new file mode 100644 index 0000000..2d1b5e5 --- /dev/null +++ b/src/include/replication/origin.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * origin.h + * Exports from replication/logical/origin.c + * + * Copyright (c) 2013-2022, PostgreSQL Global Development Group + * + * src/include/replication/origin.h + *------------------------------------------------------------------------- + */ +#ifndef PG_ORIGIN_H +#define PG_ORIGIN_H + +#include "access/xlog.h" +#include "access/xlogdefs.h" +#include "access/xlogreader.h" +#include "catalog/pg_replication_origin.h" + +typedef struct xl_replorigin_set +{ + XLogRecPtr remote_lsn; + RepOriginId node_id; + bool force; +} xl_replorigin_set; + +typedef struct xl_replorigin_drop +{ + RepOriginId node_id; +} xl_replorigin_drop; + +#define XLOG_REPLORIGIN_SET 0x00 +#define XLOG_REPLORIGIN_DROP 0x10 + +#define InvalidRepOriginId 0 +#define DoNotReplicateId PG_UINT16_MAX + +extern PGDLLIMPORT RepOriginId replorigin_session_origin; +extern PGDLLIMPORT XLogRecPtr replorigin_session_origin_lsn; +extern PGDLLIMPORT TimestampTz replorigin_session_origin_timestamp; + +/* API for querying & manipulating replication origins */ +extern RepOriginId replorigin_by_name(const char *name, bool missing_ok); +extern RepOriginId replorigin_create(const char *name); +extern void replorigin_drop_by_name(const char *name, bool missing_ok, bool nowait); +extern bool replorigin_by_oid(RepOriginId roident, bool missing_ok, + char **roname); + +/* API for querying & manipulating replication progress tracking */ +extern void replorigin_advance(RepOriginId node, + XLogRecPtr remote_commit, + XLogRecPtr local_commit, + bool go_backward, bool wal_log); +extern XLogRecPtr replorigin_get_progress(RepOriginId node, bool flush); + +extern void replorigin_session_advance(XLogRecPtr remote_commit, + XLogRecPtr local_commit); +extern void replorigin_session_setup(RepOriginId node); +extern void replorigin_session_reset(void); +extern XLogRecPtr replorigin_session_get_progress(bool flush); + +/* Checkpoint/Startup integration */ +extern void CheckPointReplicationOrigin(void); +extern void StartupReplicationOrigin(void); + +/* WAL logging */ +extern void replorigin_redo(XLogReaderState *record); +extern void replorigin_desc(StringInfo buf, XLogReaderState *record); +extern const char *replorigin_identify(uint8 info); + +/* shared memory allocation */ +extern Size ReplicationOriginShmemSize(void); +extern void ReplicationOriginShmemInit(void); + +#endif /* PG_ORIGIN_H */ diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h new file mode 100644 index 0000000..539dc8e --- /dev/null +++ b/src/include/replication/output_plugin.h @@ -0,0 +1,248 @@ +/*------------------------------------------------------------------------- + * output_plugin.h + * PostgreSQL Logical Decode Plugin Interface + * + * Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ +#ifndef OUTPUT_PLUGIN_H +#define OUTPUT_PLUGIN_H + +#include "replication/reorderbuffer.h" + +struct LogicalDecodingContext; +struct OutputPluginCallbacks; + +typedef enum OutputPluginOutputType +{ + OUTPUT_PLUGIN_BINARY_OUTPUT, + OUTPUT_PLUGIN_TEXTUAL_OUTPUT +} OutputPluginOutputType; + +/* + * Options set by the output plugin, in the startup callback. + */ +typedef struct OutputPluginOptions +{ + OutputPluginOutputType output_type; + bool receive_rewrites; +} OutputPluginOptions; + +/* + * Type of the shared library symbol _PG_output_plugin_init that is looked up + * when loading an output plugin shared library. + */ +typedef void (*LogicalOutputPluginInit) (struct OutputPluginCallbacks *cb); + +/* + * Callback that gets called in a user-defined plugin. ctx->private_data can + * be set to some private data. + * + * "is_init" will be set to "true" if the decoding slot just got defined. When + * the same slot is used from there one, it will be "false". + */ +typedef void (*LogicalDecodeStartupCB) (struct LogicalDecodingContext *ctx, + OutputPluginOptions *options, + bool is_init); + +/* + * Callback called for every (explicit or implicit) BEGIN of a successful + * transaction. + */ +typedef void (*LogicalDecodeBeginCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + +/* + * Callback for every individual change in a successful transaction. + */ +typedef void (*LogicalDecodeChangeCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change); + +/* + * Callback for every TRUNCATE in a successful transaction. + */ +typedef void (*LogicalDecodeTruncateCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, + Relation relations[], + ReorderBufferChange *change); + +/* + * Called for every (explicit or implicit) COMMIT of a successful transaction. + */ +typedef void (*LogicalDecodeCommitCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* + * Called for the generic logical decoding messages. + */ +typedef void (*LogicalDecodeMessageCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr message_lsn, + bool transactional, + const char *prefix, + Size message_size, + const char *message); + +/* + * Filter changes by origin. + */ +typedef bool (*LogicalDecodeFilterByOriginCB) (struct LogicalDecodingContext *ctx, + RepOriginId origin_id); + +/* + * Called to shutdown an output plugin. + */ +typedef void (*LogicalDecodeShutdownCB) (struct LogicalDecodingContext *ctx); + +/* + * Called before decoding of PREPARE record to decide whether this + * transaction should be decoded with separate calls to prepare and + * commit_prepared/rollback_prepared callbacks or wait till COMMIT PREPARED + * and sent as usual transaction. + */ +typedef bool (*LogicalDecodeFilterPrepareCB) (struct LogicalDecodingContext *ctx, + TransactionId xid, + const char *gid); + +/* + * Callback called for every BEGIN of a prepared trnsaction. + */ +typedef void (*LogicalDecodeBeginPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + +/* + * Called for PREPARE record unless it was filtered by filter_prepare() + * callback. + */ +typedef void (*LogicalDecodePrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* + * Called for COMMIT PREPARED. + */ +typedef void (*LogicalDecodeCommitPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* + * Called for ROLLBACK PREPARED. + */ +typedef void (*LogicalDecodeRollbackPreparedCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); + + +/* + * Called when starting to stream a block of changes from in-progress + * transaction (may be called repeatedly, if it's streamed in multiple + * chunks). + */ +typedef void (*LogicalDecodeStreamStartCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + +/* + * Called when stopping to stream a block of changes from in-progress + * transaction to a remote node (may be called repeatedly, if it's streamed + * in multiple chunks). + */ +typedef void (*LogicalDecodeStreamStopCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn); + +/* + * Called to discard changes streamed to remote node from in-progress + * transaction. + */ +typedef void (*LogicalDecodeStreamAbortCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr abort_lsn); + +/* + * Called to prepare changes streamed to remote node from in-progress + * transaction. This is called as part of a two-phase commit. + */ +typedef void (*LogicalDecodeStreamPrepareCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* + * Called to apply changes streamed to remote node from in-progress + * transaction. + */ +typedef void (*LogicalDecodeStreamCommitCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* + * Callback for streaming individual changes from in-progress transactions. + */ +typedef void (*LogicalDecodeStreamChangeCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change); + +/* + * Callback for streaming generic logical decoding messages from in-progress + * transactions. + */ +typedef void (*LogicalDecodeStreamMessageCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + XLogRecPtr message_lsn, + bool transactional, + const char *prefix, + Size message_size, + const char *message); + +/* + * Callback for streaming truncates from in-progress transactions. + */ +typedef void (*LogicalDecodeStreamTruncateCB) (struct LogicalDecodingContext *ctx, + ReorderBufferTXN *txn, + int nrelations, + Relation relations[], + ReorderBufferChange *change); + +/* + * Output plugin callbacks + */ +typedef struct OutputPluginCallbacks +{ + LogicalDecodeStartupCB startup_cb; + LogicalDecodeBeginCB begin_cb; + LogicalDecodeChangeCB change_cb; + LogicalDecodeTruncateCB truncate_cb; + LogicalDecodeCommitCB commit_cb; + LogicalDecodeMessageCB message_cb; + LogicalDecodeFilterByOriginCB filter_by_origin_cb; + LogicalDecodeShutdownCB shutdown_cb; + + /* streaming of changes at prepare time */ + LogicalDecodeFilterPrepareCB filter_prepare_cb; + LogicalDecodeBeginPrepareCB begin_prepare_cb; + LogicalDecodePrepareCB prepare_cb; + LogicalDecodeCommitPreparedCB commit_prepared_cb; + LogicalDecodeRollbackPreparedCB rollback_prepared_cb; + + /* streaming of changes */ + LogicalDecodeStreamStartCB stream_start_cb; + LogicalDecodeStreamStopCB stream_stop_cb; + LogicalDecodeStreamAbortCB stream_abort_cb; + LogicalDecodeStreamPrepareCB stream_prepare_cb; + LogicalDecodeStreamCommitCB stream_commit_cb; + LogicalDecodeStreamChangeCB stream_change_cb; + LogicalDecodeStreamMessageCB stream_message_cb; + LogicalDecodeStreamTruncateCB stream_truncate_cb; +} OutputPluginCallbacks; + +/* Functions in replication/logical/logical.c */ +extern void OutputPluginPrepareWrite(struct LogicalDecodingContext *ctx, bool last_write); +extern void OutputPluginWrite(struct LogicalDecodingContext *ctx, bool last_write); +extern void OutputPluginUpdateProgress(struct LogicalDecodingContext *ctx, bool skipped_xact); + +#endif /* OUTPUT_PLUGIN_H */ diff --git a/src/include/replication/pgoutput.h b/src/include/replication/pgoutput.h new file mode 100644 index 0000000..eafedd6 --- /dev/null +++ b/src/include/replication/pgoutput.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * pgoutput.h + * Logical Replication output plugin + * + * Copyright (c) 2015-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/replication/pgoutput.h + * + *------------------------------------------------------------------------- + */ +#ifndef PGOUTPUT_H +#define PGOUTPUT_H + +#include "nodes/pg_list.h" + +typedef struct PGOutputData +{ + MemoryContext context; /* private memory context for transient + * allocations */ + MemoryContext cachectx; /* private memory context for cache data */ + + /* client-supplied info: */ + uint32 protocol_version; + List *publication_names; + List *publications; + bool binary; + bool streaming; + bool messages; + bool two_phase; +} PGOutputData; + +#endif /* PGOUTPUT_H */ diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h new file mode 100644 index 0000000..4a01f87 --- /dev/null +++ b/src/include/replication/reorderbuffer.h @@ -0,0 +1,685 @@ +/* + * reorderbuffer.h + * PostgreSQL logical replay/reorder buffer management. + * + * Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + * src/include/replication/reorderbuffer.h + */ +#ifndef REORDERBUFFER_H +#define REORDERBUFFER_H + +#include "access/htup_details.h" +#include "lib/ilist.h" +#include "storage/sinval.h" +#include "utils/hsearch.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" +#include "utils/timestamp.h" + +extern PGDLLIMPORT int logical_decoding_work_mem; + +/* an individual tuple, stored in one chunk of memory */ +typedef struct ReorderBufferTupleBuf +{ + /* position in preallocated list */ + slist_node node; + + /* tuple header, the interesting bit for users of logical decoding */ + HeapTupleData tuple; + + /* pre-allocated size of tuple buffer, different from tuple size */ + Size alloc_tuple_size; + + /* actual tuple data follows */ +} ReorderBufferTupleBuf; + +/* pointer to the data stored in a TupleBuf */ +#define ReorderBufferTupleBufData(p) \ + ((HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf))) + +/* + * Types of the change passed to a 'change' callback. + * + * For efficiency and simplicity reasons we want to keep Snapshots, CommandIds + * and ComboCids in the same list with the user visible INSERT/UPDATE/DELETE + * changes. Users of the decoding facilities will never see changes with + * *_INTERNAL_* actions. + * + * The INTERNAL_SPEC_INSERT and INTERNAL_SPEC_CONFIRM, and INTERNAL_SPEC_ABORT + * changes concern "speculative insertions", their confirmation, and abort + * respectively. They're used by INSERT .. ON CONFLICT .. UPDATE. Users of + * logical decoding don't have to care about these. + */ +typedef enum ReorderBufferChangeType +{ + REORDER_BUFFER_CHANGE_INSERT, + REORDER_BUFFER_CHANGE_UPDATE, + REORDER_BUFFER_CHANGE_DELETE, + REORDER_BUFFER_CHANGE_MESSAGE, + REORDER_BUFFER_CHANGE_INVALIDATION, + REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT, + REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID, + REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID, + REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT, + REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM, + REORDER_BUFFER_CHANGE_INTERNAL_SPEC_ABORT, + REORDER_BUFFER_CHANGE_TRUNCATE +} ReorderBufferChangeType; + +/* forward declaration */ +struct ReorderBufferTXN; + +/* + * a single 'change', can be an insert (with one tuple), an update (old, new), + * or a delete (old). + * + * The same struct is also used internally for other purposes but that should + * never be visible outside reorderbuffer.c. + */ +typedef struct ReorderBufferChange +{ + XLogRecPtr lsn; + + /* The type of change. */ + ReorderBufferChangeType action; + + /* Transaction this change belongs to. */ + struct ReorderBufferTXN *txn; + + RepOriginId origin_id; + + /* + * Context data for the change. Which part of the union is valid depends + * on action. + */ + union + { + /* Old, new tuples when action == *_INSERT|UPDATE|DELETE */ + struct + { + /* relation that has been changed */ + RelFileNode relnode; + + /* no previously reassembled toast chunks are necessary anymore */ + bool clear_toast_afterwards; + + /* valid for DELETE || UPDATE */ + ReorderBufferTupleBuf *oldtuple; + /* valid for INSERT || UPDATE */ + ReorderBufferTupleBuf *newtuple; + } tp; + + /* + * Truncate data for REORDER_BUFFER_CHANGE_TRUNCATE representing one + * set of relations to be truncated. + */ + struct + { + Size nrelids; + bool cascade; + bool restart_seqs; + Oid *relids; + } truncate; + + /* Message with arbitrary data. */ + struct + { + char *prefix; + Size message_size; + char *message; + } msg; + + /* New snapshot, set when action == *_INTERNAL_SNAPSHOT */ + Snapshot snapshot; + + /* + * New command id for existing snapshot in a catalog changing tx. Set + * when action == *_INTERNAL_COMMAND_ID. + */ + CommandId command_id; + + /* + * New cid mapping for catalog changing transaction, set when action + * == *_INTERNAL_TUPLECID. + */ + struct + { + RelFileNode node; + ItemPointerData tid; + CommandId cmin; + CommandId cmax; + CommandId combocid; + } tuplecid; + + /* Invalidation. */ + struct + { + uint32 ninvalidations; /* Number of messages */ + SharedInvalidationMessage *invalidations; /* invalidation message */ + } inval; + } data; + + /* + * While in use this is how a change is linked into a transactions, + * otherwise it's the preallocated list. + */ + dlist_node node; +} ReorderBufferChange; + +/* ReorderBufferTXN txn_flags */ +#define RBTXN_HAS_CATALOG_CHANGES 0x0001 +#define RBTXN_IS_SUBXACT 0x0002 +#define RBTXN_IS_SERIALIZED 0x0004 +#define RBTXN_IS_SERIALIZED_CLEAR 0x0008 +#define RBTXN_IS_STREAMED 0x0010 +#define RBTXN_HAS_PARTIAL_CHANGE 0x0020 +#define RBTXN_PREPARE 0x0040 +#define RBTXN_SKIPPED_PREPARE 0x0080 + +/* Does the transaction have catalog changes? */ +#define rbtxn_has_catalog_changes(txn) \ +( \ + ((txn)->txn_flags & RBTXN_HAS_CATALOG_CHANGES) != 0 \ +) + +/* Is the transaction known as a subxact? */ +#define rbtxn_is_known_subxact(txn) \ +( \ + ((txn)->txn_flags & RBTXN_IS_SUBXACT) != 0 \ +) + +/* Has this transaction been spilled to disk? */ +#define rbtxn_is_serialized(txn) \ +( \ + ((txn)->txn_flags & RBTXN_IS_SERIALIZED) != 0 \ +) + +/* Has this transaction ever been spilled to disk? */ +#define rbtxn_is_serialized_clear(txn) \ +( \ + ((txn)->txn_flags & RBTXN_IS_SERIALIZED_CLEAR) != 0 \ +) + +/* Has this transaction contains partial changes? */ +#define rbtxn_has_partial_change(txn) \ +( \ + ((txn)->txn_flags & RBTXN_HAS_PARTIAL_CHANGE) != 0 \ +) + +/* + * Has this transaction been streamed to downstream? + * + * (It's not possible to deduce this from nentries and nentries_mem for + * various reasons. For example, all changes may be in subtransactions in + * which case we'd have nentries==0 for the toplevel one, which would say + * nothing about the streaming. So we maintain this flag, but only for the + * toplevel transaction.) + */ +#define rbtxn_is_streamed(txn) \ +( \ + ((txn)->txn_flags & RBTXN_IS_STREAMED) != 0 \ +) + +/* Has this transaction been prepared? */ +#define rbtxn_prepared(txn) \ +( \ + ((txn)->txn_flags & RBTXN_PREPARE) != 0 \ +) + +/* prepare for this transaction skipped? */ +#define rbtxn_skip_prepared(txn) \ +( \ + ((txn)->txn_flags & RBTXN_SKIPPED_PREPARE) != 0 \ +) + +typedef struct ReorderBufferTXN +{ + /* See above */ + bits32 txn_flags; + + /* The transaction's transaction id, can be a toplevel or sub xid. */ + TransactionId xid; + + /* Xid of top-level transaction, if known */ + TransactionId toplevel_xid; + + /* + * Global transaction id required for identification of prepared + * transactions. + */ + char *gid; + + /* + * LSN of the first data carrying, WAL record with knowledge about this + * xid. This is allowed to *not* be first record adorned with this xid, if + * the previous records aren't relevant for logical decoding. + */ + XLogRecPtr first_lsn; + + /* ---- + * LSN of the record that lead to this xact to be prepared or committed or + * aborted. This can be a + * * plain commit record + * * plain commit record, of a parent transaction + * * prepared tansaction + * * prepared transaction commit + * * plain abort record + * * prepared transaction abort + * + * This can also become set to earlier values than transaction end when + * a transaction is spilled to disk; specifically it's set to the LSN of + * the latest change written to disk so far. + * ---- + */ + XLogRecPtr final_lsn; + + /* + * LSN pointing to the end of the commit record + 1. + */ + XLogRecPtr end_lsn; + + /* Toplevel transaction for this subxact (NULL for top-level). */ + struct ReorderBufferTXN *toptxn; + + /* + * LSN of the last lsn at which snapshot information reside, so we can + * restart decoding from there and fully recover this transaction from + * WAL. + */ + XLogRecPtr restart_decoding_lsn; + + /* origin of the change that caused this transaction */ + RepOriginId origin_id; + XLogRecPtr origin_lsn; + + /* + * Commit or Prepare time, only known when we read the actual commit or + * prepare record. + */ + union + { + TimestampTz commit_time; + TimestampTz prepare_time; + } xact_time; + + /* + * The base snapshot is used to decode all changes until either this + * transaction modifies the catalog, or another catalog-modifying + * transaction commits. + */ + Snapshot base_snapshot; + XLogRecPtr base_snapshot_lsn; + dlist_node base_snapshot_node; /* link in txns_by_base_snapshot_lsn */ + + /* + * Snapshot/CID from the previous streaming run. Only valid for already + * streamed transactions (NULL/InvalidCommandId otherwise). + */ + Snapshot snapshot_now; + CommandId command_id; + + /* + * How many ReorderBufferChange's do we have in this txn. + * + * Changes in subtransactions are *not* included but tracked separately. + */ + uint64 nentries; + + /* + * How many of the above entries are stored in memory in contrast to being + * spilled to disk. + */ + uint64 nentries_mem; + + /* + * List of ReorderBufferChange structs, including new Snapshots, new + * CommandIds and command invalidation messages. + */ + dlist_head changes; + + /* + * List of (relation, ctid) => (cmin, cmax) mappings for catalog tuples. + * Those are always assigned to the toplevel transaction. (Keep track of + * #entries to create a hash of the right size) + */ + dlist_head tuplecids; + uint64 ntuplecids; + + /* + * On-demand built hash for looking up the above values. + */ + HTAB *tuplecid_hash; + + /* + * Hash containing (potentially partial) toast entries. NULL if no toast + * tuples have been found for the current change. + */ + HTAB *toast_hash; + + /* + * non-hierarchical list of subtransactions that are *not* aborted. Only + * used in toplevel transactions. + */ + dlist_head subtxns; + uint32 nsubtxns; + + /* + * Stored cache invalidations. This is not a linked list because we get + * all the invalidations at once. + */ + uint32 ninvalidations; + SharedInvalidationMessage *invalidations; + + /* --- + * Position in one of three lists: + * * list of subtransactions if we are *known* to be subxact + * * list of toplevel xacts (can be an as-yet unknown subxact) + * * list of preallocated ReorderBufferTXNs (if unused) + * --- + */ + dlist_node node; + + /* + * Size of this transaction (changes currently in memory, in bytes). + */ + Size size; + + /* Size of top-transaction including sub-transactions. */ + Size total_size; + + /* If we have detected concurrent abort then ignore future changes. */ + bool concurrent_abort; + + /* + * Private data pointer of the output plugin. + */ + void *output_plugin_private; +} ReorderBufferTXN; + +/* so we can define the callbacks used inside struct ReorderBuffer itself */ +typedef struct ReorderBuffer ReorderBuffer; + +/* change callback signature */ +typedef void (*ReorderBufferApplyChangeCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change); + +/* truncate callback signature */ +typedef void (*ReorderBufferApplyTruncateCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + int nrelations, + Relation relations[], + ReorderBufferChange *change); + +/* begin callback signature */ +typedef void (*ReorderBufferBeginCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn); + +/* commit callback signature */ +typedef void (*ReorderBufferCommitCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* message callback signature */ +typedef void (*ReorderBufferMessageCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr message_lsn, + bool transactional, + const char *prefix, Size sz, + const char *message); + +/* begin prepare callback signature */ +typedef void (*ReorderBufferBeginPrepareCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn); + +/* prepare callback signature */ +typedef void (*ReorderBufferPrepareCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* commit prepared callback signature */ +typedef void (*ReorderBufferCommitPreparedCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* rollback prepared callback signature */ +typedef void (*ReorderBufferRollbackPreparedCB) (ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_end_lsn, + TimestampTz prepare_time); + +/* start streaming transaction callback signature */ +typedef void (*ReorderBufferStreamStartCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr first_lsn); + +/* stop streaming transaction callback signature */ +typedef void (*ReorderBufferStreamStopCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr last_lsn); + +/* discard streamed transaction callback signature */ +typedef void (*ReorderBufferStreamAbortCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr abort_lsn); + +/* prepare streamed transaction callback signature */ +typedef void (*ReorderBufferStreamPrepareCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr prepare_lsn); + +/* commit streamed transaction callback signature */ +typedef void (*ReorderBufferStreamCommitCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr commit_lsn); + +/* stream change callback signature */ +typedef void (*ReorderBufferStreamChangeCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + Relation relation, + ReorderBufferChange *change); + +/* stream message callback signature */ +typedef void (*ReorderBufferStreamMessageCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + XLogRecPtr message_lsn, + bool transactional, + const char *prefix, Size sz, + const char *message); + +/* stream truncate callback signature */ +typedef void (*ReorderBufferStreamTruncateCB) ( + ReorderBuffer *rb, + ReorderBufferTXN *txn, + int nrelations, + Relation relations[], + ReorderBufferChange *change); + +struct ReorderBuffer +{ + /* + * xid => ReorderBufferTXN lookup table + */ + HTAB *by_txn; + + /* + * Transactions that could be a toplevel xact, ordered by LSN of the first + * record bearing that xid. + */ + dlist_head toplevel_by_lsn; + + /* + * Transactions and subtransactions that have a base snapshot, ordered by + * LSN of the record which caused us to first obtain the base snapshot. + * This is not the same as toplevel_by_lsn, because we only set the base + * snapshot on the first logical-decoding-relevant record (eg. heap + * writes), whereas the initial LSN could be set by other operations. + */ + dlist_head txns_by_base_snapshot_lsn; + + /* + * one-entry sized cache for by_txn. Very frequently the same txn gets + * looked up over and over again. + */ + TransactionId by_txn_last_xid; + ReorderBufferTXN *by_txn_last_txn; + + /* + * Callbacks to be called when a transactions commits. + */ + ReorderBufferBeginCB begin; + ReorderBufferApplyChangeCB apply_change; + ReorderBufferApplyTruncateCB apply_truncate; + ReorderBufferCommitCB commit; + ReorderBufferMessageCB message; + + /* + * Callbacks to be called when streaming a transaction at prepare time. + */ + ReorderBufferBeginCB begin_prepare; + ReorderBufferPrepareCB prepare; + ReorderBufferCommitPreparedCB commit_prepared; + ReorderBufferRollbackPreparedCB rollback_prepared; + + /* + * Callbacks to be called when streaming a transaction. + */ + ReorderBufferStreamStartCB stream_start; + ReorderBufferStreamStopCB stream_stop; + ReorderBufferStreamAbortCB stream_abort; + ReorderBufferStreamPrepareCB stream_prepare; + ReorderBufferStreamCommitCB stream_commit; + ReorderBufferStreamChangeCB stream_change; + ReorderBufferStreamMessageCB stream_message; + ReorderBufferStreamTruncateCB stream_truncate; + + /* + * Pointer that will be passed untouched to the callbacks. + */ + void *private_data; + + /* + * Saved output plugin option + */ + bool output_rewrites; + + /* + * Private memory context. + */ + MemoryContext context; + + /* + * Memory contexts for specific types objects + */ + MemoryContext change_context; + MemoryContext txn_context; + MemoryContext tup_context; + + XLogRecPtr current_restart_decoding_lsn; + + /* buffer for disk<->memory conversions */ + char *outbuf; + Size outbufsize; + + /* memory accounting */ + Size size; + + /* + * Statistics about transactions spilled to disk. + * + * A single transaction may be spilled repeatedly, which is why we keep + * two different counters. For spilling, the transaction counter includes + * both toplevel transactions and subtransactions. + */ + int64 spillTxns; /* number of transactions spilled to disk */ + int64 spillCount; /* spill-to-disk invocation counter */ + int64 spillBytes; /* amount of data spilled to disk */ + + /* Statistics about transactions streamed to the decoding output plugin */ + int64 streamTxns; /* number of transactions streamed */ + int64 streamCount; /* streaming invocation counter */ + int64 streamBytes; /* amount of data decoded */ + + /* + * Statistics about all the transactions sent to the decoding output + * plugin + */ + int64 totalTxns; /* total number of transactions sent */ + int64 totalBytes; /* total amount of data decoded */ +}; + + +extern ReorderBuffer *ReorderBufferAllocate(void); +extern void ReorderBufferFree(ReorderBuffer *); + +extern ReorderBufferTupleBuf *ReorderBufferGetTupleBuf(ReorderBuffer *, Size tuple_len); +extern void ReorderBufferReturnTupleBuf(ReorderBuffer *, ReorderBufferTupleBuf *tuple); +extern ReorderBufferChange *ReorderBufferGetChange(ReorderBuffer *); +extern void ReorderBufferReturnChange(ReorderBuffer *, ReorderBufferChange *, bool); + +extern Oid *ReorderBufferGetRelids(ReorderBuffer *, int nrelids); +extern void ReorderBufferReturnRelids(ReorderBuffer *, Oid *relids); + +extern void ReorderBufferQueueChange(ReorderBuffer *, TransactionId, + XLogRecPtr lsn, ReorderBufferChange *, + bool toast_insert); +extern void ReorderBufferQueueMessage(ReorderBuffer *, TransactionId, Snapshot snapshot, XLogRecPtr lsn, + bool transactional, const char *prefix, + Size message_size, const char *message); +extern void ReorderBufferCommit(ReorderBuffer *, TransactionId, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn, + TimestampTz commit_time, RepOriginId origin_id, XLogRecPtr origin_lsn); +extern void ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn, + XLogRecPtr two_phase_at, + TimestampTz commit_time, + RepOriginId origin_id, XLogRecPtr origin_lsn, + char *gid, bool is_commit); +extern void ReorderBufferAssignChild(ReorderBuffer *, TransactionId, TransactionId, XLogRecPtr commit_lsn); +extern void ReorderBufferCommitChild(ReorderBuffer *, TransactionId, TransactionId, + XLogRecPtr commit_lsn, XLogRecPtr end_lsn); +extern void ReorderBufferAbort(ReorderBuffer *, TransactionId, XLogRecPtr lsn); +extern void ReorderBufferAbortOld(ReorderBuffer *, TransactionId xid); +extern void ReorderBufferForget(ReorderBuffer *, TransactionId, XLogRecPtr lsn); +extern void ReorderBufferInvalidate(ReorderBuffer *, TransactionId, XLogRecPtr lsn); + +extern void ReorderBufferSetBaseSnapshot(ReorderBuffer *, TransactionId, XLogRecPtr lsn, struct SnapshotData *snap); +extern void ReorderBufferAddSnapshot(ReorderBuffer *, TransactionId, XLogRecPtr lsn, struct SnapshotData *snap); +extern void ReorderBufferAddNewCommandId(ReorderBuffer *, TransactionId, XLogRecPtr lsn, + CommandId cid); +extern void ReorderBufferAddNewTupleCids(ReorderBuffer *, TransactionId, XLogRecPtr lsn, + RelFileNode node, ItemPointerData pt, + CommandId cmin, CommandId cmax, CommandId combocid); +extern void ReorderBufferAddInvalidations(ReorderBuffer *, TransactionId, XLogRecPtr lsn, + Size nmsgs, SharedInvalidationMessage *msgs); +extern void ReorderBufferImmediateInvalidation(ReorderBuffer *, uint32 ninvalidations, + SharedInvalidationMessage *invalidations); +extern void ReorderBufferProcessXid(ReorderBuffer *, TransactionId xid, XLogRecPtr lsn); + +extern void ReorderBufferXidSetCatalogChanges(ReorderBuffer *, TransactionId xid, XLogRecPtr lsn); +extern bool ReorderBufferXidHasCatalogChanges(ReorderBuffer *, TransactionId xid); +extern bool ReorderBufferXidHasBaseSnapshot(ReorderBuffer *, TransactionId xid); + +extern bool ReorderBufferRememberPrepareInfo(ReorderBuffer *rb, TransactionId xid, + XLogRecPtr prepare_lsn, XLogRecPtr end_lsn, + TimestampTz prepare_time, + RepOriginId origin_id, XLogRecPtr origin_lsn); +extern void ReorderBufferSkipPrepare(ReorderBuffer *rb, TransactionId xid); +extern void ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid, char *gid); +extern ReorderBufferTXN *ReorderBufferGetOldestTXN(ReorderBuffer *); +extern TransactionId ReorderBufferGetOldestXmin(ReorderBuffer *rb); + +extern void ReorderBufferSetRestartPoint(ReorderBuffer *, XLogRecPtr ptr); + +extern void StartupReorderBuffer(void); + +#endif diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h new file mode 100644 index 0000000..deba2c4 --- /dev/null +++ b/src/include/replication/slot.h @@ -0,0 +1,230 @@ +/*------------------------------------------------------------------------- + * slot.h + * Replication slot management. + * + * Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ +#ifndef SLOT_H +#define SLOT_H + +#include "access/xlog.h" +#include "access/xlogreader.h" +#include "storage/condition_variable.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "storage/spin.h" +#include "replication/walreceiver.h" + +/* + * Behaviour of replication slots, upon release or crash. + * + * Slots marked as PERSISTENT are crash-safe and will not be dropped when + * released. Slots marked as EPHEMERAL will be dropped when released or after + * restarts. Slots marked TEMPORARY will be dropped at the end of a session + * or on error. + * + * EPHEMERAL is used as a not-quite-ready state when creating persistent + * slots. EPHEMERAL slots can be made PERSISTENT by calling + * ReplicationSlotPersist(). For a slot that goes away at the end of a + * session, TEMPORARY is the appropriate choice. + */ +typedef enum ReplicationSlotPersistency +{ + RS_PERSISTENT, + RS_EPHEMERAL, + RS_TEMPORARY +} ReplicationSlotPersistency; + +/* + * On-Disk data of a replication slot, preserved across restarts. + */ +typedef struct ReplicationSlotPersistentData +{ + /* The slot's identifier */ + NameData name; + + /* database the slot is active on */ + Oid database; + + /* + * The slot's behaviour when being dropped (or restored after a crash). + */ + ReplicationSlotPersistency persistency; + + /* + * xmin horizon for data + * + * NB: This may represent a value that hasn't been written to disk yet; + * see notes for effective_xmin, below. + */ + TransactionId xmin; + + /* + * xmin horizon for catalog tuples + * + * NB: This may represent a value that hasn't been written to disk yet; + * see notes for effective_xmin, below. + */ + TransactionId catalog_xmin; + + /* oldest LSN that might be required by this replication slot */ + XLogRecPtr restart_lsn; + + /* restart_lsn is copied here when the slot is invalidated */ + XLogRecPtr invalidated_at; + + /* + * Oldest LSN that the client has acked receipt for. This is used as the + * start_lsn point in case the client doesn't specify one, and also as a + * safety measure to jump forwards in case the client specifies a + * start_lsn that's further in the past than this value. + */ + XLogRecPtr confirmed_flush; + + /* + * LSN at which we enabled two_phase commit for this slot or LSN at which + * we found a consistent point at the time of slot creation. + */ + XLogRecPtr two_phase_at; + + /* + * Allow decoding of prepared transactions? + */ + bool two_phase; + + /* plugin name */ + NameData plugin; +} ReplicationSlotPersistentData; + +/* + * Shared memory state of a single replication slot. + * + * The in-memory data of replication slots follows a locking model based + * on two linked concepts: + * - A replication slot's in_use flag is switched when added or discarded using + * the LWLock ReplicationSlotControlLock, which needs to be hold in exclusive + * mode when updating the flag by the backend owning the slot and doing the + * operation, while readers (concurrent backends not owning the slot) need + * to hold it in shared mode when looking at replication slot data. + * - Individual fields are protected by mutex where only the backend owning + * the slot is authorized to update the fields from its own slot. The + * backend owning the slot does not need to take this lock when reading its + * own fields, while concurrent backends not owning this slot should take the + * lock when reading this slot's data. + */ +typedef struct ReplicationSlot +{ + /* lock, on same cacheline as effective_xmin */ + slock_t mutex; + + /* is this slot defined */ + bool in_use; + + /* Who is streaming out changes for this slot? 0 in unused slots. */ + pid_t active_pid; + + /* any outstanding modifications? */ + bool just_dirtied; + bool dirty; + + /* + * For logical decoding, it's extremely important that we never remove any + * data that's still needed for decoding purposes, even after a crash; + * otherwise, decoding will produce wrong answers. Ordinary streaming + * replication also needs to prevent old row versions from being removed + * too soon, but the worst consequence we might encounter there is + * unwanted query cancellations on the standby. Thus, for logical + * decoding, this value represents the latest xmin that has actually been + * written to disk, whereas for streaming replication, it's just the same + * as the persistent value (data.xmin). + */ + TransactionId effective_xmin; + TransactionId effective_catalog_xmin; + + /* data surviving shutdowns and crashes */ + ReplicationSlotPersistentData data; + + /* is somebody performing io on this slot? */ + LWLock io_in_progress_lock; + + /* Condition variable signaled when active_pid changes */ + ConditionVariable active_cv; + + /* all the remaining data is only used for logical slots */ + + /* + * When the client has confirmed flushes >= candidate_xmin_lsn we can + * advance the catalog xmin. When restart_valid has been passed, + * restart_lsn can be increased. + */ + TransactionId candidate_catalog_xmin; + XLogRecPtr candidate_xmin_lsn; + XLogRecPtr candidate_restart_valid; + XLogRecPtr candidate_restart_lsn; +} ReplicationSlot; + +#define SlotIsPhysical(slot) ((slot)->data.database == InvalidOid) +#define SlotIsLogical(slot) ((slot)->data.database != InvalidOid) + +/* + * Shared memory control area for all of replication slots. + */ +typedef struct ReplicationSlotCtlData +{ + /* + * This array should be declared [FLEXIBLE_ARRAY_MEMBER], but for some + * reason you can't do that in an otherwise-empty struct. + */ + ReplicationSlot replication_slots[1]; +} ReplicationSlotCtlData; + +/* + * Pointers to shared memory + */ +extern PGDLLIMPORT ReplicationSlotCtlData *ReplicationSlotCtl; +extern PGDLLIMPORT ReplicationSlot *MyReplicationSlot; + +/* GUCs */ +extern PGDLLIMPORT int max_replication_slots; + +/* shmem initialization functions */ +extern Size ReplicationSlotsShmemSize(void); +extern void ReplicationSlotsShmemInit(void); + +/* management of individual slots */ +extern void ReplicationSlotCreate(const char *name, bool db_specific, + ReplicationSlotPersistency p, bool two_phase); +extern void ReplicationSlotPersist(void); +extern void ReplicationSlotDrop(const char *name, bool nowait); + +extern void ReplicationSlotAcquire(const char *name, bool nowait); +extern void ReplicationSlotRelease(void); +extern void ReplicationSlotCleanup(void); +extern void ReplicationSlotSave(void); +extern void ReplicationSlotMarkDirty(void); + +/* misc stuff */ +extern void ReplicationSlotInitialize(void); +extern bool ReplicationSlotValidateName(const char *name, int elevel); +extern void ReplicationSlotReserveWal(void); +extern void ReplicationSlotsComputeRequiredXmin(bool already_locked); +extern void ReplicationSlotsComputeRequiredLSN(void); +extern XLogRecPtr ReplicationSlotsComputeLogicalRestartLSN(void); +extern bool ReplicationSlotsCountDBSlots(Oid dboid, int *nslots, int *nactive); +extern void ReplicationSlotsDropDBSlots(Oid dboid); +extern bool InvalidateObsoleteReplicationSlots(XLogSegNo oldestSegno); +extern ReplicationSlot *SearchNamedReplicationSlot(const char *name, bool need_lock); +extern int ReplicationSlotIndex(ReplicationSlot *slot); +extern bool ReplicationSlotName(int index, Name name); +extern void ReplicationSlotNameForTablesync(Oid suboid, Oid relid, char *syncslotname, int szslot); +extern void ReplicationSlotDropAtPubNode(WalReceiverConn *wrconn, char *slotname, bool missing_ok); + +extern void StartupReplicationSlots(void); +extern void CheckPointReplicationSlots(void); + +extern void CheckSlotRequirements(void); +extern void CheckSlotPermissions(void); + +#endif /* SLOT_H */ diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h new file mode 100644 index 0000000..53d83f3 --- /dev/null +++ b/src/include/replication/snapbuild.h @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------------- + * + * snapbuild.h + * Exports from replication/logical/snapbuild.c. + * + * Copyright (c) 2012-2022, PostgreSQL Global Development Group + * + * src/include/replication/snapbuild.h + * + *------------------------------------------------------------------------- + */ +#ifndef SNAPBUILD_H +#define SNAPBUILD_H + +#include "access/xlogdefs.h" +#include "utils/snapmgr.h" + +typedef enum +{ + /* + * Initial state, we can't do much yet. + */ + SNAPBUILD_START = -1, + + /* + * Collecting committed transactions, to build the initial catalog + * snapshot. + */ + SNAPBUILD_BUILDING_SNAPSHOT = 0, + + /* + * We have collected enough information to decode tuples in transactions + * that started after this. + * + * Once we reached this we start to collect changes. We cannot apply them + * yet, because they might be based on transactions that were still + * running when FULL_SNAPSHOT was reached. + */ + SNAPBUILD_FULL_SNAPSHOT = 1, + + /* + * Found a point after SNAPBUILD_FULL_SNAPSHOT where all transactions that + * were running at that point finished. Till we reach that we hold off + * calling any commit callbacks. + */ + SNAPBUILD_CONSISTENT = 2 +} SnapBuildState; + +/* forward declare so we don't have to expose the struct to the public */ +struct SnapBuild; +typedef struct SnapBuild SnapBuild; + +/* forward declare so we don't have to include reorderbuffer.h */ +struct ReorderBuffer; + +/* forward declare so we don't have to include heapam_xlog.h */ +struct xl_heap_new_cid; +struct xl_running_xacts; + +extern void CheckPointSnapBuild(void); + +extern SnapBuild *AllocateSnapshotBuilder(struct ReorderBuffer *cache, + TransactionId xmin_horizon, XLogRecPtr start_lsn, + bool need_full_snapshot, + XLogRecPtr two_phase_at); +extern void FreeSnapshotBuilder(SnapBuild *cache); + +extern void SnapBuildSnapDecRefcount(Snapshot snap); + +extern Snapshot SnapBuildInitialSnapshot(SnapBuild *builder); +extern const char *SnapBuildExportSnapshot(SnapBuild *snapstate); +extern void SnapBuildClearExportedSnapshot(void); +extern void SnapBuildResetExportedSnapshotState(void); + +extern SnapBuildState SnapBuildCurrentState(SnapBuild *snapstate); +extern Snapshot SnapBuildGetOrBuildSnapshot(SnapBuild *builder, + TransactionId xid); + +extern bool SnapBuildXactNeedsSkip(SnapBuild *snapstate, XLogRecPtr ptr); +extern XLogRecPtr SnapBuildGetTwoPhaseAt(SnapBuild *builder); +extern void SnapBuildSetTwoPhaseAt(SnapBuild *builder, XLogRecPtr ptr); + +extern void SnapBuildCommitTxn(SnapBuild *builder, XLogRecPtr lsn, + TransactionId xid, int nsubxacts, + TransactionId *subxacts); +extern bool SnapBuildProcessChange(SnapBuild *builder, TransactionId xid, + XLogRecPtr lsn); +extern void SnapBuildProcessNewCid(SnapBuild *builder, TransactionId xid, + XLogRecPtr lsn, struct xl_heap_new_cid *cid); +extern void SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, + struct xl_running_xacts *running); +extern void SnapBuildSerializationPoint(SnapBuild *builder, XLogRecPtr lsn); + +extern void SnapBuildXidSetCatalogChanges(SnapBuild *builder, TransactionId xid, + int subxcnt, TransactionId *subxacts, + XLogRecPtr lsn); +#endif /* SNAPBUILD_H */ diff --git a/src/include/replication/syncrep.h b/src/include/replication/syncrep.h new file mode 100644 index 0000000..4d7c90b --- /dev/null +++ b/src/include/replication/syncrep.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- + * + * syncrep.h + * Exports from replication/syncrep.c. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/replication/syncrep.h + * + *------------------------------------------------------------------------- + */ +#ifndef _SYNCREP_H +#define _SYNCREP_H + +#include "access/xlogdefs.h" +#include "utils/guc.h" + +#define SyncRepRequested() \ + (max_wal_senders > 0 && synchronous_commit > SYNCHRONOUS_COMMIT_LOCAL_FLUSH) + +/* SyncRepWaitMode */ +#define SYNC_REP_NO_WAIT (-1) +#define SYNC_REP_WAIT_WRITE 0 +#define SYNC_REP_WAIT_FLUSH 1 +#define SYNC_REP_WAIT_APPLY 2 + +#define NUM_SYNC_REP_WAIT_MODE 3 + +/* syncRepState */ +#define SYNC_REP_NOT_WAITING 0 +#define SYNC_REP_WAITING 1 +#define SYNC_REP_WAIT_COMPLETE 2 + +/* syncrep_method of SyncRepConfigData */ +#define SYNC_REP_PRIORITY 0 +#define SYNC_REP_QUORUM 1 + +/* + * SyncRepGetCandidateStandbys returns an array of these structs, + * one per candidate synchronous walsender. + */ +typedef struct SyncRepStandbyData +{ + /* Copies of relevant fields from WalSnd shared-memory struct */ + pid_t pid; + XLogRecPtr write; + XLogRecPtr flush; + XLogRecPtr apply; + int sync_standby_priority; + /* Index of this walsender in the WalSnd shared-memory array */ + int walsnd_index; + /* This flag indicates whether this struct is about our own process */ + bool is_me; +} SyncRepStandbyData; + +/* + * Struct for the configuration of synchronous replication. + * + * Note: this must be a flat representation that can be held in a single + * chunk of malloc'd memory, so that it can be stored as the "extra" data + * for the synchronous_standby_names GUC. + */ +typedef struct SyncRepConfigData +{ + int config_size; /* total size of this struct, in bytes */ + int num_sync; /* number of sync standbys that we need to + * wait for */ + uint8 syncrep_method; /* method to choose sync standbys */ + int nmembers; /* number of members in the following list */ + /* member_names contains nmembers consecutive nul-terminated C strings */ + char member_names[FLEXIBLE_ARRAY_MEMBER]; +} SyncRepConfigData; + +extern PGDLLIMPORT SyncRepConfigData *SyncRepConfig; + +/* communication variables for parsing synchronous_standby_names GUC */ +extern PGDLLIMPORT SyncRepConfigData *syncrep_parse_result; +extern PGDLLIMPORT char *syncrep_parse_error_msg; + +/* user-settable parameters for synchronous replication */ +extern PGDLLIMPORT char *SyncRepStandbyNames; + +/* called by user backend */ +extern void SyncRepWaitForLSN(XLogRecPtr lsn, bool commit); + +/* called at backend exit */ +extern void SyncRepCleanupAtProcExit(void); + +/* called by wal sender */ +extern void SyncRepInitConfig(void); +extern void SyncRepReleaseWaiters(void); + +/* called by wal sender and user backend */ +extern int SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys); + +/* called by checkpointer */ +extern void SyncRepUpdateSyncStandbysDefined(void); + +/* GUC infrastructure */ +extern bool check_synchronous_standby_names(char **newval, void **extra, GucSource source); +extern void assign_synchronous_standby_names(const char *newval, void *extra); +extern void assign_synchronous_commit(int newval, void *extra); + +/* + * Internal functions for parsing synchronous_standby_names grammar, + * in syncrep_gram.y and syncrep_scanner.l + */ +extern int syncrep_yyparse(void); +extern int syncrep_yylex(void); +extern void syncrep_yyerror(const char *str); +extern void syncrep_scanner_init(const char *query_string); +extern void syncrep_scanner_finish(void); + +#endif /* _SYNCREP_H */ diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h new file mode 100644 index 0000000..81184aa --- /dev/null +++ b/src/include/replication/walreceiver.h @@ -0,0 +1,472 @@ +/*------------------------------------------------------------------------- + * + * walreceiver.h + * Exports from replication/walreceiverfuncs.c. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/replication/walreceiver.h + * + *------------------------------------------------------------------------- + */ +#ifndef _WALRECEIVER_H +#define _WALRECEIVER_H + +#include "access/xlog.h" +#include "access/xlogdefs.h" +#include "getaddrinfo.h" /* for NI_MAXHOST */ +#include "pgtime.h" +#include "port/atomics.h" +#include "replication/logicalproto.h" +#include "replication/walsender.h" +#include "storage/condition_variable.h" +#include "storage/latch.h" +#include "storage/spin.h" +#include "utils/tuplestore.h" + +/* user-settable parameters */ +extern PGDLLIMPORT int wal_receiver_status_interval; +extern PGDLLIMPORT int wal_receiver_timeout; +extern PGDLLIMPORT bool hot_standby_feedback; + +/* + * MAXCONNINFO: maximum size of a connection string. + * + * XXX: Should this move to pg_config_manual.h? + */ +#define MAXCONNINFO 1024 + +/* Can we allow the standby to accept replication connection from another standby? */ +#define AllowCascadeReplication() (EnableHotStandby && max_wal_senders > 0) + +/* + * Values for WalRcv->walRcvState. + */ +typedef enum +{ + WALRCV_STOPPED, /* stopped and mustn't start up again */ + WALRCV_STARTING, /* launched, but the process hasn't + * initialized yet */ + WALRCV_STREAMING, /* walreceiver is streaming */ + WALRCV_WAITING, /* stopped streaming, waiting for orders */ + WALRCV_RESTARTING, /* asked to restart streaming */ + WALRCV_STOPPING /* requested to stop, but still running */ +} WalRcvState; + +/* Shared memory area for management of walreceiver process */ +typedef struct +{ + /* + * PID of currently active walreceiver process, its current state and + * start time (actually, the time at which it was requested to be + * started). + */ + pid_t pid; + WalRcvState walRcvState; + ConditionVariable walRcvStoppedCV; + pg_time_t startTime; + + /* + * receiveStart and receiveStartTLI indicate the first byte position and + * timeline that will be received. When startup process starts the + * walreceiver, it sets these to the point where it wants the streaming to + * begin. + */ + XLogRecPtr receiveStart; + TimeLineID receiveStartTLI; + + /* + * flushedUpto-1 is the last byte position that has already been received, + * and receivedTLI is the timeline it came from. At the first startup of + * walreceiver, these are set to receiveStart and receiveStartTLI. After + * that, walreceiver updates these whenever it flushes the received WAL to + * disk. + */ + XLogRecPtr flushedUpto; + TimeLineID receivedTLI; + + /* + * latestChunkStart is the starting byte position of the current "batch" + * of received WAL. It's actually the same as the previous value of + * flushedUpto before the last flush to disk. Startup process can use + * this to detect whether it's keeping up or not. + */ + XLogRecPtr latestChunkStart; + + /* + * Time of send and receive of any message received. + */ + TimestampTz lastMsgSendTime; + TimestampTz lastMsgReceiptTime; + + /* + * Latest reported end of WAL on the sender + */ + XLogRecPtr latestWalEnd; + TimestampTz latestWalEndTime; + + /* + * connection string; initially set to connect to the primary, and later + * clobbered to hide security-sensitive fields. + */ + char conninfo[MAXCONNINFO]; + + /* + * Host name (this can be a host name, an IP address, or a directory path) + * and port number of the active replication connection. + */ + char sender_host[NI_MAXHOST]; + int sender_port; + + /* + * replication slot name; is also used for walreceiver to connect with the + * primary + */ + char slotname[NAMEDATALEN]; + + /* + * If it's a temporary replication slot, it needs to be recreated when + * connecting. + */ + bool is_temp_slot; + + /* set true once conninfo is ready to display (obfuscated pwds etc) */ + bool ready_to_display; + + /* + * Latch used by startup process to wake up walreceiver after telling it + * where to start streaming (after setting receiveStart and + * receiveStartTLI), and also to tell it to send apply feedback to the + * primary whenever specially marked commit records are applied. This is + * normally mapped to procLatch when walreceiver is running. + */ + Latch *latch; + + slock_t mutex; /* locks shared variables shown above */ + + /* + * Like flushedUpto, but advanced after writing and before flushing, + * without the need to acquire the spin lock. Data can be read by another + * process up to this point, but shouldn't be used for data integrity + * purposes. + */ + pg_atomic_uint64 writtenUpto; + + /* + * force walreceiver reply? This doesn't need to be locked; memory + * barriers for ordering are sufficient. But we do need atomic fetch and + * store semantics, so use sig_atomic_t. + */ + sig_atomic_t force_reply; /* used as a bool */ +} WalRcvData; + +extern PGDLLIMPORT WalRcvData *WalRcv; + +typedef struct +{ + bool logical; /* True if this is logical replication stream, + * false if physical stream. */ + char *slotname; /* Name of the replication slot or NULL. */ + XLogRecPtr startpoint; /* LSN of starting point. */ + + union + { + struct + { + TimeLineID startpointTLI; /* Starting timeline */ + } physical; + struct + { + uint32 proto_version; /* Logical protocol version */ + List *publication_names; /* String list of publications */ + bool binary; /* Ask publisher to use binary */ + bool streaming; /* Streaming of large transactions */ + bool twophase; /* Streaming of two-phase transactions at + * prepare time */ + } logical; + } proto; +} WalRcvStreamOptions; + +struct WalReceiverConn; +typedef struct WalReceiverConn WalReceiverConn; + +/* + * Status of walreceiver query execution. + * + * We only define statuses that are currently used. + */ +typedef enum +{ + WALRCV_ERROR, /* There was error when executing the query. */ + WALRCV_OK_COMMAND, /* Query executed utility or replication + * command. */ + WALRCV_OK_TUPLES, /* Query returned tuples. */ + WALRCV_OK_COPY_IN, /* Query started COPY FROM. */ + WALRCV_OK_COPY_OUT, /* Query started COPY TO. */ + WALRCV_OK_COPY_BOTH /* Query started COPY BOTH replication + * protocol. */ +} WalRcvExecStatus; + +/* + * Return value for walrcv_exec, returns the status of the execution and + * tuples if any. + */ +typedef struct WalRcvExecResult +{ + WalRcvExecStatus status; + int sqlstate; + char *err; + Tuplestorestate *tuplestore; + TupleDesc tupledesc; +} WalRcvExecResult; + +/* WAL receiver - libpqwalreceiver hooks */ + +/* + * walrcv_connect_fn + * + * Establish connection to a cluster. 'logical' is true if the + * connection is logical, and false if the connection is physical. + * 'appname' is a name associated to the connection, to use for example + * with fallback_application_name or application_name. Returns the + * details about the connection established, as defined by + * WalReceiverConn for each WAL receiver module. On error, NULL is + * returned with 'err' including the error generated. + */ +typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, + bool logical, + const char *appname, + char **err); + +/* + * walrcv_check_conninfo_fn + * + * Parse and validate the connection string given as of 'conninfo'. + */ +typedef void (*walrcv_check_conninfo_fn) (const char *conninfo); + +/* + * walrcv_get_conninfo_fn + * + * Returns a user-displayable conninfo string. Note that any + * security-sensitive fields should be obfuscated. + */ +typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn); + +/* + * walrcv_get_senderinfo_fn + * + * Provide information of the WAL sender this WAL receiver is connected + * to, as of 'sender_host' for the host of the sender and 'sender_port' + * for its port. + */ +typedef void (*walrcv_get_senderinfo_fn) (WalReceiverConn *conn, + char **sender_host, + int *sender_port); + +/* + * walrcv_identify_system_fn + * + * Run IDENTIFY_SYSTEM on the cluster connected to and validate the + * identity of the cluster. Returns the system ID of the cluster + * connected to. 'primary_tli' is the timeline ID of the sender. + */ +typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn, + TimeLineID *primary_tli); + +/* + * walrcv_server_version_fn + * + * Returns the version number of the cluster connected to. + */ +typedef int (*walrcv_server_version_fn) (WalReceiverConn *conn); + +/* + * walrcv_readtimelinehistoryfile_fn + * + * Fetch from cluster the timeline history file for timeline 'tli'. + * Returns the name of the timeline history file as of 'filename', its + * contents as of 'content' and its 'size'. + */ +typedef void (*walrcv_readtimelinehistoryfile_fn) (WalReceiverConn *conn, + TimeLineID tli, + char **filename, + char **content, + int *size); + +/* + * walrcv_startstreaming_fn + * + * Start streaming WAL data from given streaming options. Returns true + * if the connection has switched successfully to copy-both mode and false + * if the server received the command and executed it successfully, but + * didn't switch to copy-mode. + */ +typedef bool (*walrcv_startstreaming_fn) (WalReceiverConn *conn, + const WalRcvStreamOptions *options); + +/* + * walrcv_endstreaming_fn + * + * Stop streaming of WAL data. Returns the next timeline ID of the cluster + * connected to in 'next_tli', or 0 if there was no report. + */ +typedef void (*walrcv_endstreaming_fn) (WalReceiverConn *conn, + TimeLineID *next_tli); + +/* + * walrcv_receive_fn + * + * Receive a message available from the WAL stream. 'buffer' is a pointer + * to a buffer holding the message received. Returns the length of the data, + * 0 if no data is available yet ('wait_fd' is a socket descriptor which can + * be waited on before a retry), and -1 if the cluster ended the COPY. + */ +typedef int (*walrcv_receive_fn) (WalReceiverConn *conn, + char **buffer, + pgsocket *wait_fd); + +/* + * walrcv_send_fn + * + * Send a message of size 'nbytes' to the WAL stream with 'buffer' as + * contents. + */ +typedef void (*walrcv_send_fn) (WalReceiverConn *conn, + const char *buffer, + int nbytes); + +/* + * walrcv_create_slot_fn + * + * Create a new replication slot named 'slotname'. 'temporary' defines + * if the slot is temporary. 'snapshot_action' defines the behavior wanted + * for an exported snapshot (see replication protocol for more details). + * 'lsn' includes the LSN position at which the created slot became + * consistent. Returns the name of the exported snapshot for a logical + * slot, or NULL for a physical slot. + */ +typedef char *(*walrcv_create_slot_fn) (WalReceiverConn *conn, + const char *slotname, + bool temporary, + bool two_phase, + CRSSnapshotAction snapshot_action, + XLogRecPtr *lsn); + +/* + * walrcv_get_backend_pid_fn + * + * Returns the PID of the remote backend process. + */ +typedef pid_t (*walrcv_get_backend_pid_fn) (WalReceiverConn *conn); + +/* + * walrcv_exec_fn + * + * Send generic queries (and commands) to the remote cluster. 'nRetTypes' + * is the expected number of returned attributes, and 'retTypes' an array + * including their type OIDs. Returns the status of the execution and + * tuples if any. + */ +typedef WalRcvExecResult *(*walrcv_exec_fn) (WalReceiverConn *conn, + const char *query, + const int nRetTypes, + const Oid *retTypes); + +/* + * walrcv_disconnect_fn + * + * Disconnect with the cluster. + */ +typedef void (*walrcv_disconnect_fn) (WalReceiverConn *conn); + +typedef struct WalReceiverFunctionsType +{ + walrcv_connect_fn walrcv_connect; + walrcv_check_conninfo_fn walrcv_check_conninfo; + walrcv_get_conninfo_fn walrcv_get_conninfo; + walrcv_get_senderinfo_fn walrcv_get_senderinfo; + walrcv_identify_system_fn walrcv_identify_system; + walrcv_server_version_fn walrcv_server_version; + walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile; + walrcv_startstreaming_fn walrcv_startstreaming; + walrcv_endstreaming_fn walrcv_endstreaming; + walrcv_receive_fn walrcv_receive; + walrcv_send_fn walrcv_send; + walrcv_create_slot_fn walrcv_create_slot; + walrcv_get_backend_pid_fn walrcv_get_backend_pid; + walrcv_exec_fn walrcv_exec; + walrcv_disconnect_fn walrcv_disconnect; +} WalReceiverFunctionsType; + +extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions; + +#define walrcv_connect(conninfo, logical, appname, err) \ + WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err) +#define walrcv_check_conninfo(conninfo) \ + WalReceiverFunctions->walrcv_check_conninfo(conninfo) +#define walrcv_get_conninfo(conn) \ + WalReceiverFunctions->walrcv_get_conninfo(conn) +#define walrcv_get_senderinfo(conn, sender_host, sender_port) \ + WalReceiverFunctions->walrcv_get_senderinfo(conn, sender_host, sender_port) +#define walrcv_identify_system(conn, primary_tli) \ + WalReceiverFunctions->walrcv_identify_system(conn, primary_tli) +#define walrcv_server_version(conn) \ + WalReceiverFunctions->walrcv_server_version(conn) +#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \ + WalReceiverFunctions->walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) +#define walrcv_startstreaming(conn, options) \ + WalReceiverFunctions->walrcv_startstreaming(conn, options) +#define walrcv_endstreaming(conn, next_tli) \ + WalReceiverFunctions->walrcv_endstreaming(conn, next_tli) +#define walrcv_receive(conn, buffer, wait_fd) \ + WalReceiverFunctions->walrcv_receive(conn, buffer, wait_fd) +#define walrcv_send(conn, buffer, nbytes) \ + WalReceiverFunctions->walrcv_send(conn, buffer, nbytes) +#define walrcv_create_slot(conn, slotname, temporary, two_phase, snapshot_action, lsn) \ + WalReceiverFunctions->walrcv_create_slot(conn, slotname, temporary, two_phase, snapshot_action, lsn) +#define walrcv_get_backend_pid(conn) \ + WalReceiverFunctions->walrcv_get_backend_pid(conn) +#define walrcv_exec(conn, exec, nRetTypes, retTypes) \ + WalReceiverFunctions->walrcv_exec(conn, exec, nRetTypes, retTypes) +#define walrcv_disconnect(conn) \ + WalReceiverFunctions->walrcv_disconnect(conn) + +static inline void +walrcv_clear_result(WalRcvExecResult *walres) +{ + if (!walres) + return; + + if (walres->err) + pfree(walres->err); + + if (walres->tuplestore) + tuplestore_end(walres->tuplestore); + + if (walres->tupledesc) + FreeTupleDesc(walres->tupledesc); + + pfree(walres); +} + +/* prototypes for functions in walreceiver.c */ +extern void WalReceiverMain(void) pg_attribute_noreturn(); +extern void ProcessWalRcvInterrupts(void); + +/* prototypes for functions in walreceiverfuncs.c */ +extern Size WalRcvShmemSize(void); +extern void WalRcvShmemInit(void); +extern void ShutdownWalRcv(void); +extern bool WalRcvStreaming(void); +extern bool WalRcvRunning(void); +extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, + const char *conninfo, const char *slotname, + bool create_temp_slot); +extern XLogRecPtr GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI); +extern XLogRecPtr GetWalRcvWriteRecPtr(void); +extern int GetReplicationApplyDelay(void); +extern int GetReplicationTransferLatency(void); +extern void WalRcvForceReply(void); + +#endif /* _WALRECEIVER_H */ diff --git a/src/include/replication/walsender.h b/src/include/replication/walsender.h new file mode 100644 index 0000000..d99a21b --- /dev/null +++ b/src/include/replication/walsender.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * walsender.h + * Exports from replication/walsender.c. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/replication/walsender.h + * + *------------------------------------------------------------------------- + */ +#ifndef _WALSENDER_H +#define _WALSENDER_H + +#include <signal.h> + +/* + * What to do with a snapshot in create replication slot command. + */ +typedef enum +{ + CRS_EXPORT_SNAPSHOT, + CRS_NOEXPORT_SNAPSHOT, + CRS_USE_SNAPSHOT +} CRSSnapshotAction; + +/* global state */ +extern PGDLLIMPORT bool am_walsender; +extern PGDLLIMPORT bool am_cascading_walsender; +extern PGDLLIMPORT bool am_db_walsender; +extern PGDLLIMPORT bool wake_wal_senders; + +/* user-settable parameters */ +extern PGDLLIMPORT int max_wal_senders; +extern PGDLLIMPORT int wal_sender_timeout; +extern PGDLLIMPORT bool log_replication_commands; + +extern void InitWalSender(void); +extern bool exec_replication_command(const char *query_string); +extern void WalSndErrorCleanup(void); +extern void WalSndResourceCleanup(bool isCommit); +extern void WalSndSignals(void); +extern Size WalSndShmemSize(void); +extern void WalSndShmemInit(void); +extern void WalSndWakeup(void); +extern void WalSndInitStopping(void); +extern void WalSndWaitStopping(void); +extern void HandleWalSndInitStopping(void); +extern void WalSndRqstFileReload(void); + +/* + * Remember that we want to wakeup walsenders later + * + * This is separated from doing the actual wakeup because the writeout is done + * while holding contended locks. + */ +#define WalSndWakeupRequest() \ + do { wake_wal_senders = true; } while (0) + +/* + * wakeup walsenders if there is work to be done + */ +#define WalSndWakeupProcessRequests() \ + do \ + { \ + if (wake_wal_senders) \ + { \ + wake_wal_senders = false; \ + if (max_wal_senders > 0) \ + WalSndWakeup(); \ + } \ + } while (0) + +#endif /* _WALSENDER_H */ diff --git a/src/include/replication/walsender_private.h b/src/include/replication/walsender_private.h new file mode 100644 index 0000000..c14888e --- /dev/null +++ b/src/include/replication/walsender_private.h @@ -0,0 +1,128 @@ +/*------------------------------------------------------------------------- + * + * walsender_private.h + * Private definitions from replication/walsender.c. + * + * Portions Copyright (c) 2010-2022, PostgreSQL Global Development Group + * + * src/include/replication/walsender_private.h + * + *------------------------------------------------------------------------- + */ +#ifndef _WALSENDER_PRIVATE_H +#define _WALSENDER_PRIVATE_H + +#include "access/xlog.h" +#include "nodes/nodes.h" +#include "replication/syncrep.h" +#include "storage/latch.h" +#include "storage/shmem.h" +#include "storage/spin.h" + +typedef enum WalSndState +{ + WALSNDSTATE_STARTUP = 0, + WALSNDSTATE_BACKUP, + WALSNDSTATE_CATCHUP, + WALSNDSTATE_STREAMING, + WALSNDSTATE_STOPPING +} WalSndState; + +/* + * Each walsender has a WalSnd struct in shared memory. + * + * This struct is protected by its 'mutex' spinlock field, except that some + * members are only written by the walsender process itself, and thus that + * process is free to read those members without holding spinlock. pid and + * needreload always require the spinlock to be held for all accesses. + */ +typedef struct WalSnd +{ + pid_t pid; /* this walsender's PID, or 0 if not active */ + + WalSndState state; /* this walsender's state */ + XLogRecPtr sentPtr; /* WAL has been sent up to this point */ + bool needreload; /* does currently-open file need to be + * reloaded? */ + + /* + * The xlog locations that have been written, flushed, and applied by + * standby-side. These may be invalid if the standby-side has not offered + * values yet. + */ + XLogRecPtr write; + XLogRecPtr flush; + XLogRecPtr apply; + + /* Measured lag times, or -1 for unknown/none. */ + TimeOffset writeLag; + TimeOffset flushLag; + TimeOffset applyLag; + + /* + * The priority order of the standby managed by this WALSender, as listed + * in synchronous_standby_names, or 0 if not-listed. + */ + int sync_standby_priority; + + /* Protects shared variables shown above. */ + slock_t mutex; + + /* + * Pointer to the walsender's latch. Used by backends to wake up this + * walsender when it has work to do. NULL if the walsender isn't active. + */ + Latch *latch; + + /* + * Timestamp of the last message received from standby. + */ + TimestampTz replyTime; +} WalSnd; + +extern PGDLLIMPORT WalSnd *MyWalSnd; + +/* There is one WalSndCtl struct for the whole database cluster */ +typedef struct +{ + /* + * Synchronous replication queue with one queue per request type. + * Protected by SyncRepLock. + */ + SHM_QUEUE SyncRepQueue[NUM_SYNC_REP_WAIT_MODE]; + + /* + * Current location of the head of the queue. All waiters should have a + * waitLSN that follows this value. Protected by SyncRepLock. + */ + XLogRecPtr lsn[NUM_SYNC_REP_WAIT_MODE]; + + /* + * Are any sync standbys defined? Waiting backends can't reload the + * config file safely, so checkpointer updates this value as needed. + * Protected by SyncRepLock. + */ + bool sync_standbys_defined; + + WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER]; +} WalSndCtlData; + +extern PGDLLIMPORT WalSndCtlData *WalSndCtl; + + +extern void WalSndSetState(WalSndState state); + +/* + * Internal functions for parsing the replication grammar, in repl_gram.y and + * repl_scanner.l + */ +extern int replication_yyparse(void); +extern int replication_yylex(void); +extern void replication_yyerror(const char *str) pg_attribute_noreturn(); +extern void replication_scanner_init(const char *query_string); +extern void replication_scanner_finish(void); +extern bool replication_scanner_is_replication_command(void); + +extern PGDLLIMPORT Node *replication_parse_result; + +#endif /* _WALSENDER_PRIVATE_H */ diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h new file mode 100644 index 0000000..901845a --- /dev/null +++ b/src/include/replication/worker_internal.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * worker_internal.h + * Internal headers shared by logical replication workers. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * src/include/replication/worker_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef WORKER_INTERNAL_H +#define WORKER_INTERNAL_H + +#include <signal.h> + +#include "access/xlogdefs.h" +#include "catalog/pg_subscription.h" +#include "datatype/timestamp.h" +#include "storage/fileset.h" +#include "storage/lock.h" +#include "storage/spin.h" + + +typedef struct LogicalRepWorker +{ + /* Time at which this worker was launched. */ + TimestampTz launch_time; + + /* Indicates if this slot is used or free. */ + bool in_use; + + /* Increased every time the slot is taken by new worker. */ + uint16 generation; + + /* Pointer to proc array. NULL if not running. */ + PGPROC *proc; + + /* Database id to connect to. */ + Oid dbid; + + /* User to use for connection (will be same as owner of subscription). */ + Oid userid; + + /* Subscription id for the worker. */ + Oid subid; + + /* Used for initial table synchronization. */ + Oid relid; + char relstate; + XLogRecPtr relstate_lsn; + slock_t relmutex; + + /* + * Used to create the changes and subxact files for the streaming + * transactions. Upon the arrival of the first streaming transaction, the + * fileset will be initialized, and it will be deleted when the worker + * exits. Under this, separate buffiles would be created for each + * transaction which will be deleted after the transaction is finished. + */ + FileSet *stream_fileset; + + /* Stats. */ + XLogRecPtr last_lsn; + TimestampTz last_send_time; + TimestampTz last_recv_time; + XLogRecPtr reply_lsn; + TimestampTz reply_time; +} LogicalRepWorker; + +/* Main memory context for apply worker. Permanent during worker lifetime. */ +extern PGDLLIMPORT MemoryContext ApplyContext; + +/* libpqreceiver connection */ +extern PGDLLIMPORT struct WalReceiverConn *LogRepWorkerWalRcvConn; + +/* Worker and subscription objects. */ +extern PGDLLIMPORT Subscription *MySubscription; +extern PGDLLIMPORT LogicalRepWorker *MyLogicalRepWorker; + +extern PGDLLIMPORT bool in_remote_transaction; + +extern void logicalrep_worker_attach(int slot); +extern LogicalRepWorker *logicalrep_worker_find(Oid subid, Oid relid, + bool only_running); +extern List *logicalrep_workers_find(Oid subid, bool only_running); +extern void logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname, + Oid userid, Oid relid); +extern void logicalrep_worker_stop(Oid subid, Oid relid); +extern void logicalrep_worker_wakeup(Oid subid, Oid relid); +extern void logicalrep_worker_wakeup_ptr(LogicalRepWorker *worker); + +extern int logicalrep_sync_worker_count(Oid subid); + +extern void ReplicationOriginNameForTablesync(Oid suboid, Oid relid, + char *originname, int szorgname); +extern char *LogicalRepSyncTableStart(XLogRecPtr *origin_startpos); + +extern bool AllTablesyncsReady(void); +extern void UpdateTwoPhaseState(Oid suboid, char new_state); + +extern void process_syncing_tables(XLogRecPtr current_lsn); +extern void invalidate_syncing_table_states(Datum arg, int cacheid, + uint32 hashvalue); + +static inline bool +am_tablesync_worker(void) +{ + return OidIsValid(MyLogicalRepWorker->relid); +} + +#endif /* WORKER_INTERNAL_H */ diff --git a/src/include/rewrite/prs2lock.h b/src/include/rewrite/prs2lock.h new file mode 100644 index 0000000..6d98483 --- /dev/null +++ b/src/include/rewrite/prs2lock.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- + * + * prs2lock.h + * data structures for POSTGRES Rule System II (rewrite rules only) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/prs2lock.h + * + *------------------------------------------------------------------------- + */ +#ifndef PRS2LOCK_H +#define PRS2LOCK_H + +#include "access/attnum.h" +#include "nodes/pg_list.h" + +/* + * RewriteRule - + * holds an info for a rewrite rule + * + */ +typedef struct RewriteRule +{ + Oid ruleId; + CmdType event; + Node *qual; + List *actions; + char enabled; + bool isInstead; +} RewriteRule; + +/* + * RuleLock - + * all rules that apply to a particular relation. Even though we only + * have the rewrite rule system left and these are not really "locks", + * the name is kept for historical reasons. + */ +typedef struct RuleLock +{ + int numLocks; + RewriteRule **rules; +} RuleLock; + +#endif /* PRS2LOCK_H */ diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h new file mode 100644 index 0000000..2a0d493 --- /dev/null +++ b/src/include/rewrite/rewriteDefine.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------- + * + * rewriteDefine.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteDefine.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITEDEFINE_H +#define REWRITEDEFINE_H + +#include "catalog/objectaddress.h" +#include "nodes/parsenodes.h" +#include "utils/relcache.h" + +#define RULE_FIRES_ON_ORIGIN 'O' +#define RULE_FIRES_ALWAYS 'A' +#define RULE_FIRES_ON_REPLICA 'R' +#define RULE_DISABLED 'D' + +extern ObjectAddress DefineRule(RuleStmt *stmt, const char *queryString); + +extern ObjectAddress DefineQueryRewrite(const char *rulename, + Oid event_relid, + Node *event_qual, + CmdType event_type, + bool is_instead, + bool replace, + List *action); + +extern ObjectAddress RenameRewriteRule(RangeVar *relation, const char *oldName, + const char *newName); + +extern void setRuleCheckAsUser(Node *node, Oid userid); + +extern void EnableDisableRule(Relation rel, const char *rulename, + char fires_when); + +#endif /* REWRITEDEFINE_H */ diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h new file mode 100644 index 0000000..b4f96f2 --- /dev/null +++ b/src/include/rewrite/rewriteHandler.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * rewriteHandler.h + * External interface to query rewriter. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteHandler.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITEHANDLER_H +#define REWRITEHANDLER_H + +#include "nodes/parsenodes.h" +#include "utils/relcache.h" + +extern List *QueryRewrite(Query *parsetree); +extern void AcquireRewriteLocks(Query *parsetree, + bool forExecute, + bool forUpdatePushedDown); + +extern Node *build_column_default(Relation rel, int attrno); + +extern Query *get_view_query(Relation view); +extern const char *view_query_is_auto_updatable(Query *viewquery, + bool check_cols); +extern int relation_is_updatable(Oid reloid, + List *outer_reloids, + bool include_triggers, + Bitmapset *include_cols); + +#endif /* REWRITEHANDLER_H */ diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h new file mode 100644 index 0000000..98b9b3a --- /dev/null +++ b/src/include/rewrite/rewriteManip.h @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------- + * + * rewriteManip.h + * Querytree manipulation subroutines for query rewriter. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteManip.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITEMANIP_H +#define REWRITEMANIP_H + +#include "nodes/parsenodes.h" + +struct AttrMap; /* avoid including attmap.h here */ + + +typedef struct replace_rte_variables_context replace_rte_variables_context; + +typedef Node *(*replace_rte_variables_callback) (Var *var, + replace_rte_variables_context *context); + +struct replace_rte_variables_context +{ + replace_rte_variables_callback callback; /* callback function */ + void *callback_arg; /* context data for callback function */ + int target_varno; /* RTE index to search for */ + int sublevels_up; /* (current) nesting depth */ + bool inserted_sublink; /* have we inserted a SubLink? */ +}; + +typedef enum ReplaceVarsNoMatchOption +{ + REPLACEVARS_REPORT_ERROR, /* throw error if no match */ + REPLACEVARS_CHANGE_VARNO, /* change the Var's varno, nothing else */ + REPLACEVARS_SUBSTITUTE_NULL /* replace with a NULL Const */ +} ReplaceVarsNoMatchOption; + + +extern void OffsetVarNodes(Node *node, int offset, int sublevels_up); +extern void ChangeVarNodes(Node *node, int old_varno, int new_varno, + int sublevels_up); +extern void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, + int min_sublevels_up); +extern void IncrementVarSublevelsUp_rtable(List *rtable, + int delta_sublevels_up, int min_sublevels_up); + +extern bool rangeTableEntry_used(Node *node, int rt_index, + int sublevels_up); + +extern Query *getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr); + +extern void AddQual(Query *parsetree, Node *qual); +extern void AddInvertedQual(Query *parsetree, Node *qual); + +extern bool contain_aggs_of_level(Node *node, int levelsup); +extern int locate_agg_of_level(Node *node, int levelsup); +extern bool contain_windowfuncs(Node *node); +extern int locate_windowfunc(Node *node); +extern bool checkExprHasSubLink(Node *node); + +extern Node *replace_rte_variables(Node *node, + int target_varno, int sublevels_up, + replace_rte_variables_callback callback, + void *callback_arg, + bool *outer_hasSubLinks); +extern Node *replace_rte_variables_mutator(Node *node, + replace_rte_variables_context *context); + +extern Node *map_variable_attnos(Node *node, + int target_varno, int sublevels_up, + const struct AttrMap *attno_map, + Oid to_rowtype, bool *found_whole_row); + +extern Node *ReplaceVarsFromTargetList(Node *node, + int target_varno, int sublevels_up, + RangeTblEntry *target_rte, + List *targetlist, + ReplaceVarsNoMatchOption nomatch_option, + int nomatch_varno, + bool *outer_hasSubLinks); + +#endif /* REWRITEMANIP_H */ diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h new file mode 100644 index 0000000..8e039eb --- /dev/null +++ b/src/include/rewrite/rewriteRemove.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * rewriteRemove.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteRemove.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITEREMOVE_H +#define REWRITEREMOVE_H + +#include "nodes/parsenodes.h" + +extern void RemoveRewriteRuleById(Oid ruleOid); + +#endif /* REWRITEREMOVE_H */ diff --git a/src/include/rewrite/rewriteSearchCycle.h b/src/include/rewrite/rewriteSearchCycle.h new file mode 100644 index 0000000..d8aac03 --- /dev/null +++ b/src/include/rewrite/rewriteSearchCycle.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * rewriteSearchCycle.h + * Support for rewriting SEARCH and CYCLE clauses. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteSearchCycle.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITESEARCHCYCLE_H +#define REWRITESEARCHCYCLE_H + +#include "nodes/parsenodes.h" + +extern CommonTableExpr *rewriteSearchAndCycle(CommonTableExpr *cte); + +#endif /* REWRITESEARCHCYCLE_H */ diff --git a/src/include/rewrite/rewriteSupport.h b/src/include/rewrite/rewriteSupport.h new file mode 100644 index 0000000..226ff66 --- /dev/null +++ b/src/include/rewrite/rewriteSupport.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * rewriteSupport.h + * + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rewrite/rewriteSupport.h + * + *------------------------------------------------------------------------- + */ +#ifndef REWRITESUPPORT_H +#define REWRITESUPPORT_H + +/* The ON SELECT rule of a view is always named this: */ +#define ViewSelectRuleName "_RETURN" + +extern bool IsDefinedRewriteRule(Oid owningRel, const char *ruleName); + +extern void SetRelationRuleStatus(Oid relationId, bool relHasRules); + +extern Oid get_rewrite_oid(Oid relid, const char *rulename, bool missing_ok); + +#endif /* REWRITESUPPORT_H */ diff --git a/src/include/rewrite/rowsecurity.h b/src/include/rewrite/rowsecurity.h new file mode 100644 index 0000000..8798e71 --- /dev/null +++ b/src/include/rewrite/rowsecurity.h @@ -0,0 +1,49 @@ +/* ------------------------------------------------------------------------- + * + * rowsecurity.h + * + * prototypes for rewrite/rowsecurity.c and the structures for managing + * the row security policies for relations in relcache. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#ifndef ROWSECURITY_H +#define ROWSECURITY_H + +#include "nodes/parsenodes.h" +#include "utils/array.h" +#include "utils/relcache.h" + +typedef struct RowSecurityPolicy +{ + char *policy_name; /* Name of the policy */ + char polcmd; /* Type of command policy is for */ + ArrayType *roles; /* Array of roles policy is for */ + bool permissive; /* restrictive or permissive policy */ + Expr *qual; /* Expression to filter rows */ + Expr *with_check_qual; /* Expression to limit rows allowed */ + bool hassublinks; /* If either expression has sublinks */ +} RowSecurityPolicy; + +typedef struct RowSecurityDesc +{ + MemoryContext rscxt; /* row security memory context */ + List *policies; /* list of row security policies */ +} RowSecurityDesc; + +typedef List *(*row_security_policy_hook_type) (CmdType cmdtype, + Relation relation); + +extern PGDLLIMPORT row_security_policy_hook_type row_security_policy_hook_permissive; + +extern PGDLLIMPORT row_security_policy_hook_type row_security_policy_hook_restrictive; + +extern void get_row_security_policies(Query *root, + RangeTblEntry *rte, int rt_index, + List **securityQuals, List **withCheckOptions, + bool *hasRowSecurity, bool *hasSubLinks); + +#endif /* ROWSECURITY_H */ diff --git a/src/include/rusagestub.h b/src/include/rusagestub.h new file mode 100644 index 0000000..b887eff --- /dev/null +++ b/src/include/rusagestub.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + * + * rusagestub.h + * Stubs for getrusage(3). + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/rusagestub.h + * + *------------------------------------------------------------------------- + */ +#ifndef RUSAGESTUB_H +#define RUSAGESTUB_H + +#include <sys/time.h> /* for struct timeval */ +#ifndef WIN32 +#include <sys/times.h> /* for struct tms */ +#endif +#include <limits.h> /* for CLK_TCK */ + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN (-1) + +struct rusage +{ + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ +}; + +extern int getrusage(int who, struct rusage *rusage); + +#endif /* RUSAGESTUB_H */ diff --git a/src/include/snowball/header.h b/src/include/snowball/header.h new file mode 100644 index 0000000..850b72e --- /dev/null +++ b/src/include/snowball/header.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- + * + * header.h + * Replacement header file for Snowball stemmer modules + * + * The Snowball stemmer modules do #include "header.h", and think they + * are including snowball/libstemmer/header.h. We adjust the CPPFLAGS + * so that this file is found instead, and thereby we can modify the + * headers they see. The main point here is to ensure that pg_config.h + * is included before any system headers such as <stdio.h>; without that, + * we have portability issues on some platforms due to variation in + * largefile options across different modules in the backend. + * + * NOTE: this file should not be included into any non-snowball sources! + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/snowball/header.h + * + *------------------------------------------------------------------------- + */ +#ifndef SNOWBALL_HEADR_H +#define SNOWBALL_HEADR_H + +/* + * It's against Postgres coding conventions to include postgres.h in a + * header file, but we allow the violation here because the alternative is + * to modify the machine-generated .c files provided by the Snowball project. + */ +#include "postgres.h" + +/* Some platforms define MAXINT and/or MININT, causing conflicts */ +#ifdef MAXINT +#undef MAXINT +#endif +#ifdef MININT +#undef MININT +#endif + +/* Now we can include the original Snowball header.h */ +#include "snowball/libstemmer/header.h" /* pgrminclude ignore */ + +/* + * Redefine standard memory allocation interface to pgsql's one. + * This allows us to control where the Snowball code allocates stuff. + */ +#ifdef malloc +#undef malloc +#endif +#define malloc(a) palloc(a) + +#ifdef calloc +#undef calloc +#endif +#define calloc(a,b) palloc0((a) * (b)) + +#ifdef realloc +#undef realloc +#endif +#define realloc(a,b) repalloc(a,b) + +#ifdef free +#undef free +#endif +#define free(a) pfree(a) + +#endif /* SNOWBALL_HEADR_H */ diff --git a/src/include/snowball/libstemmer/api.h b/src/include/snowball/libstemmer/api.h new file mode 100644 index 0000000..ba9d1c1 --- /dev/null +++ b/src/include/snowball/libstemmer/api.h @@ -0,0 +1,32 @@ + +typedef unsigned char symbol; + +/* Or replace 'char' above with 'short' for 16 bit characters. + + More precisely, replace 'char' with whatever type guarantees the + character width you need. Note however that sizeof(symbol) should divide + HEAD, defined in header.h as 2*sizeof(int), without remainder, otherwise + there is an alignment problem. In the unlikely event of a problem here, + consult Martin Porter. + +*/ + +struct SN_env { + symbol * p; + int c; int l; int lb; int bra; int ket; + symbol * * S; + int * I; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * SN_create_env(int S_size, int I_size); +extern void SN_close_env(struct SN_env * z, int S_size); + +extern int SN_set_current(struct SN_env * z, int size, const symbol * s); + +#ifdef __cplusplus +} +#endif diff --git a/src/include/snowball/libstemmer/header.h b/src/include/snowball/libstemmer/header.h new file mode 100644 index 0000000..bf172d5 --- /dev/null +++ b/src/include/snowball/libstemmer/header.h @@ -0,0 +1,61 @@ + +#include <limits.h> + +#include "api.h" + +#define MAXINT INT_MAX +#define MININT INT_MIN + +#define HEAD 2*sizeof(int) + +#define SIZE(p) ((int *)(p))[-1] +#define SET_SIZE(p, n) ((int *)(p))[-1] = n +#define CAPACITY(p) ((int *)(p))[-2] + +struct among +{ int s_size; /* number of chars in string */ + const symbol * s; /* search string */ + int substring_i;/* index to longest matching substring */ + int result; /* result of the lookup */ + int (* function)(struct SN_env *); +}; + +extern symbol * create_s(void); +extern void lose_s(symbol * p); + +extern int skip_utf8(const symbol * p, int c, int limit, int n); + +extern int skip_b_utf8(const symbol * p, int c, int limit, int n); + +extern int in_grouping_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int in_grouping_b_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int out_grouping_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int out_grouping_b_U(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); + +extern int in_grouping(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int in_grouping_b(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int out_grouping(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); +extern int out_grouping_b(struct SN_env * z, const unsigned char * s, int min, int max, int repeat); + +extern int eq_s(struct SN_env * z, int s_size, const symbol * s); +extern int eq_s_b(struct SN_env * z, int s_size, const symbol * s); +extern int eq_v(struct SN_env * z, const symbol * p); +extern int eq_v_b(struct SN_env * z, const symbol * p); + +extern int find_among(struct SN_env * z, const struct among * v, int v_size); +extern int find_among_b(struct SN_env * z, const struct among * v, int v_size); + +extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s, int * adjustment); +extern int slice_from_s(struct SN_env * z, int s_size, const symbol * s); +extern int slice_from_v(struct SN_env * z, const symbol * p); +extern int slice_del(struct SN_env * z); + +extern int insert_s(struct SN_env * z, int bra, int ket, int s_size, const symbol * s); +extern int insert_v(struct SN_env * z, int bra, int ket, const symbol * p); + +extern symbol * slice_to(struct SN_env * z, symbol * p); +extern symbol * assign_to(struct SN_env * z, symbol * p); + +extern int len_utf8(const symbol * p); + +extern void debug(struct SN_env * z, int number, int line_count); diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_basque.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_basque.h new file mode 100644 index 0000000..bffb6e9 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_basque.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * basque_ISO_8859_1_create_env(void); +extern void basque_ISO_8859_1_close_env(struct SN_env * z); + +extern int basque_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_catalan.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_catalan.h new file mode 100644 index 0000000..96e97dd --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_catalan.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * catalan_ISO_8859_1_create_env(void); +extern void catalan_ISO_8859_1_close_env(struct SN_env * z); + +extern int catalan_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_danish.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_danish.h new file mode 100644 index 0000000..965436d --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_danish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * danish_ISO_8859_1_create_env(void); +extern void danish_ISO_8859_1_close_env(struct SN_env * z); + +extern int danish_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_dutch.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_dutch.h new file mode 100644 index 0000000..64f1c6d --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_dutch.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * dutch_ISO_8859_1_create_env(void); +extern void dutch_ISO_8859_1_close_env(struct SN_env * z); + +extern int dutch_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_english.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_english.h new file mode 100644 index 0000000..ea90984 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_english.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * english_ISO_8859_1_create_env(void); +extern void english_ISO_8859_1_close_env(struct SN_env * z); + +extern int english_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_finnish.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_finnish.h new file mode 100644 index 0000000..2c80e4c --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_finnish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * finnish_ISO_8859_1_create_env(void); +extern void finnish_ISO_8859_1_close_env(struct SN_env * z); + +extern int finnish_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_french.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_french.h new file mode 100644 index 0000000..1febb49 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_french.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * french_ISO_8859_1_create_env(void); +extern void french_ISO_8859_1_close_env(struct SN_env * z); + +extern int french_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_german.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_german.h new file mode 100644 index 0000000..98696bb --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_german.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * german_ISO_8859_1_create_env(void); +extern void german_ISO_8859_1_close_env(struct SN_env * z); + +extern int german_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_indonesian.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_indonesian.h new file mode 100644 index 0000000..d998b41 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_indonesian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * indonesian_ISO_8859_1_create_env(void); +extern void indonesian_ISO_8859_1_close_env(struct SN_env * z); + +extern int indonesian_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_irish.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_irish.h new file mode 100644 index 0000000..d91d231 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_irish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * irish_ISO_8859_1_create_env(void); +extern void irish_ISO_8859_1_close_env(struct SN_env * z); + +extern int irish_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_italian.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_italian.h new file mode 100644 index 0000000..22950bd --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_italian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * italian_ISO_8859_1_create_env(void); +extern void italian_ISO_8859_1_close_env(struct SN_env * z); + +extern int italian_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_norwegian.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_norwegian.h new file mode 100644 index 0000000..5393096 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_norwegian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * norwegian_ISO_8859_1_create_env(void); +extern void norwegian_ISO_8859_1_close_env(struct SN_env * z); + +extern int norwegian_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_porter.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_porter.h new file mode 100644 index 0000000..f504be1 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_porter.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * porter_ISO_8859_1_create_env(void); +extern void porter_ISO_8859_1_close_env(struct SN_env * z); + +extern int porter_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_portuguese.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_portuguese.h new file mode 100644 index 0000000..c7b517c --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_portuguese.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * portuguese_ISO_8859_1_create_env(void); +extern void portuguese_ISO_8859_1_close_env(struct SN_env * z); + +extern int portuguese_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_spanish.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_spanish.h new file mode 100644 index 0000000..b066b4f --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_spanish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * spanish_ISO_8859_1_create_env(void); +extern void spanish_ISO_8859_1_close_env(struct SN_env * z); + +extern int spanish_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_1_swedish.h b/src/include/snowball/libstemmer/stem_ISO_8859_1_swedish.h new file mode 100644 index 0000000..7b5ec75 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_1_swedish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * swedish_ISO_8859_1_create_env(void); +extern void swedish_ISO_8859_1_close_env(struct SN_env * z); + +extern int swedish_ISO_8859_1_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_2_hungarian.h b/src/include/snowball/libstemmer/stem_ISO_8859_2_hungarian.h new file mode 100644 index 0000000..be6ebf6 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_2_hungarian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * hungarian_ISO_8859_2_create_env(void); +extern void hungarian_ISO_8859_2_close_env(struct SN_env * z); + +extern int hungarian_ISO_8859_2_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_ISO_8859_2_romanian.h b/src/include/snowball/libstemmer/stem_ISO_8859_2_romanian.h new file mode 100644 index 0000000..a7acc38 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_ISO_8859_2_romanian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * romanian_ISO_8859_2_create_env(void); +extern void romanian_ISO_8859_2_close_env(struct SN_env * z); + +extern int romanian_ISO_8859_2_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_KOI8_R_russian.h b/src/include/snowball/libstemmer/stem_KOI8_R_russian.h new file mode 100644 index 0000000..42a8518 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_KOI8_R_russian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * russian_KOI8_R_create_env(void); +extern void russian_KOI8_R_close_env(struct SN_env * z); + +extern int russian_KOI8_R_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_arabic.h b/src/include/snowball/libstemmer/stem_UTF_8_arabic.h new file mode 100644 index 0000000..cad02f3 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_arabic.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * arabic_UTF_8_create_env(void); +extern void arabic_UTF_8_close_env(struct SN_env * z); + +extern int arabic_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_armenian.h b/src/include/snowball/libstemmer/stem_UTF_8_armenian.h new file mode 100644 index 0000000..793fd09 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_armenian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * armenian_UTF_8_create_env(void); +extern void armenian_UTF_8_close_env(struct SN_env * z); + +extern int armenian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_basque.h b/src/include/snowball/libstemmer/stem_UTF_8_basque.h new file mode 100644 index 0000000..79ddc98 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_basque.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * basque_UTF_8_create_env(void); +extern void basque_UTF_8_close_env(struct SN_env * z); + +extern int basque_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_catalan.h b/src/include/snowball/libstemmer/stem_UTF_8_catalan.h new file mode 100644 index 0000000..58c9995 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_catalan.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * catalan_UTF_8_create_env(void); +extern void catalan_UTF_8_close_env(struct SN_env * z); + +extern int catalan_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_danish.h b/src/include/snowball/libstemmer/stem_UTF_8_danish.h new file mode 100644 index 0000000..a5084dc --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_danish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * danish_UTF_8_create_env(void); +extern void danish_UTF_8_close_env(struct SN_env * z); + +extern int danish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_dutch.h b/src/include/snowball/libstemmer/stem_UTF_8_dutch.h new file mode 100644 index 0000000..16cb995 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_dutch.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * dutch_UTF_8_create_env(void); +extern void dutch_UTF_8_close_env(struct SN_env * z); + +extern int dutch_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_english.h b/src/include/snowball/libstemmer/stem_UTF_8_english.h new file mode 100644 index 0000000..11fa090 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_english.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * english_UTF_8_create_env(void); +extern void english_UTF_8_close_env(struct SN_env * z); + +extern int english_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_finnish.h b/src/include/snowball/libstemmer/stem_UTF_8_finnish.h new file mode 100644 index 0000000..eebaa2d --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_finnish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * finnish_UTF_8_create_env(void); +extern void finnish_UTF_8_close_env(struct SN_env * z); + +extern int finnish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_french.h b/src/include/snowball/libstemmer/stem_UTF_8_french.h new file mode 100644 index 0000000..22158b0 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_french.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * french_UTF_8_create_env(void); +extern void french_UTF_8_close_env(struct SN_env * z); + +extern int french_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_german.h b/src/include/snowball/libstemmer/stem_UTF_8_german.h new file mode 100644 index 0000000..f276c53 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_german.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * german_UTF_8_create_env(void); +extern void german_UTF_8_close_env(struct SN_env * z); + +extern int german_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_greek.h b/src/include/snowball/libstemmer/stem_UTF_8_greek.h new file mode 100644 index 0000000..77667a3 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_greek.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * greek_UTF_8_create_env(void); +extern void greek_UTF_8_close_env(struct SN_env * z); + +extern int greek_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_hindi.h b/src/include/snowball/libstemmer/stem_UTF_8_hindi.h new file mode 100644 index 0000000..bbc2e9b --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_hindi.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * hindi_UTF_8_create_env(void); +extern void hindi_UTF_8_close_env(struct SN_env * z); + +extern int hindi_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_hungarian.h b/src/include/snowball/libstemmer/stem_UTF_8_hungarian.h new file mode 100644 index 0000000..cc29d77 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_hungarian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * hungarian_UTF_8_create_env(void); +extern void hungarian_UTF_8_close_env(struct SN_env * z); + +extern int hungarian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_indonesian.h b/src/include/snowball/libstemmer/stem_UTF_8_indonesian.h new file mode 100644 index 0000000..9f51324 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_indonesian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * indonesian_UTF_8_create_env(void); +extern void indonesian_UTF_8_close_env(struct SN_env * z); + +extern int indonesian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_irish.h b/src/include/snowball/libstemmer/stem_UTF_8_irish.h new file mode 100644 index 0000000..f06da96 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_irish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * irish_UTF_8_create_env(void); +extern void irish_UTF_8_close_env(struct SN_env * z); + +extern int irish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_italian.h b/src/include/snowball/libstemmer/stem_UTF_8_italian.h new file mode 100644 index 0000000..f00dcaa --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_italian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * italian_UTF_8_create_env(void); +extern void italian_UTF_8_close_env(struct SN_env * z); + +extern int italian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_lithuanian.h b/src/include/snowball/libstemmer/stem_UTF_8_lithuanian.h new file mode 100644 index 0000000..e62ff1c --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_lithuanian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * lithuanian_UTF_8_create_env(void); +extern void lithuanian_UTF_8_close_env(struct SN_env * z); + +extern int lithuanian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_nepali.h b/src/include/snowball/libstemmer/stem_UTF_8_nepali.h new file mode 100644 index 0000000..f8f50af --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_nepali.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * nepali_UTF_8_create_env(void); +extern void nepali_UTF_8_close_env(struct SN_env * z); + +extern int nepali_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_norwegian.h b/src/include/snowball/libstemmer/stem_UTF_8_norwegian.h new file mode 100644 index 0000000..72aab40 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_norwegian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * norwegian_UTF_8_create_env(void); +extern void norwegian_UTF_8_close_env(struct SN_env * z); + +extern int norwegian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_porter.h b/src/include/snowball/libstemmer/stem_UTF_8_porter.h new file mode 100644 index 0000000..00685b2 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_porter.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * porter_UTF_8_create_env(void); +extern void porter_UTF_8_close_env(struct SN_env * z); + +extern int porter_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_portuguese.h b/src/include/snowball/libstemmer/stem_UTF_8_portuguese.h new file mode 100644 index 0000000..7be4335 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_portuguese.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * portuguese_UTF_8_create_env(void); +extern void portuguese_UTF_8_close_env(struct SN_env * z); + +extern int portuguese_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_romanian.h b/src/include/snowball/libstemmer/stem_UTF_8_romanian.h new file mode 100644 index 0000000..c93cd33 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_romanian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * romanian_UTF_8_create_env(void); +extern void romanian_UTF_8_close_env(struct SN_env * z); + +extern int romanian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_russian.h b/src/include/snowball/libstemmer/stem_UTF_8_russian.h new file mode 100644 index 0000000..ca1d882 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_russian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * russian_UTF_8_create_env(void); +extern void russian_UTF_8_close_env(struct SN_env * z); + +extern int russian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_serbian.h b/src/include/snowball/libstemmer/stem_UTF_8_serbian.h new file mode 100644 index 0000000..1df04f6 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_serbian.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * serbian_UTF_8_create_env(void); +extern void serbian_UTF_8_close_env(struct SN_env * z); + +extern int serbian_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_spanish.h b/src/include/snowball/libstemmer/stem_UTF_8_spanish.h new file mode 100644 index 0000000..dfd8dc3 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_spanish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * spanish_UTF_8_create_env(void); +extern void spanish_UTF_8_close_env(struct SN_env * z); + +extern int spanish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_swedish.h b/src/include/snowball/libstemmer/stem_UTF_8_swedish.h new file mode 100644 index 0000000..ca08a64 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_swedish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * swedish_UTF_8_create_env(void); +extern void swedish_UTF_8_close_env(struct SN_env * z); + +extern int swedish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_tamil.h b/src/include/snowball/libstemmer/stem_UTF_8_tamil.h new file mode 100644 index 0000000..5f5ae35 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_tamil.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * tamil_UTF_8_create_env(void); +extern void tamil_UTF_8_close_env(struct SN_env * z); + +extern int tamil_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_turkish.h b/src/include/snowball/libstemmer/stem_UTF_8_turkish.h new file mode 100644 index 0000000..6840592 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_turkish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * turkish_UTF_8_create_env(void); +extern void turkish_UTF_8_close_env(struct SN_env * z); + +extern int turkish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/snowball/libstemmer/stem_UTF_8_yiddish.h b/src/include/snowball/libstemmer/stem_UTF_8_yiddish.h new file mode 100644 index 0000000..55b6625 --- /dev/null +++ b/src/include/snowball/libstemmer/stem_UTF_8_yiddish.h @@ -0,0 +1,15 @@ +/* Generated by Snowball 2.2.0 - https://snowballstem.org/ */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct SN_env * yiddish_UTF_8_create_env(void); +extern void yiddish_UTF_8_close_env(struct SN_env * z); + +extern int yiddish_UTF_8_stem(struct SN_env * z); + +#ifdef __cplusplus +} +#endif + diff --git a/src/include/statistics/extended_stats_internal.h b/src/include/statistics/extended_stats_internal.h new file mode 100644 index 0000000..71f852c --- /dev/null +++ b/src/include/statistics/extended_stats_internal.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- + * + * extended_stats_internal.h + * POSTGRES extended statistics internal declarations + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/statistics/extended_stats_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXTENDED_STATS_INTERNAL_H +#define EXTENDED_STATS_INTERNAL_H + +#include "statistics/statistics.h" +#include "utils/sortsupport.h" + +typedef struct +{ + Oid eqopr; /* '=' operator for datatype, if any */ + Oid eqfunc; /* and associated function */ + Oid ltopr; /* '<' operator for datatype, if any */ +} StdAnalyzeData; + +typedef struct +{ + Datum value; /* a data value */ + int tupno; /* position index for tuple it came from */ +} ScalarItem; + +/* (de)serialization info */ +typedef struct DimensionInfo +{ + int nvalues; /* number of deduplicated values */ + int nbytes; /* number of bytes (serialized) */ + int nbytes_aligned; /* size of deserialized data with alignment */ + int typlen; /* pg_type.typlen */ + bool typbyval; /* pg_type.typbyval */ +} DimensionInfo; + +/* multi-sort */ +typedef struct MultiSortSupportData +{ + int ndims; /* number of dimensions */ + /* sort support data for each dimension: */ + SortSupportData ssup[FLEXIBLE_ARRAY_MEMBER]; +} MultiSortSupportData; + +typedef MultiSortSupportData *MultiSortSupport; + +typedef struct SortItem +{ + Datum *values; + bool *isnull; + int count; +} SortItem; + +/* a unified representation of the data the statistics is built on */ +typedef struct StatsBuildData +{ + int numrows; + int nattnums; + AttrNumber *attnums; + VacAttrStats **stats; + Datum **values; + bool **nulls; +} StatsBuildData; + + +extern MVNDistinct *statext_ndistinct_build(double totalrows, StatsBuildData *data); +extern bytea *statext_ndistinct_serialize(MVNDistinct *ndistinct); +extern MVNDistinct *statext_ndistinct_deserialize(bytea *data); + +extern MVDependencies *statext_dependencies_build(StatsBuildData *data); +extern bytea *statext_dependencies_serialize(MVDependencies *dependencies); +extern MVDependencies *statext_dependencies_deserialize(bytea *data); + +extern MCVList *statext_mcv_build(StatsBuildData *data, + double totalrows, int stattarget); +extern bytea *statext_mcv_serialize(MCVList *mcv, VacAttrStats **stats); +extern MCVList *statext_mcv_deserialize(bytea *data); + +extern MultiSortSupport multi_sort_init(int ndims); +extern void multi_sort_add_dimension(MultiSortSupport mss, int sortdim, + Oid oper, Oid collation); +extern int multi_sort_compare(const void *a, const void *b, void *arg); +extern int multi_sort_compare_dim(int dim, const SortItem *a, + const SortItem *b, MultiSortSupport mss); +extern int multi_sort_compare_dims(int start, int end, const SortItem *a, + const SortItem *b, MultiSortSupport mss); +extern int compare_scalars_simple(const void *a, const void *b, void *arg); +extern int compare_datums_simple(Datum a, Datum b, SortSupport ssup); + +extern AttrNumber *build_attnums_array(Bitmapset *attrs, int nexprs, int *numattrs); + +extern SortItem *build_sorted_items(StatsBuildData *data, int *nitems, + MultiSortSupport mss, + int numattrs, AttrNumber *attnums); + +extern bool examine_opclause_args(List *args, Node **exprp, + Const **cstp, bool *expronleftp); + +extern Selectivity mcv_combine_selectivities(Selectivity simple_sel, + Selectivity mcv_sel, + Selectivity mcv_basesel, + Selectivity mcv_totalsel); + +extern Selectivity mcv_clauselist_selectivity(PlannerInfo *root, + StatisticExtInfo *stat, + List *clauses, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo, + RelOptInfo *rel, + Selectivity *basesel, + Selectivity *totalsel); + +extern Selectivity mcv_clause_selectivity_or(PlannerInfo *root, + StatisticExtInfo *stat, + MCVList *mcv, + Node *clause, + bool **or_matches, + Selectivity *basesel, + Selectivity *overlap_mcvsel, + Selectivity *overlap_basesel, + Selectivity *totalsel); + +#endif /* EXTENDED_STATS_INTERNAL_H */ diff --git a/src/include/statistics/statistics.h b/src/include/statistics/statistics.h new file mode 100644 index 0000000..bb7ef12 --- /dev/null +++ b/src/include/statistics/statistics.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- + * + * statistics.h + * Extended statistics and selectivity estimation functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/statistics/statistics.h + * + *------------------------------------------------------------------------- + */ +#ifndef STATISTICS_H +#define STATISTICS_H + +#include "commands/vacuum.h" +#include "nodes/pathnodes.h" + +#define STATS_MAX_DIMENSIONS 8 /* max number of attributes */ + +/* Multivariate distinct coefficients */ +#define STATS_NDISTINCT_MAGIC 0xA352BFA4 /* struct identifier */ +#define STATS_NDISTINCT_TYPE_BASIC 1 /* struct version */ + +/* MVNDistinctItem represents a single combination of columns */ +typedef struct MVNDistinctItem +{ + double ndistinct; /* ndistinct value for this combination */ + int nattributes; /* number of attributes */ + AttrNumber *attributes; /* attribute numbers */ +} MVNDistinctItem; + +/* A MVNDistinct object, comprising all possible combinations of columns */ +typedef struct MVNDistinct +{ + uint32 magic; /* magic constant marker */ + uint32 type; /* type of ndistinct (BASIC) */ + uint32 nitems; /* number of items in the statistic */ + MVNDistinctItem items[FLEXIBLE_ARRAY_MEMBER]; +} MVNDistinct; + +/* Multivariate functional dependencies */ +#define STATS_DEPS_MAGIC 0xB4549A2C /* marks serialized bytea */ +#define STATS_DEPS_TYPE_BASIC 1 /* basic dependencies type */ + +/* + * Functional dependencies, tracking column-level relationships (values + * in one column determine values in another one). + */ +typedef struct MVDependency +{ + double degree; /* degree of validity (0-1) */ + AttrNumber nattributes; /* number of attributes */ + AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]; /* attribute numbers */ +} MVDependency; + +typedef struct MVDependencies +{ + uint32 magic; /* magic constant marker */ + uint32 type; /* type of MV Dependencies (BASIC) */ + uint32 ndeps; /* number of dependencies */ + MVDependency *deps[FLEXIBLE_ARRAY_MEMBER]; /* dependencies */ +} MVDependencies; + +/* used to flag stats serialized to bytea */ +#define STATS_MCV_MAGIC 0xE1A651C2 /* marks serialized bytea */ +#define STATS_MCV_TYPE_BASIC 1 /* basic MCV list type */ + +/* max items in MCV list (should be equal to max default_statistics_target) */ +#define STATS_MCVLIST_MAX_ITEMS 10000 + +/* + * Multivariate MCV (most-common value) lists + * + * A straightforward extension of MCV items - i.e. a list (array) of + * combinations of attribute values, together with a frequency and null flags. + */ +typedef struct MCVItem +{ + double frequency; /* frequency of this combination */ + double base_frequency; /* frequency if independent */ + bool *isnull; /* NULL flags */ + Datum *values; /* item values */ +} MCVItem; + +/* multivariate MCV list - essentially an array of MCV items */ +typedef struct MCVList +{ + uint32 magic; /* magic constant marker */ + uint32 type; /* type of MCV list (BASIC) */ + uint32 nitems; /* number of MCV items in the array */ + AttrNumber ndimensions; /* number of dimensions */ + Oid types[STATS_MAX_DIMENSIONS]; /* OIDs of data types */ + MCVItem items[FLEXIBLE_ARRAY_MEMBER]; /* array of MCV items */ +} MCVList; + +extern MVNDistinct *statext_ndistinct_load(Oid mvoid, bool inh); +extern MVDependencies *statext_dependencies_load(Oid mvoid, bool inh); +extern MCVList *statext_mcv_load(Oid mvoid, bool inh); + +extern void BuildRelationExtStatistics(Relation onerel, bool inh, double totalrows, + int numrows, HeapTuple *rows, + int natts, VacAttrStats **vacattrstats); +extern int ComputeExtStatisticsRows(Relation onerel, + int natts, VacAttrStats **stats); +extern bool statext_is_kind_built(HeapTuple htup, char kind); +extern Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, + List *clauses, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo, + RelOptInfo *rel, + Bitmapset **estimatedclauses); +extern Selectivity statext_clauselist_selectivity(PlannerInfo *root, + List *clauses, + int varRelid, + JoinType jointype, + SpecialJoinInfo *sjinfo, + RelOptInfo *rel, + Bitmapset **estimatedclauses, + bool is_or); +extern bool has_stats_of_kind(List *stats, char requiredkind); +extern StatisticExtInfo *choose_best_statistics(List *stats, char requiredkind, + bool inh, + Bitmapset **clause_attnums, + List **clause_exprs, + int nclauses); +extern HeapTuple statext_expressions_load(Oid stxoid, bool inh, int idx); + +#endif /* STATISTICS_H */ diff --git a/src/include/storage/.gitignore b/src/include/storage/.gitignore new file mode 100644 index 0000000..209c8be --- /dev/null +++ b/src/include/storage/.gitignore @@ -0,0 +1 @@ +/lwlocknames.h diff --git a/src/include/storage/backendid.h b/src/include/storage/backendid.h new file mode 100644 index 0000000..93d5b50 --- /dev/null +++ b/src/include/storage/backendid.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * backendid.h + * POSTGRES backend id communication definitions + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/backendid.h + * + *------------------------------------------------------------------------- + */ +#ifndef BACKENDID_H +#define BACKENDID_H + +/* ---------------- + * -cim 8/17/90 + * ---------------- + */ +typedef int BackendId; /* unique currently active backend identifier */ + +#define InvalidBackendId (-1) + +extern PGDLLIMPORT BackendId MyBackendId; /* backend id of this backend */ + +/* backend id of our parallel session leader, or InvalidBackendId if none */ +extern PGDLLIMPORT BackendId ParallelLeaderBackendId; + +/* + * The BackendId to use for our session's temp relations is normally our own, + * but parallel workers should use their leader's ID. + */ +#define BackendIdForTempRelations() \ + (ParallelLeaderBackendId == InvalidBackendId ? MyBackendId : ParallelLeaderBackendId) + +#endif /* BACKENDID_H */ diff --git a/src/include/storage/barrier.h b/src/include/storage/barrier.h new file mode 100644 index 0000000..57d2c52 --- /dev/null +++ b/src/include/storage/barrier.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- + * + * barrier.h + * Barriers for synchronizing cooperating processes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/barrier.h + * + *------------------------------------------------------------------------- + */ +#ifndef BARRIER_H +#define BARRIER_H + +/* + * For the header previously known as "barrier.h", please include + * "port/atomics.h", which deals with atomics, compiler barriers and memory + * barriers. + */ + +#include "storage/condition_variable.h" +#include "storage/spin.h" + +typedef struct Barrier +{ + slock_t mutex; + int phase; /* phase counter */ + int participants; /* the number of participants attached */ + int arrived; /* the number of participants that have + * arrived */ + int elected; /* highest phase elected */ + bool static_party; /* used only for assertions */ + ConditionVariable condition_variable; +} Barrier; + +extern void BarrierInit(Barrier *barrier, int num_workers); +extern bool BarrierArriveAndWait(Barrier *barrier, uint32 wait_event_info); +extern bool BarrierArriveAndDetach(Barrier *barrier); +extern bool BarrierArriveAndDetachExceptLast(Barrier *barrier); +extern int BarrierAttach(Barrier *barrier); +extern bool BarrierDetach(Barrier *barrier); +extern int BarrierPhase(Barrier *barrier); +extern int BarrierParticipants(Barrier *barrier); + +#endif /* BARRIER_H */ diff --git a/src/include/storage/block.h b/src/include/storage/block.h new file mode 100644 index 0000000..d756e3f --- /dev/null +++ b/src/include/storage/block.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- + * + * block.h + * POSTGRES disk block definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/block.h + * + *------------------------------------------------------------------------- + */ +#ifndef BLOCK_H +#define BLOCK_H + +/* + * BlockNumber: + * + * each data file (heap or index) is divided into postgres disk blocks + * (which may be thought of as the unit of i/o -- a postgres buffer + * contains exactly one disk block). the blocks are numbered + * sequentially, 0 to 0xFFFFFFFE. + * + * InvalidBlockNumber is the same thing as P_NEW in bufmgr.h. + * + * the access methods, the buffer manager and the storage manager are + * more or less the only pieces of code that should be accessing disk + * blocks directly. + */ +typedef uint32 BlockNumber; + +#define InvalidBlockNumber ((BlockNumber) 0xFFFFFFFF) + +#define MaxBlockNumber ((BlockNumber) 0xFFFFFFFE) + +/* + * BlockId: + * + * this is a storage type for BlockNumber. in other words, this type + * is used for on-disk structures (e.g., in HeapTupleData) whereas + * BlockNumber is the type on which calculations are performed (e.g., + * in access method code). + * + * there doesn't appear to be any reason to have separate types except + * for the fact that BlockIds can be SHORTALIGN'd (and therefore any + * structures that contains them, such as ItemPointerData, can also be + * SHORTALIGN'd). this is an important consideration for reducing the + * space requirements of the line pointer (ItemIdData) array on each + * page and the header of each heap or index tuple, so it doesn't seem + * wise to change this without good reason. + */ +typedef struct BlockIdData +{ + uint16 bi_hi; + uint16 bi_lo; +} BlockIdData; + +typedef BlockIdData *BlockId; /* block identifier */ + +/* ---------------- + * support macros + * ---------------- + */ + +/* + * BlockNumberIsValid + * True iff blockNumber is valid. + */ +#define BlockNumberIsValid(blockNumber) \ + ((BlockNumber) (blockNumber) != InvalidBlockNumber) + +/* + * BlockIdIsValid + * True iff the block identifier is valid. + */ +#define BlockIdIsValid(blockId) \ + PointerIsValid(blockId) + +/* + * BlockIdSet + * Sets a block identifier to the specified value. + */ +#define BlockIdSet(blockId, blockNumber) \ +( \ + (blockId)->bi_hi = (blockNumber) >> 16, \ + (blockId)->bi_lo = (blockNumber) & 0xffff \ +) + +/* + * BlockIdCopy + * Copy a block identifier. + */ +#define BlockIdCopy(toBlockId, fromBlockId) \ +( \ + (toBlockId)->bi_hi = (fromBlockId)->bi_hi, \ + (toBlockId)->bi_lo = (fromBlockId)->bi_lo \ +) + +/* + * BlockIdEquals + * Check for block number equality. + */ +#define BlockIdEquals(blockId1, blockId2) \ + ((blockId1)->bi_hi == (blockId2)->bi_hi && \ + (blockId1)->bi_lo == (blockId2)->bi_lo) + +/* + * BlockIdGetBlockNumber + * Retrieve the block number from a block identifier. + */ +#define BlockIdGetBlockNumber(blockId) \ + ((((BlockNumber) (blockId)->bi_hi) << 16) | ((BlockNumber) (blockId)->bi_lo)) + +#endif /* BLOCK_H */ diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h new file mode 100644 index 0000000..aec01ca --- /dev/null +++ b/src/include/storage/buf.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- + * + * buf.h + * Basic buffer manager data types. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/buf.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUF_H +#define BUF_H + +/* + * Buffer identifiers. + * + * Zero is invalid, positive is the index of a shared buffer (1..NBuffers), + * negative is the index of a local buffer (-1 .. -NLocBuffer). + */ +typedef int Buffer; + +#define InvalidBuffer 0 + +/* + * BufferIsInvalid + * True iff the buffer is invalid. + */ +#define BufferIsInvalid(buffer) ((buffer) == InvalidBuffer) + +/* + * BufferIsLocal + * True iff the buffer is local (not visible to other backends). + */ +#define BufferIsLocal(buffer) ((buffer) < 0) + +/* + * Buffer access strategy objects. + * + * BufferAccessStrategyData is private to freelist.c + */ +typedef struct BufferAccessStrategyData *BufferAccessStrategy; + +#endif /* BUF_H */ diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h new file mode 100644 index 0000000..a17e7b2 --- /dev/null +++ b/src/include/storage/buf_internals.h @@ -0,0 +1,345 @@ +/*------------------------------------------------------------------------- + * + * buf_internals.h + * Internal definitions for buffer manager and the buffer replacement + * strategy. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/buf_internals.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUFMGR_INTERNALS_H +#define BUFMGR_INTERNALS_H + +#include "port/atomics.h" +#include "storage/buf.h" +#include "storage/bufmgr.h" +#include "storage/condition_variable.h" +#include "storage/latch.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "storage/smgr.h" +#include "storage/spin.h" +#include "utils/relcache.h" + +/* + * Buffer state is a single 32-bit variable where following data is combined. + * + * - 18 bits refcount + * - 4 bits usage count + * - 10 bits of flags + * + * Combining these values allows to perform some operations without locking + * the buffer header, by modifying them together with a CAS loop. + * + * The definition of buffer state components is below. + */ +#define BUF_REFCOUNT_ONE 1 +#define BUF_REFCOUNT_MASK ((1U << 18) - 1) +#define BUF_USAGECOUNT_MASK 0x003C0000U +#define BUF_USAGECOUNT_ONE (1U << 18) +#define BUF_USAGECOUNT_SHIFT 18 +#define BUF_FLAG_MASK 0xFFC00000U + +/* Get refcount and usagecount from buffer state */ +#define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) +#define BUF_STATE_GET_USAGECOUNT(state) (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + +/* + * Flags for buffer descriptors + * + * Note: BM_TAG_VALID essentially means that there is a buffer hashtable + * entry associated with the buffer's tag. + */ +#define BM_LOCKED (1U << 22) /* buffer header is locked */ +#define BM_DIRTY (1U << 23) /* data needs writing */ +#define BM_VALID (1U << 24) /* data is valid */ +#define BM_TAG_VALID (1U << 25) /* tag is assigned */ +#define BM_IO_IN_PROGRESS (1U << 26) /* read or write in progress */ +#define BM_IO_ERROR (1U << 27) /* previous I/O failed */ +#define BM_JUST_DIRTIED (1U << 28) /* dirtied since write started */ +#define BM_PIN_COUNT_WAITER (1U << 29) /* have waiter for sole pin */ +#define BM_CHECKPOINT_NEEDED (1U << 30) /* must write for checkpoint */ +#define BM_PERMANENT (1U << 31) /* permanent buffer (not unlogged, + * or init fork) */ +/* + * The maximum allowed value of usage_count represents a tradeoff between + * accuracy and speed of the clock-sweep buffer management algorithm. A + * large value (comparable to NBuffers) would approximate LRU semantics. + * But it can take as many as BM_MAX_USAGE_COUNT+1 complete cycles of + * clock sweeps to find a free buffer, so in practice we don't want the + * value to be very large. + */ +#define BM_MAX_USAGE_COUNT 5 + +/* + * Buffer tag identifies which disk block the buffer contains. + * + * Note: the BufferTag data must be sufficient to determine where to write the + * block, without reference to pg_class or pg_tablespace entries. It's + * possible that the backend flushing the buffer doesn't even believe the + * relation is visible yet (its xact may have started before the xact that + * created the rel). The storage manager must be able to cope anyway. + * + * Note: if there's any pad bytes in the struct, INIT_BUFFERTAG will have + * to be fixed to zero them, since this struct is used as a hash key. + */ +typedef struct buftag +{ + RelFileNode rnode; /* physical relation identifier */ + ForkNumber forkNum; + BlockNumber blockNum; /* blknum relative to begin of reln */ +} BufferTag; + +#define CLEAR_BUFFERTAG(a) \ +( \ + (a).rnode.spcNode = InvalidOid, \ + (a).rnode.dbNode = InvalidOid, \ + (a).rnode.relNode = InvalidOid, \ + (a).forkNum = InvalidForkNumber, \ + (a).blockNum = InvalidBlockNumber \ +) + +#define INIT_BUFFERTAG(a,xx_rnode,xx_forkNum,xx_blockNum) \ +( \ + (a).rnode = (xx_rnode), \ + (a).forkNum = (xx_forkNum), \ + (a).blockNum = (xx_blockNum) \ +) + +#define BUFFERTAGS_EQUAL(a,b) \ +( \ + RelFileNodeEquals((a).rnode, (b).rnode) && \ + (a).blockNum == (b).blockNum && \ + (a).forkNum == (b).forkNum \ +) + +/* + * The shared buffer mapping table is partitioned to reduce contention. + * To determine which partition lock a given tag requires, compute the tag's + * hash code with BufTableHashCode(), then apply BufMappingPartitionLock(). + * NB: NUM_BUFFER_PARTITIONS must be a power of 2! + */ +#define BufTableHashPartition(hashcode) \ + ((hashcode) % NUM_BUFFER_PARTITIONS) +#define BufMappingPartitionLock(hashcode) \ + (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + \ + BufTableHashPartition(hashcode)].lock) +#define BufMappingPartitionLockByIndex(i) \ + (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock) + +/* + * BufferDesc -- shared descriptor/state data for a single shared buffer. + * + * Note: Buffer header lock (BM_LOCKED flag) must be held to examine or change + * tag, state or wait_backend_pgprocno fields. In general, buffer header lock + * is a spinlock which is combined with flags, refcount and usagecount into + * single atomic variable. This layout allow us to do some operations in a + * single atomic operation, without actually acquiring and releasing spinlock; + * for instance, increase or decrease refcount. buf_id field never changes + * after initialization, so does not need locking. freeNext is protected by + * the buffer_strategy_lock not buffer header lock. The LWLock can take care + * of itself. The buffer header lock is *not* used to control access to the + * data in the buffer! + * + * It's assumed that nobody changes the state field while buffer header lock + * is held. Thus buffer header lock holder can do complex updates of the + * state variable in single write, simultaneously with lock release (cleaning + * BM_LOCKED flag). On the other hand, updating of state without holding + * buffer header lock is restricted to CAS, which insure that BM_LOCKED flag + * is not set. Atomic increment/decrement, OR/AND etc. are not allowed. + * + * An exception is that if we have the buffer pinned, its tag can't change + * underneath us, so we can examine the tag without locking the buffer header. + * Also, in places we do one-time reads of the flags without bothering to + * lock the buffer header; this is generally for situations where we don't + * expect the flag bit being tested to be changing. + * + * We can't physically remove items from a disk page if another backend has + * the buffer pinned. Hence, a backend may need to wait for all other pins + * to go away. This is signaled by storing its own pgprocno into + * wait_backend_pgprocno and setting flag bit BM_PIN_COUNT_WAITER. At present, + * there can be only one such waiter per buffer. + * + * We use this same struct for local buffer headers, but the locks are not + * used and not all of the flag bits are useful either. To avoid unnecessary + * overhead, manipulations of the state field should be done without actual + * atomic operations (i.e. only pg_atomic_read_u32() and + * pg_atomic_unlocked_write_u32()). + * + * Be careful to avoid increasing the size of the struct when adding or + * reordering members. Keeping it below 64 bytes (the most common CPU + * cache line size) is fairly important for performance. + * + * Per-buffer I/O condition variables are currently kept outside this struct in + * a separate array. They could be moved in here and still fit within that + * limit on common systems, but for now that is not done. + */ +typedef struct BufferDesc +{ + BufferTag tag; /* ID of page contained in buffer */ + int buf_id; /* buffer's index number (from 0) */ + + /* state of the tag, containing flags, refcount and usagecount */ + pg_atomic_uint32 state; + + int wait_backend_pgprocno; /* backend of pin-count waiter */ + int freeNext; /* link in freelist chain */ + LWLock content_lock; /* to lock access to buffer contents */ +} BufferDesc; + +/* + * Concurrent access to buffer headers has proven to be more efficient if + * they're cache line aligned. So we force the start of the BufferDescriptors + * array to be on a cache line boundary and force the elements to be cache + * line sized. + * + * XXX: As this is primarily matters in highly concurrent workloads which + * probably all are 64bit these days, and the space wastage would be a bit + * more noticeable on 32bit systems, we don't force the stride to be cache + * line sized on those. If somebody does actual performance testing, we can + * reevaluate. + * + * Note that local buffer descriptors aren't forced to be aligned - as there's + * no concurrent access to those it's unlikely to be beneficial. + * + * We use a 64-byte cache line size here, because that's the most common + * size. Making it bigger would be a waste of memory. Even if running on a + * platform with either 32 or 128 byte line sizes, it's good to align to + * boundaries and avoid false sharing. + */ +#define BUFFERDESC_PAD_TO_SIZE (SIZEOF_VOID_P == 8 ? 64 : 1) + +typedef union BufferDescPadded +{ + BufferDesc bufferdesc; + char pad[BUFFERDESC_PAD_TO_SIZE]; +} BufferDescPadded; + +#define GetBufferDescriptor(id) (&BufferDescriptors[(id)].bufferdesc) +#define GetLocalBufferDescriptor(id) (&LocalBufferDescriptors[(id)]) + +#define BufferDescriptorGetBuffer(bdesc) ((bdesc)->buf_id + 1) + +#define BufferDescriptorGetIOCV(bdesc) \ + (&(BufferIOCVArray[(bdesc)->buf_id]).cv) +#define BufferDescriptorGetContentLock(bdesc) \ + ((LWLock*) (&(bdesc)->content_lock)) + +extern PGDLLIMPORT ConditionVariableMinimallyPadded *BufferIOCVArray; + +/* + * The freeNext field is either the index of the next freelist entry, + * or one of these special values: + */ +#define FREENEXT_END_OF_LIST (-1) +#define FREENEXT_NOT_IN_LIST (-2) + +/* + * Functions for acquiring/releasing a shared buffer header's spinlock. Do + * not apply these to local buffers! + */ +extern uint32 LockBufHdr(BufferDesc *desc); +#define UnlockBufHdr(desc, s) \ + do { \ + pg_write_barrier(); \ + pg_atomic_write_u32(&(desc)->state, (s) & (~BM_LOCKED)); \ + } while (0) + + +/* + * The PendingWriteback & WritebackContext structure are used to keep + * information about pending flush requests to be issued to the OS. + */ +typedef struct PendingWriteback +{ + /* could store different types of pending flushes here */ + BufferTag tag; +} PendingWriteback; + +/* struct forward declared in bufmgr.h */ +typedef struct WritebackContext +{ + /* pointer to the max number of writeback requests to coalesce */ + int *max_pending; + + /* current number of pending writeback requests */ + int nr_pending; + + /* pending requests */ + PendingWriteback pending_writebacks[WRITEBACK_MAX_PENDING_FLUSHES]; +} WritebackContext; + +/* in buf_init.c */ +extern PGDLLIMPORT BufferDescPadded *BufferDescriptors; +extern PGDLLIMPORT WritebackContext BackendWritebackContext; + +/* in localbuf.c */ +extern PGDLLIMPORT BufferDesc *LocalBufferDescriptors; + +/* in bufmgr.c */ + +/* + * Structure to sort buffers per file on checkpoints. + * + * This structure is allocated per buffer in shared memory, so it should be + * kept as small as possible. + */ +typedef struct CkptSortItem +{ + Oid tsId; + Oid relNode; + ForkNumber forkNum; + BlockNumber blockNum; + int buf_id; +} CkptSortItem; + +extern PGDLLIMPORT CkptSortItem *CkptBufferIds; + +/* + * Internal buffer management routines + */ +/* bufmgr.c */ +extern void WritebackContextInit(WritebackContext *context, int *max_pending); +extern void IssuePendingWritebacks(WritebackContext *context); +extern void ScheduleBufferTagForWriteback(WritebackContext *context, BufferTag *tag); + +/* freelist.c */ +extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, + uint32 *buf_state); +extern void StrategyFreeBuffer(BufferDesc *buf); +extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, + BufferDesc *buf); + +extern int StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc); +extern void StrategyNotifyBgWriter(int bgwprocno); + +extern Size StrategyShmemSize(void); +extern void StrategyInitialize(bool init); +extern bool have_free_buffer(void); + +/* buf_table.c */ +extern Size BufTableShmemSize(int size); +extern void InitBufTable(int size); +extern uint32 BufTableHashCode(BufferTag *tagPtr); +extern int BufTableLookup(BufferTag *tagPtr, uint32 hashcode); +extern int BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id); +extern void BufTableDelete(BufferTag *tagPtr, uint32 hashcode); + +/* localbuf.c */ +extern PrefetchBufferResult PrefetchLocalBuffer(SMgrRelation smgr, + ForkNumber forkNum, + BlockNumber blockNum); +extern BufferDesc *LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, + BlockNumber blockNum, bool *foundPtr); +extern void MarkLocalBufferDirty(Buffer buffer); +extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum, + BlockNumber firstDelBlock); +extern void DropRelFileNodeAllLocalBuffers(RelFileNode rnode); +extern void AtEOXact_LocalBuffers(bool isCommit); + +#endif /* BUFMGR_INTERNALS_H */ diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h new file mode 100644 index 0000000..a4922d1 --- /dev/null +++ b/src/include/storage/buffile.h @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * buffile.h + * Management of large buffered temporary files. + * + * The BufFile routines provide a partial replacement for stdio atop + * virtual file descriptors managed by fd.c. Currently they only support + * buffered access to a virtual file, without any of stdio's formatting + * features. That's enough for immediate needs, but the set of facilities + * could be expanded if necessary. + * + * BufFile also supports working with temporary files that exceed the OS + * file size limit and/or the largest offset representable in an int. + * It might be better to split that out as a separately accessible module, + * but currently we have no need for oversize temp files without buffered + * access. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/buffile.h + * + *------------------------------------------------------------------------- + */ + +#ifndef BUFFILE_H +#define BUFFILE_H + +#include "storage/fileset.h" + +/* BufFile is an opaque type whose details are not known outside buffile.c. */ + +typedef struct BufFile BufFile; + +/* + * prototypes for functions in buffile.c + */ + +extern BufFile *BufFileCreateTemp(bool interXact); +extern void BufFileClose(BufFile *file); +extern size_t BufFileRead(BufFile *file, void *ptr, size_t size); +extern void BufFileWrite(BufFile *file, void *ptr, size_t size); +extern int BufFileSeek(BufFile *file, int fileno, off_t offset, int whence); +extern void BufFileTell(BufFile *file, int *fileno, off_t *offset); +extern int BufFileSeekBlock(BufFile *file, long blknum); +extern int64 BufFileSize(BufFile *file); +extern long BufFileAppend(BufFile *target, BufFile *source); + +extern BufFile *BufFileCreateFileSet(FileSet *fileset, const char *name); +extern void BufFileExportFileSet(BufFile *file); +extern BufFile *BufFileOpenFileSet(FileSet *fileset, const char *name, + int mode, bool missing_ok); +extern void BufFileDeleteFileSet(FileSet *fileset, const char *name, + bool missing_ok); +extern void BufFileTruncateFileSet(BufFile *file, int fileno, off_t offset); + +#endif /* BUFFILE_H */ diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h new file mode 100644 index 0000000..5839140 --- /dev/null +++ b/src/include/storage/bufmgr.h @@ -0,0 +1,297 @@ +/*------------------------------------------------------------------------- + * + * bufmgr.h + * POSTGRES buffer manager definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/bufmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUFMGR_H +#define BUFMGR_H + +#include "storage/block.h" +#include "storage/buf.h" +#include "storage/bufpage.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" +#include "utils/snapmgr.h" + +typedef void *Block; + +/* Possible arguments for GetAccessStrategy() */ +typedef enum BufferAccessStrategyType +{ + BAS_NORMAL, /* Normal random access */ + BAS_BULKREAD, /* Large read-only scan (hint bit updates are + * ok) */ + BAS_BULKWRITE, /* Large multi-block write (e.g. COPY IN) */ + BAS_VACUUM /* VACUUM */ +} BufferAccessStrategyType; + +/* Possible modes for ReadBufferExtended() */ +typedef enum +{ + RBM_NORMAL, /* Normal read */ + RBM_ZERO_AND_LOCK, /* Don't read from disk, caller will + * initialize. Also locks the page. */ + RBM_ZERO_AND_CLEANUP_LOCK, /* Like RBM_ZERO_AND_LOCK, but locks the page + * in "cleanup" mode */ + RBM_ZERO_ON_ERROR, /* Read, but return an all-zeros page on error */ + RBM_NORMAL_NO_LOG /* Don't log page as invalid during WAL + * replay; otherwise same as RBM_NORMAL */ +} ReadBufferMode; + +/* + * Type returned by PrefetchBuffer(). + */ +typedef struct PrefetchBufferResult +{ + Buffer recent_buffer; /* If valid, a hit (recheck needed!) */ + bool initiated_io; /* If true, a miss resulting in async I/O */ +} PrefetchBufferResult; + +/* forward declared, to avoid having to expose buf_internals.h here */ +struct WritebackContext; + +/* forward declared, to avoid including smgr.h here */ +struct SMgrRelationData; + +/* in globals.c ... this duplicates miscadmin.h */ +extern PGDLLIMPORT int NBuffers; + +/* in bufmgr.c */ +extern PGDLLIMPORT bool zero_damaged_pages; +extern PGDLLIMPORT int bgwriter_lru_maxpages; +extern PGDLLIMPORT double bgwriter_lru_multiplier; +extern PGDLLIMPORT bool track_io_timing; +extern PGDLLIMPORT int effective_io_concurrency; +extern PGDLLIMPORT int maintenance_io_concurrency; + +extern PGDLLIMPORT int checkpoint_flush_after; +extern PGDLLIMPORT int backend_flush_after; +extern PGDLLIMPORT int bgwriter_flush_after; + +/* in buf_init.c */ +extern PGDLLIMPORT char *BufferBlocks; + +/* in localbuf.c */ +extern PGDLLIMPORT int NLocBuffer; +extern PGDLLIMPORT Block *LocalBufferBlockPointers; +extern PGDLLIMPORT int32 *LocalRefCount; + +/* upper limit for effective_io_concurrency */ +#define MAX_IO_CONCURRENCY 1000 + +/* special block number for ReadBuffer() */ +#define P_NEW InvalidBlockNumber /* grow the file to get a new page */ + +/* + * Buffer content lock modes (mode argument for LockBuffer()) + */ +#define BUFFER_LOCK_UNLOCK 0 +#define BUFFER_LOCK_SHARE 1 +#define BUFFER_LOCK_EXCLUSIVE 2 + +/* + * These routines are beaten on quite heavily, hence the macroization. + */ + +/* + * BufferIsValid + * True iff the given buffer number is valid (either as a shared + * or local buffer). + * + * Note: For a long time this was defined the same as BufferIsPinned, + * that is it would say False if you didn't hold a pin on the buffer. + * I believe this was bogus and served only to mask logic errors. + * Code should always know whether it has a buffer reference, + * independently of the pin state. + * + * Note: For a further long time this was not quite the inverse of the + * BufferIsInvalid() macro, in that it also did sanity checks to verify + * that the buffer number was in range. Most likely, this macro was + * originally intended only to be used in assertions, but its use has + * since expanded quite a bit, and the overhead of making those checks + * even in non-assert-enabled builds can be significant. Thus, we've + * now demoted the range checks to assertions within the macro itself. + */ +#define BufferIsValid(bufnum) \ +( \ + AssertMacro((bufnum) <= NBuffers && (bufnum) >= -NLocBuffer), \ + (bufnum) != InvalidBuffer \ +) + +/* + * BufferGetBlock + * Returns a reference to a disk page image associated with a buffer. + * + * Note: + * Assumes buffer is valid. + */ +#define BufferGetBlock(buffer) \ +( \ + AssertMacro(BufferIsValid(buffer)), \ + BufferIsLocal(buffer) ? \ + LocalBufferBlockPointers[-(buffer) - 1] \ + : \ + (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \ +) + +/* + * BufferGetPageSize + * Returns the page size within a buffer. + * + * Notes: + * Assumes buffer is valid. + * + * The buffer can be a raw disk block and need not contain a valid + * (formatted) disk page. + */ +/* XXX should dig out of buffer descriptor */ +#define BufferGetPageSize(buffer) \ +( \ + AssertMacro(BufferIsValid(buffer)), \ + (Size)BLCKSZ \ +) + +/* + * BufferGetPage + * Returns the page associated with a buffer. + * + * When this is called as part of a scan, there may be a need for a nearby + * call to TestForOldSnapshot(). See the definition of that for details. + */ +#define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer)) + +/* + * prototypes for functions in bufmgr.c + */ +extern PrefetchBufferResult PrefetchSharedBuffer(struct SMgrRelationData *smgr_reln, + ForkNumber forkNum, + BlockNumber blockNum); +extern PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum, + BlockNumber blockNum); +extern bool ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum, + BlockNumber blockNum, Buffer recent_buffer); +extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum); +extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, + BlockNumber blockNum, ReadBufferMode mode, + BufferAccessStrategy strategy); +extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, + ForkNumber forkNum, BlockNumber blockNum, + ReadBufferMode mode, BufferAccessStrategy strategy, + bool permanent); +extern void ReleaseBuffer(Buffer buffer); +extern void UnlockReleaseBuffer(Buffer buffer); +extern void MarkBufferDirty(Buffer buffer); +extern void IncrBufferRefCount(Buffer buffer); +extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, + BlockNumber blockNum); + +extern void InitBufferPool(void); +extern void InitBufferPoolAccess(void); +extern void AtEOXact_Buffers(bool isCommit); +extern void PrintBufferLeakWarning(Buffer buffer); +extern void CheckPointBuffers(int flags); +extern BlockNumber BufferGetBlockNumber(Buffer buffer); +extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, + ForkNumber forkNum); +extern void FlushOneBuffer(Buffer buffer); +extern void FlushRelationBuffers(Relation rel); +extern void FlushRelationsAllBuffers(struct SMgrRelationData **smgrs, int nrels); +extern void CreateAndCopyRelationData(RelFileNode src_rnode, + RelFileNode dst_rnode, + bool permanent); +extern void FlushDatabaseBuffers(Oid dbid); +extern void DropRelFileNodeBuffers(struct SMgrRelationData *smgr_reln, ForkNumber *forkNum, + int nforks, BlockNumber *firstDelBlock); +extern void DropRelFileNodesAllBuffers(struct SMgrRelationData **smgr_reln, int nnodes); +extern void DropDatabaseBuffers(Oid dbid); + +#define RelationGetNumberOfBlocks(reln) \ + RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM) + +extern bool BufferIsPermanent(Buffer buffer); +extern XLogRecPtr BufferGetLSNAtomic(Buffer buffer); + +#ifdef NOT_USED +extern void PrintPinnedBufs(void); +#endif +extern Size BufferShmemSize(void); +extern void BufferGetTag(Buffer buffer, RelFileNode *rnode, + ForkNumber *forknum, BlockNumber *blknum); + +extern void MarkBufferDirtyHint(Buffer buffer, bool buffer_std); + +extern void UnlockBuffers(void); +extern void LockBuffer(Buffer buffer, int mode); +extern bool ConditionalLockBuffer(Buffer buffer); +extern void LockBufferForCleanup(Buffer buffer); +extern bool ConditionalLockBufferForCleanup(Buffer buffer); +extern bool IsBufferCleanupOK(Buffer buffer); +extern bool HoldingBufferPinThatDelaysRecovery(void); + +extern void AbortBufferIO(void); + +extern void BufmgrCommit(void); +extern bool BgBufferSync(struct WritebackContext *wb_context); + +extern void AtProcExit_LocalBuffers(void); + +extern void TestForOldSnapshot_impl(Snapshot snapshot, Relation relation); + +/* in freelist.c */ +extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); +extern void FreeAccessStrategy(BufferAccessStrategy strategy); + + +/* inline functions */ + +/* + * Although this header file is nominally backend-only, certain frontend + * programs like pg_waldump include it. For compilers that emit static + * inline functions even when they're unused, that leads to unsatisfied + * external references; hence hide these with #ifndef FRONTEND. + */ + +#ifndef FRONTEND + +/* + * Check whether the given snapshot is too old to have safely read the given + * page from the given table. If so, throw a "snapshot too old" error. + * + * This test generally needs to be performed after every BufferGetPage() call + * that is executed as part of a scan. It is not needed for calls made for + * modifying the page (for example, to position to the right place to insert a + * new index tuple or for vacuuming). It may also be omitted where calls to + * lower-level functions will have already performed the test. + * + * Note that a NULL snapshot argument is allowed and causes a fast return + * without error; this is to support call sites which can be called from + * either scans or index modification areas. + * + * For best performance, keep the tests that are fastest and/or most likely to + * exclude a page from old snapshot testing near the front. + */ +static inline void +TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page) +{ + Assert(relation != NULL); + + if (old_snapshot_threshold >= 0 + && (snapshot) != NULL + && ((snapshot)->snapshot_type == SNAPSHOT_MVCC + || (snapshot)->snapshot_type == SNAPSHOT_TOAST) + && !XLogRecPtrIsInvalid((snapshot)->lsn) + && PageGetLSN(page) > (snapshot)->lsn) + TestForOldSnapshot_impl(snapshot, relation); +} + +#endif /* FRONTEND */ + +#endif /* BUFMGR_H */ diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h new file mode 100644 index 0000000..e9f253f --- /dev/null +++ b/src/include/storage/bufpage.h @@ -0,0 +1,457 @@ +/*------------------------------------------------------------------------- + * + * bufpage.h + * Standard POSTGRES buffer page definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/bufpage.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUFPAGE_H +#define BUFPAGE_H + +#include "access/xlogdefs.h" +#include "storage/block.h" +#include "storage/item.h" +#include "storage/off.h" + +/* + * A postgres disk page is an abstraction layered on top of a postgres + * disk block (which is simply a unit of i/o, see block.h). + * + * specifically, while a disk block can be unformatted, a postgres + * disk page is always a slotted page of the form: + * + * +----------------+---------------------------------+ + * | PageHeaderData | linp1 linp2 linp3 ... | + * +-----------+----+---------------------------------+ + * | ... linpN | | + * +-----------+--------------------------------------+ + * | ^ pd_lower | + * | | + * | v pd_upper | + * +-------------+------------------------------------+ + * | | tupleN ... | + * +-------------+------------------+-----------------+ + * | ... tuple3 tuple2 tuple1 | "special space" | + * +--------------------------------+-----------------+ + * ^ pd_special + * + * a page is full when nothing can be added between pd_lower and + * pd_upper. + * + * all blocks written out by an access method must be disk pages. + * + * EXCEPTIONS: + * + * obviously, a page is not formatted before it is initialized by + * a call to PageInit. + * + * NOTES: + * + * linp1..N form an ItemId (line pointer) array. ItemPointers point + * to a physical block number and a logical offset (line pointer + * number) within that block/page. Note that OffsetNumbers + * conventionally start at 1, not 0. + * + * tuple1..N are added "backwards" on the page. Since an ItemPointer + * offset is used to access an ItemId entry rather than an actual + * byte-offset position, tuples can be physically shuffled on a page + * whenever the need arises. This indirection also keeps crash recovery + * relatively simple, because the low-level details of page space + * management can be controlled by standard buffer page code during + * logging, and during recovery. + * + * AM-generic per-page information is kept in PageHeaderData. + * + * AM-specific per-page data (if any) is kept in the area marked "special + * space"; each AM has an "opaque" structure defined somewhere that is + * stored as the page trailer. an access method should always + * initialize its pages with PageInit and then set its own opaque + * fields. + */ + +typedef Pointer Page; + + +/* + * location (byte offset) within a page. + * + * note that this is actually limited to 2^15 because we have limited + * ItemIdData.lp_off and ItemIdData.lp_len to 15 bits (see itemid.h). + */ +typedef uint16 LocationIndex; + + +/* + * For historical reasons, the 64-bit LSN value is stored as two 32-bit + * values. + */ +typedef struct +{ + uint32 xlogid; /* high bits */ + uint32 xrecoff; /* low bits */ +} PageXLogRecPtr; + +#define PageXLogRecPtrGet(val) \ + ((uint64) (val).xlogid << 32 | (val).xrecoff) +#define PageXLogRecPtrSet(ptr, lsn) \ + ((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn)) + +/* + * disk page organization + * + * space management information generic to any page + * + * pd_lsn - identifies xlog record for last change to this page. + * pd_checksum - page checksum, if set. + * pd_flags - flag bits. + * pd_lower - offset to start of free space. + * pd_upper - offset to end of free space. + * pd_special - offset to start of special space. + * pd_pagesize_version - size in bytes and page layout version number. + * pd_prune_xid - oldest XID among potentially prunable tuples on page. + * + * The LSN is used by the buffer manager to enforce the basic rule of WAL: + * "thou shalt write xlog before data". A dirty buffer cannot be dumped + * to disk until xlog has been flushed at least as far as the page's LSN. + * + * pd_checksum stores the page checksum, if it has been set for this page; + * zero is a valid value for a checksum. If a checksum is not in use then + * we leave the field unset. This will typically mean the field is zero + * though non-zero values may also be present if databases have been + * pg_upgraded from releases prior to 9.3, when the same byte offset was + * used to store the current timelineid when the page was last updated. + * Note that there is no indication on a page as to whether the checksum + * is valid or not, a deliberate design choice which avoids the problem + * of relying on the page contents to decide whether to verify it. Hence + * there are no flag bits relating to checksums. + * + * pd_prune_xid is a hint field that helps determine whether pruning will be + * useful. It is currently unused in index pages. + * + * The page version number and page size are packed together into a single + * uint16 field. This is for historical reasons: before PostgreSQL 7.3, + * there was no concept of a page version number, and doing it this way + * lets us pretend that pre-7.3 databases have page version number zero. + * We constrain page sizes to be multiples of 256, leaving the low eight + * bits available for a version number. + * + * Minimum possible page size is perhaps 64B to fit page header, opaque space + * and a minimal tuple; of course, in reality you want it much bigger, so + * the constraint on pagesize mod 256 is not an important restriction. + * On the high end, we can only support pages up to 32KB because lp_off/lp_len + * are 15 bits. + */ + +typedef struct PageHeaderData +{ + /* XXX LSN is member of *any* block, not only page-organized ones */ + PageXLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog + * record for last change to this page */ + uint16 pd_checksum; /* checksum */ + uint16 pd_flags; /* flag bits, see below */ + LocationIndex pd_lower; /* offset to start of free space */ + LocationIndex pd_upper; /* offset to end of free space */ + LocationIndex pd_special; /* offset to start of special space */ + uint16 pd_pagesize_version; + TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */ + ItemIdData pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */ +} PageHeaderData; + +typedef PageHeaderData *PageHeader; + +/* + * pd_flags contains the following flag bits. Undefined bits are initialized + * to zero and may be used in the future. + * + * PD_HAS_FREE_LINES is set if there are any LP_UNUSED line pointers before + * pd_lower. This should be considered a hint rather than the truth, since + * changes to it are not WAL-logged. + * + * PD_PAGE_FULL is set if an UPDATE doesn't find enough free space in the + * page for its new tuple version; this suggests that a prune is needed. + * Again, this is just a hint. + */ +#define PD_HAS_FREE_LINES 0x0001 /* are there any unused line pointers? */ +#define PD_PAGE_FULL 0x0002 /* not enough free space for new tuple? */ +#define PD_ALL_VISIBLE 0x0004 /* all tuples on page are visible to + * everyone */ + +#define PD_VALID_FLAG_BITS 0x0007 /* OR of all valid pd_flags bits */ + +/* + * Page layout version number 0 is for pre-7.3 Postgres releases. + * Releases 7.3 and 7.4 use 1, denoting a new HeapTupleHeader layout. + * Release 8.0 uses 2; it changed the HeapTupleHeader layout again. + * Release 8.1 uses 3; it redefined HeapTupleHeader infomask bits. + * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and + * added the pd_flags field (by stealing some bits from pd_tli), + * as well as adding the pd_prune_xid field (which enlarges the header). + * + * As of Release 9.3, the checksum version must also be considered when + * handling pages. + */ +#define PG_PAGE_LAYOUT_VERSION 4 +#define PG_DATA_CHECKSUM_VERSION 1 + +/* ---------------------------------------------------------------- + * page support macros + * ---------------------------------------------------------------- + */ + +/* + * PageIsValid + * True iff page is valid. + */ +#define PageIsValid(page) PointerIsValid(page) + +/* + * line pointer(s) do not count as part of header + */ +#define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp)) + +/* + * PageIsEmpty + * returns true iff no itemid has been allocated on the page + */ +#define PageIsEmpty(page) \ + (((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData) + +/* + * PageIsNew + * returns true iff page has not been initialized (by PageInit) + */ +#define PageIsNew(page) (((PageHeader) (page))->pd_upper == 0) + +/* + * PageGetItemId + * Returns an item identifier of a page. + */ +#define PageGetItemId(page, offsetNumber) \ + ((ItemId) (&((PageHeader) (page))->pd_linp[(offsetNumber) - 1])) + +/* + * PageGetContents + * To be used in cases where the page does not contain line pointers. + * + * Note: prior to 8.3 this was not guaranteed to yield a MAXALIGN'd result. + * Now it is. Beware of old code that might think the offset to the contents + * is just SizeOfPageHeaderData rather than MAXALIGN(SizeOfPageHeaderData). + */ +#define PageGetContents(page) \ + ((char *) (page) + MAXALIGN(SizeOfPageHeaderData)) + +/* ---------------- + * macros to access page size info + * ---------------- + */ + +/* + * PageSizeIsValid + * True iff the page size is valid. + */ +#define PageSizeIsValid(pageSize) ((pageSize) == BLCKSZ) + +/* + * PageGetPageSize + * Returns the page size of a page. + * + * this can only be called on a formatted page (unlike + * BufferGetPageSize, which can be called on an unformatted page). + * however, it can be called on a page that is not stored in a buffer. + */ +#define PageGetPageSize(page) \ + ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00)) + +/* + * PageGetPageLayoutVersion + * Returns the page layout version of a page. + */ +#define PageGetPageLayoutVersion(page) \ + (((PageHeader) (page))->pd_pagesize_version & 0x00FF) + +/* + * PageSetPageSizeAndVersion + * Sets the page size and page layout version number of a page. + * + * We could support setting these two values separately, but there's + * no real need for it at the moment. + */ +#define PageSetPageSizeAndVersion(page, size, version) \ +( \ + AssertMacro(((size) & 0xFF00) == (size)), \ + AssertMacro(((version) & 0x00FF) == (version)), \ + ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \ +) + +/* ---------------- + * page special data macros + * ---------------- + */ +/* + * PageGetSpecialSize + * Returns size of special space on a page. + */ +#define PageGetSpecialSize(page) \ + ((uint16) (PageGetPageSize(page) - ((PageHeader)(page))->pd_special)) + +/* + * Using assertions, validate that the page special pointer is OK. + * + * This is intended to catch use of the pointer before page initialization. + * It is implemented as a function due to the limitations of the MSVC + * compiler, which choked on doing all these tests within another macro. We + * return true so that AssertMacro() can be used while still getting the + * specifics from the macro failure within this function. + */ +static inline bool +PageValidateSpecialPointer(Page page) +{ + Assert(PageIsValid(page)); + Assert(((PageHeader) (page))->pd_special <= BLCKSZ); + Assert(((PageHeader) (page))->pd_special >= SizeOfPageHeaderData); + + return true; +} + +/* + * PageGetSpecialPointer + * Returns pointer to special space on a page. + */ +#define PageGetSpecialPointer(page) \ +( \ + AssertMacro(PageValidateSpecialPointer(page)), \ + (char *) ((char *) (page) + ((PageHeader) (page))->pd_special) \ +) + +/* + * PageGetItem + * Retrieves an item on the given page. + * + * Note: + * This does not change the status of any of the resources passed. + * The semantics may change in the future. + */ +#define PageGetItem(page, itemId) \ +( \ + AssertMacro(PageIsValid(page)), \ + AssertMacro(ItemIdHasStorage(itemId)), \ + (Item)(((char *)(page)) + ItemIdGetOffset(itemId)) \ +) + +/* + * PageGetMaxOffsetNumber + * Returns the maximum offset number used by the given page. + * Since offset numbers are 1-based, this is also the number + * of items on the page. + * + * NOTE: if the page is not initialized (pd_lower == 0), we must + * return zero to ensure sane behavior. Accept double evaluation + * of the argument so that we can ensure this. + */ +#define PageGetMaxOffsetNumber(page) \ + (((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData ? 0 : \ + ((((PageHeader) (page))->pd_lower - SizeOfPageHeaderData) \ + / sizeof(ItemIdData))) + +/* + * Additional macros for access to page headers. (Beware multiple evaluation + * of the arguments!) + */ +#define PageGetLSN(page) \ + PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn) +#define PageSetLSN(page, lsn) \ + PageXLogRecPtrSet(((PageHeader) (page))->pd_lsn, lsn) + +#define PageHasFreeLinePointers(page) \ + (((PageHeader) (page))->pd_flags & PD_HAS_FREE_LINES) +#define PageSetHasFreeLinePointers(page) \ + (((PageHeader) (page))->pd_flags |= PD_HAS_FREE_LINES) +#define PageClearHasFreeLinePointers(page) \ + (((PageHeader) (page))->pd_flags &= ~PD_HAS_FREE_LINES) + +#define PageIsFull(page) \ + (((PageHeader) (page))->pd_flags & PD_PAGE_FULL) +#define PageSetFull(page) \ + (((PageHeader) (page))->pd_flags |= PD_PAGE_FULL) +#define PageClearFull(page) \ + (((PageHeader) (page))->pd_flags &= ~PD_PAGE_FULL) + +#define PageIsAllVisible(page) \ + (((PageHeader) (page))->pd_flags & PD_ALL_VISIBLE) +#define PageSetAllVisible(page) \ + (((PageHeader) (page))->pd_flags |= PD_ALL_VISIBLE) +#define PageClearAllVisible(page) \ + (((PageHeader) (page))->pd_flags &= ~PD_ALL_VISIBLE) + +#define PageSetPrunable(page, xid) \ +do { \ + Assert(TransactionIdIsNormal(xid)); \ + if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \ + TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \ + ((PageHeader) (page))->pd_prune_xid = (xid); \ +} while (0) +#define PageClearPrunable(page) \ + (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId) + + +/* ---------------------------------------------------------------- + * extern declarations + * ---------------------------------------------------------------- + */ + +/* flags for PageAddItemExtended() */ +#define PAI_OVERWRITE (1 << 0) +#define PAI_IS_HEAP (1 << 1) + +/* flags for PageIsVerifiedExtended() */ +#define PIV_LOG_WARNING (1 << 0) +#define PIV_REPORT_STAT (1 << 1) + +#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap) \ + PageAddItemExtended(page, item, size, offsetNumber, \ + ((overwrite) ? PAI_OVERWRITE : 0) | \ + ((is_heap) ? PAI_IS_HEAP : 0)) + +#define PageIsVerified(page, blkno) \ + PageIsVerifiedExtended(page, blkno, \ + PIV_LOG_WARNING | PIV_REPORT_STAT) + +/* + * Check that BLCKSZ is a multiple of sizeof(size_t). In + * PageIsVerifiedExtended(), it is much faster to check if a page is + * full of zeroes using the native word size. Note that this assertion + * is kept within a header to make sure that StaticAssertDecl() works + * across various combinations of platforms and compilers. + */ +StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)), + "BLCKSZ has to be a multiple of sizeof(size_t)"); + +extern void PageInit(Page page, Size pageSize, Size specialSize); +extern bool PageIsVerifiedExtended(Page page, BlockNumber blkno, int flags); +extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size, + OffsetNumber offsetNumber, int flags); +extern Page PageGetTempPage(Page page); +extern Page PageGetTempPageCopy(Page page); +extern Page PageGetTempPageCopySpecial(Page page); +extern void PageRestoreTempPage(Page tempPage, Page oldPage); +extern void PageRepairFragmentation(Page page); +extern void PageTruncateLinePointerArray(Page page); +extern Size PageGetFreeSpace(Page page); +extern Size PageGetFreeSpaceForMultipleTuples(Page page, int ntups); +extern Size PageGetExactFreeSpace(Page page); +extern Size PageGetHeapFreeSpace(Page page); +extern void PageIndexTupleDelete(Page page, OffsetNumber offset); +extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems); +extern void PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offset); +extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, + Item newtup, Size newsize); +extern char *PageSetChecksumCopy(Page page, BlockNumber blkno); +extern void PageSetChecksumInplace(Page page, BlockNumber blkno); + +#endif /* BUFPAGE_H */ diff --git a/src/include/storage/checksum.h b/src/include/storage/checksum.h new file mode 100644 index 0000000..1904fab --- /dev/null +++ b/src/include/storage/checksum.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * checksum.h + * Checksum implementation for data pages. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/checksum.h + * + *------------------------------------------------------------------------- + */ +#ifndef CHECKSUM_H +#define CHECKSUM_H + +#include "storage/block.h" + +/* + * Compute the checksum for a Postgres page. The page must be aligned on a + * 4-byte boundary. + */ +extern uint16 pg_checksum_page(char *page, BlockNumber blkno); + +#endif /* CHECKSUM_H */ diff --git a/src/include/storage/checksum_impl.h b/src/include/storage/checksum_impl.h new file mode 100644 index 0000000..015f0f1 --- /dev/null +++ b/src/include/storage/checksum_impl.h @@ -0,0 +1,215 @@ +/*------------------------------------------------------------------------- + * + * checksum_impl.h + * Checksum implementation for data pages. + * + * This file exists for the benefit of external programs that may wish to + * check Postgres page checksums. They can #include this to get the code + * referenced by storage/checksum.h. (Note: you may need to redefine + * Assert() as empty to compile this successfully externally.) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/checksum_impl.h + * + *------------------------------------------------------------------------- + */ + +/* + * The algorithm used to checksum pages is chosen for very fast calculation. + * Workloads where the database working set fits into OS file cache but not + * into shared buffers can read in pages at a very fast pace and the checksum + * algorithm itself can become the largest bottleneck. + * + * The checksum algorithm itself is based on the FNV-1a hash (FNV is shorthand + * for Fowler/Noll/Vo). The primitive of a plain FNV-1a hash folds in data 1 + * byte at a time according to the formula: + * + * hash = (hash ^ value) * FNV_PRIME + * + * FNV-1a algorithm is described at http://www.isthe.com/chongo/tech/comp/fnv/ + * + * PostgreSQL doesn't use FNV-1a hash directly because it has bad mixing of + * high bits - high order bits in input data only affect high order bits in + * output data. To resolve this we xor in the value prior to multiplication + * shifted right by 17 bits. The number 17 was chosen because it doesn't + * have common denominator with set bit positions in FNV_PRIME and empirically + * provides the fastest mixing for high order bits of final iterations quickly + * avalanche into lower positions. For performance reasons we choose to combine + * 4 bytes at a time. The actual hash formula used as the basis is: + * + * hash = (hash ^ value) * FNV_PRIME ^ ((hash ^ value) >> 17) + * + * The main bottleneck in this calculation is the multiplication latency. To + * hide the latency and to make use of SIMD parallelism multiple hash values + * are calculated in parallel. The page is treated as a 32 column two + * dimensional array of 32 bit values. Each column is aggregated separately + * into a partial checksum. Each partial checksum uses a different initial + * value (offset basis in FNV terminology). The initial values actually used + * were chosen randomly, as the values themselves don't matter as much as that + * they are different and don't match anything in real data. After initializing + * partial checksums each value in the column is aggregated according to the + * above formula. Finally two more iterations of the formula are performed with + * value 0 to mix the bits of the last value added. + * + * The partial checksums are then folded together using xor to form a single + * 32-bit checksum. The caller can safely reduce the value to 16 bits + * using modulo 2^16-1. That will cause a very slight bias towards lower + * values but this is not significant for the performance of the + * checksum. + * + * The algorithm choice was based on what instructions are available in SIMD + * instruction sets. This meant that a fast and good algorithm needed to use + * multiplication as the main mixing operator. The simplest multiplication + * based checksum primitive is the one used by FNV. The prime used is chosen + * for good dispersion of values. It has no known simple patterns that result + * in collisions. Test of 5-bit differentials of the primitive over 64bit keys + * reveals no differentials with 3 or more values out of 100000 random keys + * colliding. Avalanche test shows that only high order bits of the last word + * have a bias. Tests of 1-4 uncorrelated bit errors, stray 0 and 0xFF bytes, + * overwriting page from random position to end with 0 bytes, and overwriting + * random segments of page with 0x00, 0xFF and random data all show optimal + * 2e-16 false positive rate within margin of error. + * + * Vectorization of the algorithm requires 32bit x 32bit -> 32bit integer + * multiplication instruction. As of 2013 the corresponding instruction is + * available on x86 SSE4.1 extensions (pmulld) and ARM NEON (vmul.i32). + * Vectorization requires a compiler to do the vectorization for us. For recent + * GCC versions the flags -msse4.1 -funroll-loops -ftree-vectorize are enough + * to achieve vectorization. + * + * The optimal amount of parallelism to use depends on CPU specific instruction + * latency, SIMD instruction width, throughput and the amount of registers + * available to hold intermediate state. Generally, more parallelism is better + * up to the point that state doesn't fit in registers and extra load-store + * instructions are needed to swap values in/out. The number chosen is a fixed + * part of the algorithm because changing the parallelism changes the checksum + * result. + * + * The parallelism number 32 was chosen based on the fact that it is the + * largest state that fits into architecturally visible x86 SSE registers while + * leaving some free registers for intermediate values. For future processors + * with 256bit vector registers this will leave some performance on the table. + * When vectorization is not available it might be beneficial to restructure + * the computation to calculate a subset of the columns at a time and perform + * multiple passes to avoid register spilling. This optimization opportunity + * is not used. Current coding also assumes that the compiler has the ability + * to unroll the inner loop to avoid loop overhead and minimize register + * spilling. For less sophisticated compilers it might be beneficial to + * manually unroll the inner loop. + */ + +#include "storage/bufpage.h" + +/* number of checksums to calculate in parallel */ +#define N_SUMS 32 +/* prime multiplier of FNV-1a hash */ +#define FNV_PRIME 16777619 + +/* Use a union so that this code is valid under strict aliasing */ +typedef union +{ + PageHeaderData phdr; + uint32 data[BLCKSZ / (sizeof(uint32) * N_SUMS)][N_SUMS]; +} PGChecksummablePage; + +/* + * Base offsets to initialize each of the parallel FNV hashes into a + * different initial state. + */ +static const uint32 checksumBaseOffsets[N_SUMS] = { + 0x5B1F36E9, 0xB8525960, 0x02AB50AA, 0x1DE66D2A, + 0x79FF467A, 0x9BB9F8A3, 0x217E7CD2, 0x83E13D2C, + 0xF8D4474F, 0xE39EB970, 0x42C6AE16, 0x993216FA, + 0x7B093B5D, 0x98DAFF3C, 0xF718902A, 0x0B1C9CDB, + 0xE58F764B, 0x187636BC, 0x5D7B3BB1, 0xE73DE7DE, + 0x92BEC979, 0xCCA6C0B2, 0x304A0979, 0x85AA43D4, + 0x783125BB, 0x6CA8EAA2, 0xE407EAC6, 0x4B5CFC3E, + 0x9FBF8C76, 0x15CA20BE, 0xF2CA9FD3, 0x959BD756 +}; + +/* + * Calculate one round of the checksum. + */ +#define CHECKSUM_COMP(checksum, value) \ +do { \ + uint32 __tmp = (checksum) ^ (value); \ + (checksum) = __tmp * FNV_PRIME ^ (__tmp >> 17); \ +} while (0) + +/* + * Block checksum algorithm. The page must be adequately aligned + * (at least on 4-byte boundary). + */ +static uint32 +pg_checksum_block(const PGChecksummablePage *page) +{ + uint32 sums[N_SUMS]; + uint32 result = 0; + uint32 i, + j; + + /* ensure that the size is compatible with the algorithm */ + Assert(sizeof(PGChecksummablePage) == BLCKSZ); + + /* initialize partial checksums to their corresponding offsets */ + memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets)); + + /* main checksum calculation */ + for (i = 0; i < (uint32) (BLCKSZ / (sizeof(uint32) * N_SUMS)); i++) + for (j = 0; j < N_SUMS; j++) + CHECKSUM_COMP(sums[j], page->data[i][j]); + + /* finally add in two rounds of zeroes for additional mixing */ + for (i = 0; i < 2; i++) + for (j = 0; j < N_SUMS; j++) + CHECKSUM_COMP(sums[j], 0); + + /* xor fold partial checksums together */ + for (i = 0; i < N_SUMS; i++) + result ^= sums[i]; + + return result; +} + +/* + * Compute the checksum for a Postgres page. + * + * The page must be adequately aligned (at least on a 4-byte boundary). + * Beware also that the checksum field of the page is transiently zeroed. + * + * The checksum includes the block number (to detect the case where a page is + * somehow moved to a different location), the page header (excluding the + * checksum itself), and the page data. + */ +uint16 +pg_checksum_page(char *page, BlockNumber blkno) +{ + PGChecksummablePage *cpage = (PGChecksummablePage *) page; + uint16 save_checksum; + uint32 checksum; + + /* We only calculate the checksum for properly-initialized pages */ + Assert(!PageIsNew(&cpage->phdr)); + + /* + * Save pd_checksum and temporarily set it to zero, so that the checksum + * calculation isn't affected by the old checksum stored on the page. + * Restore it after, because actually updating the checksum is NOT part of + * the API of this function. + */ + save_checksum = cpage->phdr.pd_checksum; + cpage->phdr.pd_checksum = 0; + checksum = pg_checksum_block(cpage); + cpage->phdr.pd_checksum = save_checksum; + + /* Mix in the block number to detect transposed pages */ + checksum ^= blkno; + + /* + * Reduce to a uint16 (to fit in the pd_checksum field) with an offset of + * one. That avoids checksums of zero, which seems like a good idea. + */ + return (uint16) ((checksum % 65535) + 1); +} diff --git a/src/include/storage/condition_variable.h b/src/include/storage/condition_variable.h new file mode 100644 index 0000000..e89175e --- /dev/null +++ b/src/include/storage/condition_variable.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * condition_variable.h + * Condition variables + * + * A condition variable is a method of waiting until a certain condition + * becomes true. Conventionally, a condition variable supports three + * operations: (1) sleep; (2) signal, which wakes up one process sleeping + * on the condition variable; and (3) broadcast, which wakes up every + * process sleeping on the condition variable. In our implementation, + * condition variables put a process into an interruptible sleep (so it + * can be canceled prior to the fulfillment of the condition) and do not + * use pointers internally (so that they are safe to use within DSMs). + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/condition_variable.h + * + *------------------------------------------------------------------------- + */ +#ifndef CONDITION_VARIABLE_H +#define CONDITION_VARIABLE_H + +#include "storage/proclist_types.h" +#include "storage/spin.h" + +typedef struct +{ + slock_t mutex; /* spinlock protecting the wakeup list */ + proclist_head wakeup; /* list of wake-able processes */ +} ConditionVariable; + +/* + * Pad a condition variable to a power-of-two size so that an array of + * condition variables does not cross a cache line boundary. + */ +#define CV_MINIMAL_SIZE (sizeof(ConditionVariable) <= 16 ? 16 : 32) +typedef union ConditionVariableMinimallyPadded +{ + ConditionVariable cv; + char pad[CV_MINIMAL_SIZE]; +} ConditionVariableMinimallyPadded; + +/* Initialize a condition variable. */ +extern void ConditionVariableInit(ConditionVariable *cv); + +/* + * To sleep on a condition variable, a process should use a loop which first + * checks the condition, exiting the loop if it is met, and then calls + * ConditionVariableSleep. Spurious wakeups are possible, but should be + * infrequent. After exiting the loop, ConditionVariableCancelSleep must + * be called to ensure that the process is no longer in the wait list for + * the condition variable. + */ +extern void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info); +extern bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, + uint32 wait_event_info); +extern void ConditionVariableCancelSleep(void); + +/* + * Optionally, ConditionVariablePrepareToSleep can be called before entering + * the test-and-sleep loop described above. Doing so is more efficient if + * at least one sleep is needed, whereas not doing so is more efficient when + * no sleep is needed because the test condition is true the first time. + */ +extern void ConditionVariablePrepareToSleep(ConditionVariable *cv); + +/* Wake up a single waiter (via signal) or all waiters (via broadcast). */ +extern void ConditionVariableSignal(ConditionVariable *cv); +extern void ConditionVariableBroadcast(ConditionVariable *cv); + +#endif /* CONDITION_VARIABLE_H */ diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h new file mode 100644 index 0000000..50a26ed --- /dev/null +++ b/src/include/storage/copydir.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * copydir.h + * Copy a directory. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/copydir.h + * + *------------------------------------------------------------------------- + */ +#ifndef COPYDIR_H +#define COPYDIR_H + +extern void copydir(char *fromdir, char *todir, bool recurse); +extern void copy_file(char *fromfile, char *tofile); + +#endif /* COPYDIR_H */ diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h new file mode 100644 index 0000000..4dd6af2 --- /dev/null +++ b/src/include/storage/dsm.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * dsm.h + * manage dynamic shared memory segments + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/dsm.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSM_H +#define DSM_H + +#include "storage/dsm_impl.h" + +typedef struct dsm_segment dsm_segment; + +#define DSM_CREATE_NULL_IF_MAXSEGMENTS 0x0001 + +/* A sentinel value for an invalid DSM handle. */ +#define DSM_HANDLE_INVALID 0 + +/* Startup and shutdown functions. */ +struct PGShmemHeader; /* avoid including pg_shmem.h */ +extern void dsm_cleanup_using_control_segment(dsm_handle old_control_handle); +extern void dsm_postmaster_startup(struct PGShmemHeader *); +extern void dsm_backend_shutdown(void); +extern void dsm_detach_all(void); + +extern size_t dsm_estimate_size(void); +extern void dsm_shmem_init(void); + +#ifdef EXEC_BACKEND +extern void dsm_set_control_handle(dsm_handle h); +#endif + +/* Functions that create or remove mappings. */ +extern dsm_segment *dsm_create(Size size, int flags); +extern dsm_segment *dsm_attach(dsm_handle h); +extern void dsm_detach(dsm_segment *seg); + +/* Resource management functions. */ +extern void dsm_pin_mapping(dsm_segment *seg); +extern void dsm_unpin_mapping(dsm_segment *seg); +extern void dsm_pin_segment(dsm_segment *seg); +extern void dsm_unpin_segment(dsm_handle h); +extern dsm_segment *dsm_find_mapping(dsm_handle h); + +/* Informational functions. */ +extern void *dsm_segment_address(dsm_segment *seg); +extern Size dsm_segment_map_length(dsm_segment *seg); +extern dsm_handle dsm_segment_handle(dsm_segment *seg); + +/* Cleanup hooks. */ +typedef void (*on_dsm_detach_callback) (dsm_segment *, Datum arg); +extern void on_dsm_detach(dsm_segment *seg, + on_dsm_detach_callback function, Datum arg); +extern void cancel_on_dsm_detach(dsm_segment *seg, + on_dsm_detach_callback function, Datum arg); +extern void reset_on_dsm_detach(void); + +#endif /* DSM_H */ diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h new file mode 100644 index 0000000..c51584d --- /dev/null +++ b/src/include/storage/dsm_impl.h @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------- + * + * dsm_impl.h + * low-level dynamic shared memory primitives + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/dsm_impl.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSM_IMPL_H +#define DSM_IMPL_H + +/* Dynamic shared memory implementations. */ +#define DSM_IMPL_POSIX 1 +#define DSM_IMPL_SYSV 2 +#define DSM_IMPL_WINDOWS 3 +#define DSM_IMPL_MMAP 4 + +/* + * Determine which dynamic shared memory implementations will be supported + * on this platform, and which one will be the default. + */ +#ifdef WIN32 +#define USE_DSM_WINDOWS +#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_WINDOWS +#else +#ifdef HAVE_SHM_OPEN +#define USE_DSM_POSIX +#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_POSIX +#endif +#define USE_DSM_SYSV +#ifndef DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE +#define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_SYSV +#endif +#define USE_DSM_MMAP +#endif + +/* GUC. */ +extern PGDLLIMPORT int dynamic_shared_memory_type; +extern PGDLLIMPORT int min_dynamic_shared_memory; + +/* + * Directory for on-disk state. + * + * This is used by all implementations for crash recovery and by the mmap + * implementation for storage. + */ +#define PG_DYNSHMEM_DIR "pg_dynshmem" +#define PG_DYNSHMEM_MMAP_FILE_PREFIX "mmap." + +/* A "name" for a dynamic shared memory segment. */ +typedef uint32 dsm_handle; + +/* All the shared-memory operations we know about. */ +typedef enum +{ + DSM_OP_CREATE, + DSM_OP_ATTACH, + DSM_OP_DETACH, + DSM_OP_DESTROY +} dsm_op; + +/* Create, attach to, detach from, resize, or destroy a segment. */ +extern bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, + void **impl_private, void **mapped_address, Size *mapped_size, + int elevel); + +/* Implementation-dependent actions required to keep segment until shutdown. */ +extern void dsm_impl_pin_segment(dsm_handle handle, void *impl_private, + void **impl_private_pm_handle); +extern void dsm_impl_unpin_segment(dsm_handle handle, void **impl_private); + +#endif /* DSM_IMPL_H */ diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h new file mode 100644 index 0000000..69549b0 --- /dev/null +++ b/src/include/storage/fd.h @@ -0,0 +1,198 @@ +/*------------------------------------------------------------------------- + * + * fd.h + * Virtual file descriptor definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/fd.h + * + *------------------------------------------------------------------------- + */ + +/* + * calls: + * + * File {Close, Read, Write, Size, Sync} + * {Path Name Open, Allocate, Free} File + * + * These are NOT JUST RENAMINGS OF THE UNIX ROUTINES. + * Use them for all file activity... + * + * File fd; + * fd = PathNameOpenFile("foo", O_RDONLY); + * + * AllocateFile(); + * FreeFile(); + * + * Use AllocateFile, not fopen, if you need a stdio file (FILE*); then + * use FreeFile, not fclose, to close it. AVOID using stdio for files + * that you intend to hold open for any length of time, since there is + * no way for them to share kernel file descriptors with other files. + * + * Likewise, use AllocateDir/FreeDir, not opendir/closedir, to allocate + * open directories (DIR*), and OpenTransientFile/CloseTransientFile for an + * unbuffered file descriptor. + * + * If you really can't use any of the above, at least call AcquireExternalFD + * or ReserveExternalFD to report any file descriptors that are held for any + * length of time. Failure to do so risks unnecessary EMFILE errors. + */ +#ifndef FD_H +#define FD_H + +#include <dirent.h> + +typedef enum RecoveryInitSyncMethod +{ + RECOVERY_INIT_SYNC_METHOD_FSYNC, + RECOVERY_INIT_SYNC_METHOD_SYNCFS +} RecoveryInitSyncMethod; + +struct iovec; /* avoid including port/pg_iovec.h here */ + +typedef int File; + + +/* GUC parameter */ +extern PGDLLIMPORT int max_files_per_process; +extern PGDLLIMPORT bool data_sync_retry; +extern PGDLLIMPORT int recovery_init_sync_method; + +/* + * This is private to fd.c, but exported for save/restore_backend_variables() + */ +extern PGDLLIMPORT int max_safe_fds; + +/* + * On Windows, we have to interpret EACCES as possibly meaning the same as + * ENOENT, because if a file is unlinked-but-not-yet-gone on that platform, + * that's what you get. Ugh. This code is designed so that we don't + * actually believe these cases are okay without further evidence (namely, + * a pending fsync request getting canceled ... see ProcessSyncRequests). + */ +#ifndef WIN32 +#define FILE_POSSIBLY_DELETED(err) ((err) == ENOENT) +#else +#define FILE_POSSIBLY_DELETED(err) ((err) == ENOENT || (err) == EACCES) +#endif + +/* + * O_DIRECT is not standard, but almost every Unix has it. We translate it + * to the appropriate Windows flag in src/port/open.c. We simulate it with + * fcntl(F_NOCACHE) on macOS inside fd.c's open() wrapper. We use the name + * PG_O_DIRECT rather than defining O_DIRECT in that case (probably not a good + * idea on a Unix). + */ +#if defined(O_DIRECT) +#define PG_O_DIRECT O_DIRECT +#elif defined(F_NOCACHE) +#define PG_O_DIRECT 0x80000000 +#define PG_O_DIRECT_USE_F_NOCACHE +#else +#define PG_O_DIRECT 0 +#endif + +/* + * prototypes for functions in fd.c + */ + +/* Operations on virtual Files --- equivalent to Unix kernel file ops */ +extern File PathNameOpenFile(const char *fileName, int fileFlags); +extern File PathNameOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode); +extern File OpenTemporaryFile(bool interXact); +extern void FileClose(File file); +extern int FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info); +extern int FileRead(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info); +extern int FileWrite(File file, char *buffer, int amount, off_t offset, uint32 wait_event_info); +extern int FileSync(File file, uint32 wait_event_info); +extern off_t FileSize(File file); +extern int FileTruncate(File file, off_t offset, uint32 wait_event_info); +extern void FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info); +extern char *FilePathName(File file); +extern int FileGetRawDesc(File file); +extern int FileGetRawFlags(File file); +extern mode_t FileGetRawMode(File file); + +/* Operations used for sharing named temporary files */ +extern File PathNameCreateTemporaryFile(const char *name, bool error_on_failure); +extern File PathNameOpenTemporaryFile(const char *path, int mode); +extern bool PathNameDeleteTemporaryFile(const char *name, bool error_on_failure); +extern void PathNameCreateTemporaryDir(const char *base, const char *name); +extern void PathNameDeleteTemporaryDir(const char *name); +extern void TempTablespacePath(char *path, Oid tablespace); + +/* Operations that allow use of regular stdio --- USE WITH CAUTION */ +extern FILE *AllocateFile(const char *name, const char *mode); +extern int FreeFile(FILE *file); + +/* Operations that allow use of pipe streams (popen/pclose) */ +extern FILE *OpenPipeStream(const char *command, const char *mode); +extern int ClosePipeStream(FILE *file); + +/* Operations to allow use of the <dirent.h> library routines */ +extern DIR *AllocateDir(const char *dirname); +extern struct dirent *ReadDir(DIR *dir, const char *dirname); +extern struct dirent *ReadDirExtended(DIR *dir, const char *dirname, + int elevel); +extern int FreeDir(DIR *dir); + +/* Operations to allow use of a plain kernel FD, with automatic cleanup */ +extern int OpenTransientFile(const char *fileName, int fileFlags); +extern int OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode); +extern int CloseTransientFile(int fd); + +/* If you've really really gotta have a plain kernel FD, use this */ +extern int BasicOpenFile(const char *fileName, int fileFlags); +extern int BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode); + +/* Use these for other cases, and also for long-lived BasicOpenFile FDs */ +extern bool AcquireExternalFD(void); +extern void ReserveExternalFD(void); +extern void ReleaseExternalFD(void); + +/* Make a directory with default permissions */ +extern int MakePGDirectory(const char *directoryName); + +/* Miscellaneous support routines */ +extern void InitFileAccess(void); +extern void InitTemporaryFileAccess(void); +extern void set_max_safe_fds(void); +extern void closeAllVfds(void); +extern void SetTempTablespaces(Oid *tableSpaces, int numSpaces); +extern bool TempTablespacesAreSet(void); +extern int GetTempTablespaces(Oid *tableSpaces, int numSpaces); +extern Oid GetNextTempTableSpace(void); +extern void AtEOXact_Files(bool isCommit); +extern void AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid, + SubTransactionId parentSubid); +extern void RemovePgTempFiles(void); +extern void RemovePgTempFilesInDir(const char *tmpdirname, bool missing_ok, + bool unlink_all); +extern bool looks_like_temp_rel_name(const char *name); + +extern int pg_fsync(int fd); +extern int pg_fsync_no_writethrough(int fd); +extern int pg_fsync_writethrough(int fd); +extern int pg_fdatasync(int fd); +extern void pg_flush_data(int fd, off_t offset, off_t amount); +extern ssize_t pg_pwritev_with_retry(int fd, + const struct iovec *iov, + int iovcnt, + off_t offset); +extern int pg_truncate(const char *path, off_t length); +extern void fsync_fname(const char *fname, bool isdir); +extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel); +extern int durable_rename(const char *oldfile, const char *newfile, int loglevel); +extern int durable_unlink(const char *fname, int loglevel); +extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel); +extern void SyncDataDirectory(void); +extern int data_sync_elevel(int elevel); + +/* Filename components */ +#define PG_TEMP_FILES_DIR "pgsql_tmp" +#define PG_TEMP_FILE_PREFIX "pgsql_tmp" + +#endif /* FD_H */ diff --git a/src/include/storage/fileset.h b/src/include/storage/fileset.h new file mode 100644 index 0000000..ad37884 --- /dev/null +++ b/src/include/storage/fileset.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * fileset.h + * Management of named temporary files. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/fileset.h + * + *------------------------------------------------------------------------- + */ + +#ifndef FILESET_H +#define FILESET_H + +#include "storage/fd.h" + +/* + * A set of temporary files. + */ +typedef struct FileSet +{ + pid_t creator_pid; /* PID of the creating process */ + uint32 number; /* per-PID identifier */ + int ntablespaces; /* number of tablespaces to use */ + Oid tablespaces[8]; /* OIDs of tablespaces to use. Assumes that + * it's rare that there more than temp + * tablespaces. */ +} FileSet; + +extern void FileSetInit(FileSet *fileset); +extern File FileSetCreate(FileSet *fileset, const char *name); +extern File FileSetOpen(FileSet *fileset, const char *name, + int mode); +extern bool FileSetDelete(FileSet *fileset, const char *name, + bool error_on_failure); +extern void FileSetDeleteAll(FileSet *fileset); + +#endif diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h new file mode 100644 index 0000000..dcc40eb --- /dev/null +++ b/src/include/storage/freespace.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * freespace.h + * POSTGRES free space map for quickly finding free space in relations + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/freespace.h + * + *------------------------------------------------------------------------- + */ +#ifndef FREESPACE_H_ +#define FREESPACE_H_ + +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + +/* prototypes for public functions in freespace.c */ +extern Size GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk); +extern BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded); +extern BlockNumber RecordAndGetPageWithFreeSpace(Relation rel, + BlockNumber oldPage, + Size oldSpaceAvail, + Size spaceNeeded); +extern void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, + Size spaceAvail); +extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk, + Size spaceAvail); + +extern BlockNumber FreeSpaceMapPrepareTruncateRel(Relation rel, + BlockNumber nblocks); +extern void FreeSpaceMapVacuum(Relation rel); +extern void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, + BlockNumber end); + +#endif /* FREESPACE_H_ */ diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h new file mode 100644 index 0000000..a6f8372 --- /dev/null +++ b/src/include/storage/fsm_internals.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * fsm_internals.h + * internal functions for free space map + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/fsm_internals.h + * + *------------------------------------------------------------------------- + */ +#ifndef FSM_INTERNALS_H +#define FSM_INTERNALS_H + +#include "storage/buf.h" +#include "storage/bufpage.h" + +/* + * Structure of a FSM page. See src/backend/storage/freespace/README for + * details. + */ +typedef struct +{ + /* + * fsm_search_avail() tries to spread the load of multiple backends by + * returning different pages to different backends in a round-robin + * fashion. fp_next_slot points to the next slot to be returned (assuming + * there's enough space on it for the request). It's defined as an int, + * because it's updated without an exclusive lock. uint16 would be more + * appropriate, but int is more likely to be atomically + * fetchable/storable. + */ + int fp_next_slot; + + /* + * fp_nodes contains the binary tree, stored in array. The first + * NonLeafNodesPerPage elements are upper nodes, and the following + * LeafNodesPerPage elements are leaf nodes. Unused nodes are zero. + */ + uint8 fp_nodes[FLEXIBLE_ARRAY_MEMBER]; +} FSMPageData; + +typedef FSMPageData *FSMPage; + +/* + * Number of non-leaf and leaf nodes, and nodes in total, on an FSM page. + * These definitions are internal to fsmpage.c. + */ +#define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \ + offsetof(FSMPageData, fp_nodes)) + +#define NonLeafNodesPerPage (BLCKSZ / 2 - 1) +#define LeafNodesPerPage (NodesPerPage - NonLeafNodesPerPage) + +/* + * Number of FSM "slots" on a FSM page. This is what should be used + * outside fsmpage.c. + */ +#define SlotsPerFSMPage LeafNodesPerPage + +/* Prototypes for functions in fsmpage.c */ +extern int fsm_search_avail(Buffer buf, uint8 min_cat, bool advancenext, + bool exclusive_lock_held); +extern uint8 fsm_get_avail(Page page, int slot); +extern uint8 fsm_get_max_avail(Page page); +extern bool fsm_set_avail(Page page, int slot, uint8 value); +extern bool fsm_truncate_avail(Page page, int nslots); +extern bool fsm_rebuild_page(Page page); + +#endif /* FSM_INTERNALS_H */ diff --git a/src/include/storage/indexfsm.h b/src/include/storage/indexfsm.h new file mode 100644 index 0000000..04c1a05 --- /dev/null +++ b/src/include/storage/indexfsm.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * indexfsm.h + * POSTGRES free space map for quickly finding an unused page in index + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/indexfsm.h + * + *------------------------------------------------------------------------- + */ +#ifndef INDEXFSM_H_ +#define INDEXFSM_H_ + +#include "storage/block.h" +#include "utils/relcache.h" + +extern BlockNumber GetFreeIndexPage(Relation rel); +extern void RecordFreeIndexPage(Relation rel, BlockNumber page); +extern void RecordUsedIndexPage(Relation rel, BlockNumber page); + +extern void IndexFreeSpaceMapVacuum(Relation rel); + +#endif /* INDEXFSM_H_ */ diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h new file mode 100644 index 0000000..fade4db --- /dev/null +++ b/src/include/storage/ipc.h @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + * + * ipc.h + * POSTGRES inter-process communication definitions. + * + * This file is misnamed, as it no longer has much of anything directly + * to do with IPC. The functionality here is concerned with managing + * exit-time cleanup for either a postmaster or a backend. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/ipc.h + * + *------------------------------------------------------------------------- + */ +#ifndef IPC_H +#define IPC_H + +typedef void (*pg_on_exit_callback) (int code, Datum arg); +typedef void (*shmem_startup_hook_type) (void); + +/*---------- + * API for handling cleanup that must occur during either ereport(ERROR) + * or ereport(FATAL) exits from a block of code. (Typical examples are + * undoing transient changes to shared-memory state.) + * + * PG_ENSURE_ERROR_CLEANUP(cleanup_function, arg); + * { + * ... code that might throw ereport(ERROR) or ereport(FATAL) ... + * } + * PG_END_ENSURE_ERROR_CLEANUP(cleanup_function, arg); + * + * where the cleanup code is in a function declared per pg_on_exit_callback. + * The Datum value "arg" can carry any information the cleanup function + * needs. + * + * This construct ensures that cleanup_function() will be called during + * either ERROR or FATAL exits. It will not be called on successful + * exit from the controlled code. (If you want it to happen then too, + * call the function yourself from just after the construct.) + * + * Note: the macro arguments are multiply evaluated, so avoid side-effects. + *---------- + */ +#define PG_ENSURE_ERROR_CLEANUP(cleanup_function, arg) \ + do { \ + before_shmem_exit(cleanup_function, arg); \ + PG_TRY() + +#define PG_END_ENSURE_ERROR_CLEANUP(cleanup_function, arg) \ + cancel_before_shmem_exit(cleanup_function, arg); \ + PG_CATCH(); \ + { \ + cancel_before_shmem_exit(cleanup_function, arg); \ + cleanup_function (0, arg); \ + PG_RE_THROW(); \ + } \ + PG_END_TRY(); \ + } while (0) + + +/* ipc.c */ +extern PGDLLIMPORT bool proc_exit_inprogress; +extern PGDLLIMPORT bool shmem_exit_inprogress; + +extern void proc_exit(int code) pg_attribute_noreturn(); +extern void shmem_exit(int code); +extern void on_proc_exit(pg_on_exit_callback function, Datum arg); +extern void on_shmem_exit(pg_on_exit_callback function, Datum arg); +extern void before_shmem_exit(pg_on_exit_callback function, Datum arg); +extern void cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg); +extern void on_exit_reset(void); +extern void check_on_shmem_exit_lists_are_empty(void); + +/* ipci.c */ +extern PGDLLIMPORT shmem_startup_hook_type shmem_startup_hook; + +extern Size CalculateShmemSize(int *num_semaphores); +extern void CreateSharedMemoryAndSemaphores(void); +extern void InitializeShmemGUCs(void); + +#endif /* IPC_H */ diff --git a/src/include/storage/item.h b/src/include/storage/item.h new file mode 100644 index 0000000..6f3eaeb --- /dev/null +++ b/src/include/storage/item.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------- + * + * item.h + * POSTGRES disk item definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/item.h + * + *------------------------------------------------------------------------- + */ +#ifndef ITEM_H +#define ITEM_H + +typedef Pointer Item; + +#endif /* ITEM_H */ diff --git a/src/include/storage/itemid.h b/src/include/storage/itemid.h new file mode 100644 index 0000000..e33637f --- /dev/null +++ b/src/include/storage/itemid.h @@ -0,0 +1,184 @@ +/*------------------------------------------------------------------------- + * + * itemid.h + * Standard POSTGRES buffer page item identifier/line pointer definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/itemid.h + * + *------------------------------------------------------------------------- + */ +#ifndef ITEMID_H +#define ITEMID_H + +/* + * A line pointer on a buffer page. See buffer page definitions and comments + * for an explanation of how line pointers are used. + * + * In some cases a line pointer is "in use" but does not have any associated + * storage on the page. By convention, lp_len == 0 in every line pointer + * that does not have storage, independently of its lp_flags state. + */ +typedef struct ItemIdData +{ + unsigned lp_off:15, /* offset to tuple (from start of page) */ + lp_flags:2, /* state of line pointer, see below */ + lp_len:15; /* byte length of tuple */ +} ItemIdData; + +typedef ItemIdData *ItemId; + +/* + * lp_flags has these possible states. An UNUSED line pointer is available + * for immediate re-use, the other states are not. + */ +#define LP_UNUSED 0 /* unused (should always have lp_len=0) */ +#define LP_NORMAL 1 /* used (should always have lp_len>0) */ +#define LP_REDIRECT 2 /* HOT redirect (should have lp_len=0) */ +#define LP_DEAD 3 /* dead, may or may not have storage */ + +/* + * Item offsets and lengths are represented by these types when + * they're not actually stored in an ItemIdData. + */ +typedef uint16 ItemOffset; +typedef uint16 ItemLength; + + +/* ---------------- + * support macros + * ---------------- + */ + +/* + * ItemIdGetLength + */ +#define ItemIdGetLength(itemId) \ + ((itemId)->lp_len) + +/* + * ItemIdGetOffset + */ +#define ItemIdGetOffset(itemId) \ + ((itemId)->lp_off) + +/* + * ItemIdGetFlags + */ +#define ItemIdGetFlags(itemId) \ + ((itemId)->lp_flags) + +/* + * ItemIdGetRedirect + * In a REDIRECT pointer, lp_off holds offset number for next line pointer + */ +#define ItemIdGetRedirect(itemId) \ + ((itemId)->lp_off) + +/* + * ItemIdIsValid + * True iff item identifier is valid. + * This is a pretty weak test, probably useful only in Asserts. + */ +#define ItemIdIsValid(itemId) PointerIsValid(itemId) + +/* + * ItemIdIsUsed + * True iff item identifier is in use. + */ +#define ItemIdIsUsed(itemId) \ + ((itemId)->lp_flags != LP_UNUSED) + +/* + * ItemIdIsNormal + * True iff item identifier is in state NORMAL. + */ +#define ItemIdIsNormal(itemId) \ + ((itemId)->lp_flags == LP_NORMAL) + +/* + * ItemIdIsRedirected + * True iff item identifier is in state REDIRECT. + */ +#define ItemIdIsRedirected(itemId) \ + ((itemId)->lp_flags == LP_REDIRECT) + +/* + * ItemIdIsDead + * True iff item identifier is in state DEAD. + */ +#define ItemIdIsDead(itemId) \ + ((itemId)->lp_flags == LP_DEAD) + +/* + * ItemIdHasStorage + * True iff item identifier has associated storage. + */ +#define ItemIdHasStorage(itemId) \ + ((itemId)->lp_len != 0) + +/* + * ItemIdSetUnused + * Set the item identifier to be UNUSED, with no storage. + * Beware of multiple evaluations of itemId! + */ +#define ItemIdSetUnused(itemId) \ +( \ + (itemId)->lp_flags = LP_UNUSED, \ + (itemId)->lp_off = 0, \ + (itemId)->lp_len = 0 \ +) + +/* + * ItemIdSetNormal + * Set the item identifier to be NORMAL, with the specified storage. + * Beware of multiple evaluations of itemId! + */ +#define ItemIdSetNormal(itemId, off, len) \ +( \ + (itemId)->lp_flags = LP_NORMAL, \ + (itemId)->lp_off = (off), \ + (itemId)->lp_len = (len) \ +) + +/* + * ItemIdSetRedirect + * Set the item identifier to be REDIRECT, with the specified link. + * Beware of multiple evaluations of itemId! + */ +#define ItemIdSetRedirect(itemId, link) \ +( \ + (itemId)->lp_flags = LP_REDIRECT, \ + (itemId)->lp_off = (link), \ + (itemId)->lp_len = 0 \ +) + +/* + * ItemIdSetDead + * Set the item identifier to be DEAD, with no storage. + * Beware of multiple evaluations of itemId! + */ +#define ItemIdSetDead(itemId) \ +( \ + (itemId)->lp_flags = LP_DEAD, \ + (itemId)->lp_off = 0, \ + (itemId)->lp_len = 0 \ +) + +/* + * ItemIdMarkDead + * Set the item identifier to be DEAD, keeping its existing storage. + * + * Note: in indexes, this is used as if it were a hint-bit mechanism; + * we trust that multiple processors can do this in parallel and get + * the same result. + */ +#define ItemIdMarkDead(itemId) \ +( \ + (itemId)->lp_flags = LP_DEAD \ +) + +#endif /* ITEMID_H */ diff --git a/src/include/storage/itemptr.h b/src/include/storage/itemptr.h new file mode 100644 index 0000000..81947bc --- /dev/null +++ b/src/include/storage/itemptr.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- + * + * itemptr.h + * POSTGRES disk item pointer definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/itemptr.h + * + *------------------------------------------------------------------------- + */ +#ifndef ITEMPTR_H +#define ITEMPTR_H + +#include "storage/block.h" +#include "storage/off.h" + +/* + * ItemPointer: + * + * This is a pointer to an item within a disk page of a known file + * (for example, a cross-link from an index to its parent table). + * ip_blkid tells us which block, ip_posid tells us which entry in + * the linp (ItemIdData) array we want. + * + * Note: because there is an item pointer in each tuple header and index + * tuple header on disk, it's very important not to waste space with + * structure padding bytes. The struct is designed to be six bytes long + * (it contains three int16 fields) but a few compilers will pad it to + * eight bytes unless coerced. We apply appropriate persuasion where + * possible. If your compiler can't be made to play along, you'll waste + * lots of space. + */ +typedef struct ItemPointerData +{ + BlockIdData ip_blkid; + OffsetNumber ip_posid; +} + +/* If compiler understands packed and aligned pragmas, use those */ +#if defined(pg_attribute_packed) && defined(pg_attribute_aligned) + pg_attribute_packed() + pg_attribute_aligned(2) +#endif +ItemPointerData; + +typedef ItemPointerData *ItemPointer; + +/* ---------------- + * special values used in heap tuples (t_ctid) + * ---------------- + */ + +/* + * If a heap tuple holds a speculative insertion token rather than a real + * TID, ip_posid is set to SpecTokenOffsetNumber, and the token is stored in + * ip_blkid. SpecTokenOffsetNumber must be higher than MaxOffsetNumber, so + * that it can be distinguished from a valid offset number in a regular item + * pointer. + */ +#define SpecTokenOffsetNumber 0xfffe + +/* + * When a tuple is moved to a different partition by UPDATE, the t_ctid of + * the old tuple version is set to this magic value. + */ +#define MovedPartitionsOffsetNumber 0xfffd +#define MovedPartitionsBlockNumber InvalidBlockNumber + + +/* ---------------- + * support macros + * ---------------- + */ + +/* + * ItemPointerIsValid + * True iff the disk item pointer is not NULL. + */ +#define ItemPointerIsValid(pointer) \ + ((bool) (PointerIsValid(pointer) && ((pointer)->ip_posid != 0))) + +/* + * ItemPointerGetBlockNumberNoCheck + * Returns the block number of a disk item pointer. + */ +#define ItemPointerGetBlockNumberNoCheck(pointer) \ +( \ + BlockIdGetBlockNumber(&(pointer)->ip_blkid) \ +) + +/* + * ItemPointerGetBlockNumber + * As above, but verifies that the item pointer looks valid. + */ +#define ItemPointerGetBlockNumber(pointer) \ +( \ + AssertMacro(ItemPointerIsValid(pointer)), \ + ItemPointerGetBlockNumberNoCheck(pointer) \ +) + +/* + * ItemPointerGetOffsetNumberNoCheck + * Returns the offset number of a disk item pointer. + */ +#define ItemPointerGetOffsetNumberNoCheck(pointer) \ +( \ + (pointer)->ip_posid \ +) + +/* + * ItemPointerGetOffsetNumber + * As above, but verifies that the item pointer looks valid. + */ +#define ItemPointerGetOffsetNumber(pointer) \ +( \ + AssertMacro(ItemPointerIsValid(pointer)), \ + ItemPointerGetOffsetNumberNoCheck(pointer) \ +) + +/* + * ItemPointerSet + * Sets a disk item pointer to the specified block and offset. + */ +#define ItemPointerSet(pointer, blockNumber, offNum) \ +( \ + AssertMacro(PointerIsValid(pointer)), \ + BlockIdSet(&((pointer)->ip_blkid), blockNumber), \ + (pointer)->ip_posid = offNum \ +) + +/* + * ItemPointerSetBlockNumber + * Sets a disk item pointer to the specified block. + */ +#define ItemPointerSetBlockNumber(pointer, blockNumber) \ +( \ + AssertMacro(PointerIsValid(pointer)), \ + BlockIdSet(&((pointer)->ip_blkid), blockNumber) \ +) + +/* + * ItemPointerSetOffsetNumber + * Sets a disk item pointer to the specified offset. + */ +#define ItemPointerSetOffsetNumber(pointer, offsetNumber) \ +( \ + AssertMacro(PointerIsValid(pointer)), \ + (pointer)->ip_posid = (offsetNumber) \ +) + +/* + * ItemPointerCopy + * Copies the contents of one disk item pointer to another. + * + * Should there ever be padding in an ItemPointer this would need to be handled + * differently as it's used as hash key. + */ +#define ItemPointerCopy(fromPointer, toPointer) \ +( \ + AssertMacro(PointerIsValid(toPointer)), \ + AssertMacro(PointerIsValid(fromPointer)), \ + *(toPointer) = *(fromPointer) \ +) + +/* + * ItemPointerSetInvalid + * Sets a disk item pointer to be invalid. + */ +#define ItemPointerSetInvalid(pointer) \ +( \ + AssertMacro(PointerIsValid(pointer)), \ + BlockIdSet(&((pointer)->ip_blkid), InvalidBlockNumber), \ + (pointer)->ip_posid = InvalidOffsetNumber \ +) + +/* + * ItemPointerIndicatesMovedPartitions + * True iff the block number indicates the tuple has moved to another + * partition. + */ +#define ItemPointerIndicatesMovedPartitions(pointer) \ +( \ + ItemPointerGetOffsetNumber(pointer) == MovedPartitionsOffsetNumber && \ + ItemPointerGetBlockNumberNoCheck(pointer) == MovedPartitionsBlockNumber \ +) + +/* + * ItemPointerSetMovedPartitions + * Indicate that the item referenced by the itempointer has moved into a + * different partition. + */ +#define ItemPointerSetMovedPartitions(pointer) \ + ItemPointerSet((pointer), MovedPartitionsBlockNumber, MovedPartitionsOffsetNumber) + +/* ---------------- + * externs + * ---------------- + */ + +extern bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2); +extern int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2); +extern void ItemPointerInc(ItemPointer pointer); +extern void ItemPointerDec(ItemPointer pointer); + +#endif /* ITEMPTR_H */ diff --git a/src/include/storage/large_object.h b/src/include/storage/large_object.h new file mode 100644 index 0000000..b826a7d --- /dev/null +++ b/src/include/storage/large_object.h @@ -0,0 +1,100 @@ +/*------------------------------------------------------------------------- + * + * large_object.h + * Declarations for PostgreSQL large objects. POSTGRES 4.2 supported + * zillions of large objects (internal, external, jaquith, inversion). + * Now we only support inversion. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/large_object.h + * + *------------------------------------------------------------------------- + */ +#ifndef LARGE_OBJECT_H +#define LARGE_OBJECT_H + +#include "utils/snapshot.h" + + +/*---------- + * Data about a currently-open large object. + * + * id is the logical OID of the large object + * snapshot is the snapshot to use for read/write operations + * subid is the subtransaction that opened the desc (or currently owns it) + * offset is the current seek offset within the LO + * flags contains some flag bits + * + * NOTE: as of v11, permission checks are made when the large object is + * opened; therefore IFS_RDLOCK/IFS_WRLOCK indicate that read or write mode + * has been requested *and* the corresponding permission has been checked. + * + * NOTE: before 7.1, we also had to store references to the separate table + * and index of a specific large object. Now they all live in pg_largeobject + * and are accessed via a common relation descriptor. + *---------- + */ +typedef struct LargeObjectDesc +{ + Oid id; /* LO's identifier */ + Snapshot snapshot; /* snapshot to use */ + SubTransactionId subid; /* owning subtransaction ID */ + uint64 offset; /* current seek pointer */ + int flags; /* see flag bits below */ + +/* bits in flags: */ +#define IFS_RDLOCK (1 << 0) /* LO was opened for reading */ +#define IFS_WRLOCK (1 << 1) /* LO was opened for writing */ + +} LargeObjectDesc; + + +/* + * Each "page" (tuple) of a large object can hold this much data + * + * We could set this as high as BLCKSZ less some overhead, but it seems + * better to make it a smaller value, so that not as much space is used + * up when a page-tuple is updated. Note that the value is deliberately + * chosen large enough to trigger the tuple toaster, so that we will + * attempt to compress page tuples in-line. (But they won't be moved off + * unless the user creates a toast-table for pg_largeobject...) + * + * Also, it seems to be a smart move to make the page size be a power of 2, + * since clients will often be written to send data in power-of-2 blocks. + * This avoids unnecessary tuple updates caused by partial-page writes. + * + * NB: Changing LOBLKSIZE requires an initdb. + */ +#define LOBLKSIZE (BLCKSZ / 4) + +/* + * Maximum length in bytes for a large object. To make this larger, we'd + * have to widen pg_largeobject.pageno as well as various internal variables. + */ +#define MAX_LARGE_OBJECT_SIZE ((int64) INT_MAX * LOBLKSIZE) + + +/* + * GUC: backwards-compatibility flag to suppress LO permission checks + */ +extern PGDLLIMPORT bool lo_compat_privileges; + +/* + * Function definitions... + */ + +/* inversion stuff in inv_api.c */ +extern void close_lo_relation(bool isCommit); +extern Oid inv_create(Oid lobjId); +extern LargeObjectDesc *inv_open(Oid lobjId, int flags, MemoryContext mcxt); +extern void inv_close(LargeObjectDesc *obj_desc); +extern int inv_drop(Oid lobjId); +extern int64 inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence); +extern int64 inv_tell(LargeObjectDesc *obj_desc); +extern int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes); +extern int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes); +extern void inv_truncate(LargeObjectDesc *obj_desc, int64 len); + +#endif /* LARGE_OBJECT_H */ diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h new file mode 100644 index 0000000..68ab740 --- /dev/null +++ b/src/include/storage/latch.h @@ -0,0 +1,186 @@ +/*------------------------------------------------------------------------- + * + * latch.h + * Routines for interprocess latches + * + * A latch is a boolean variable, with operations that let processes sleep + * until it is set. A latch can be set from another process, or a signal + * handler within the same process. + * + * The latch interface is a reliable replacement for the common pattern of + * using pg_usleep() or select() to wait until a signal arrives, where the + * signal handler sets a flag variable. Because on some platforms an + * incoming signal doesn't interrupt sleep, and even on platforms where it + * does there is a race condition if the signal arrives just before + * entering the sleep, the common pattern must periodically wake up and + * poll the flag variable. The pselect() system call was invented to solve + * this problem, but it is not portable enough. Latches are designed to + * overcome these limitations, allowing you to sleep without polling and + * ensuring quick response to signals from other processes. + * + * There are two kinds of latches: local and shared. A local latch is + * initialized by InitLatch, and can only be set from the same process. + * A local latch can be used to wait for a signal to arrive, by calling + * SetLatch in the signal handler. A shared latch resides in shared memory, + * and must be initialized at postmaster startup by InitSharedLatch. Before + * a shared latch can be waited on, it must be associated with a process + * with OwnLatch. Only the process owning the latch can wait on it, but any + * process can set it. + * + * There are three basic operations on a latch: + * + * SetLatch - Sets the latch + * ResetLatch - Clears the latch, allowing it to be set again + * WaitLatch - Waits for the latch to become set + * + * WaitLatch includes a provision for timeouts (which should be avoided + * when possible, as they incur extra overhead) and a provision for + * postmaster child processes to wake up immediately on postmaster death. + * See latch.c for detailed specifications for the exported functions. + * + * The correct pattern to wait for event(s) is: + * + * for (;;) + * { + * ResetLatch(); + * if (work to do) + * Do Stuff(); + * WaitLatch(); + * } + * + * It's important to reset the latch *before* checking if there's work to + * do. Otherwise, if someone sets the latch between the check and the + * ResetLatch call, you will miss it and Wait will incorrectly block. + * + * Another valid coding pattern looks like: + * + * for (;;) + * { + * if (work to do) + * Do Stuff(); // in particular, exit loop if some condition satisfied + * WaitLatch(); + * ResetLatch(); + * } + * + * This is useful to reduce latch traffic if it's expected that the loop's + * termination condition will often be satisfied in the first iteration; + * the cost is an extra loop iteration before blocking when it is not. + * What must be avoided is placing any checks for asynchronous events after + * WaitLatch and before ResetLatch, as that creates a race condition. + * + * To wake up the waiter, you must first set a global flag or something + * else that the wait loop tests in the "if (work to do)" part, and call + * SetLatch *after* that. SetLatch is designed to return quickly if the + * latch is already set. + * + * On some platforms, signals will not interrupt the latch wait primitive + * by themselves. Therefore, it is critical that any signal handler that + * is meant to terminate a WaitLatch wait calls SetLatch. + * + * Note that use of the process latch (PGPROC.procLatch) is generally better + * than an ad-hoc shared latch for signaling auxiliary processes. This is + * because generic signal handlers will call SetLatch on the process latch + * only, so using any latch other than the process latch effectively precludes + * use of any generic handler. + * + * + * WaitEventSets allow to wait for latches being set and additional events - + * postmaster dying and socket readiness of several sockets currently - at the + * same time. On many platforms using a long lived event set is more + * efficient than using WaitLatch or WaitLatchOrSocket. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/latch.h + * + *------------------------------------------------------------------------- + */ +#ifndef LATCH_H +#define LATCH_H + +#include <signal.h> + +/* + * Latch structure should be treated as opaque and only accessed through + * the public functions. It is defined here to allow embedding Latches as + * part of bigger structs. + */ +typedef struct Latch +{ + sig_atomic_t is_set; + sig_atomic_t maybe_sleeping; + bool is_shared; + int owner_pid; +#ifdef WIN32 + HANDLE event; +#endif +} Latch; + +/* + * Bitmasks for events that may wake-up WaitLatch(), WaitLatchOrSocket(), or + * WaitEventSetWait(). + */ +#define WL_LATCH_SET (1 << 0) +#define WL_SOCKET_READABLE (1 << 1) +#define WL_SOCKET_WRITEABLE (1 << 2) +#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */ +#define WL_POSTMASTER_DEATH (1 << 4) +#define WL_EXIT_ON_PM_DEATH (1 << 5) +#ifdef WIN32 +#define WL_SOCKET_CONNECTED (1 << 6) +#else +/* avoid having to deal with case on platforms not requiring it */ +#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE +#endif +#define WL_SOCKET_CLOSED (1 << 7) +#define WL_SOCKET_MASK (WL_SOCKET_READABLE | \ + WL_SOCKET_WRITEABLE | \ + WL_SOCKET_CONNECTED | \ + WL_SOCKET_CLOSED) + +typedef struct WaitEvent +{ + int pos; /* position in the event data structure */ + uint32 events; /* triggered events */ + pgsocket fd; /* socket fd associated with event */ + void *user_data; /* pointer provided in AddWaitEventToSet */ +#ifdef WIN32 + bool reset; /* Is reset of the event required? */ +#endif +} WaitEvent; + +/* forward declaration to avoid exposing latch.c implementation details */ +typedef struct WaitEventSet WaitEventSet; + +/* + * prototypes for functions in latch.c + */ +extern void InitializeLatchSupport(void); +extern void InitLatch(Latch *latch); +extern void InitSharedLatch(Latch *latch); +extern void OwnLatch(Latch *latch); +extern void DisownLatch(Latch *latch); +extern void SetLatch(Latch *latch); +extern void ResetLatch(Latch *latch); +extern void ShutdownLatchSupport(void); + +extern WaitEventSet *CreateWaitEventSet(MemoryContext context, int nevents); +extern void FreeWaitEventSet(WaitEventSet *set); +extern int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, + Latch *latch, void *user_data); +extern void ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch); + +extern int WaitEventSetWait(WaitEventSet *set, long timeout, + WaitEvent *occurred_events, int nevents, + uint32 wait_event_info); +extern int WaitLatch(Latch *latch, int wakeEvents, long timeout, + uint32 wait_event_info); +extern int WaitLatchOrSocket(Latch *latch, int wakeEvents, + pgsocket sock, long timeout, uint32 wait_event_info); +extern void InitializeLatchWaitSet(void); +extern int GetNumRegisteredWaitEvents(WaitEventSet *set); +extern bool WaitEventSetCanReportClosed(void); + +#endif /* LATCH_H */ diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h new file mode 100644 index 0000000..be1d2c9 --- /dev/null +++ b/src/include/storage/lmgr.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- + * + * lmgr.h + * POSTGRES lock manager definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/lmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef LMGR_H +#define LMGR_H + +#include "lib/stringinfo.h" +#include "storage/itemptr.h" +#include "storage/lock.h" +#include "utils/rel.h" + + +/* XactLockTableWait operations */ +typedef enum XLTW_Oper +{ + XLTW_None, + XLTW_Update, + XLTW_Delete, + XLTW_Lock, + XLTW_LockUpdated, + XLTW_InsertIndex, + XLTW_InsertIndexUnique, + XLTW_FetchUpdated, + XLTW_RecheckExclusionConstr +} XLTW_Oper; + +extern void RelationInitLockInfo(Relation relation); + +/* Lock a relation */ +extern void LockRelationOid(Oid relid, LOCKMODE lockmode); +extern void LockRelationId(LockRelId *relid, LOCKMODE lockmode); +extern bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode); +extern void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode); +extern void UnlockRelationOid(Oid relid, LOCKMODE lockmode); + +extern void LockRelation(Relation relation, LOCKMODE lockmode); +extern bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode); +extern void UnlockRelation(Relation relation, LOCKMODE lockmode); +extern bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, + bool orstronger); +extern bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode); + +extern void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode); +extern void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode); + +/* Lock a relation for extension */ +extern void LockRelationForExtension(Relation relation, LOCKMODE lockmode); +extern void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode); +extern bool ConditionalLockRelationForExtension(Relation relation, + LOCKMODE lockmode); +extern int RelationExtensionLockWaiterCount(Relation relation); + +/* Lock to recompute pg_database.datfrozenxid in the current database */ +extern void LockDatabaseFrozenIds(LOCKMODE lockmode); + +/* Lock a page (currently only used within indexes) */ +extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); +extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); +extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); + +/* Lock a tuple (see heap_lock_tuple before assuming you understand this) */ +extern void LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode); +extern bool ConditionalLockTuple(Relation relation, ItemPointer tid, + LOCKMODE lockmode); +extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode); + +/* Lock an XID (used to wait for a transaction to finish) */ +extern void XactLockTableInsert(TransactionId xid); +extern void XactLockTableDelete(TransactionId xid); +extern void XactLockTableWait(TransactionId xid, Relation rel, + ItemPointer ctid, XLTW_Oper oper); +extern bool ConditionalXactLockTableWait(TransactionId xid); + +/* Lock VXIDs, specified by conflicting locktags */ +extern void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress); +extern void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress); + +/* Lock an XID for tuple insertion (used to wait for an insertion to finish) */ +extern uint32 SpeculativeInsertionLockAcquire(TransactionId xid); +extern void SpeculativeInsertionLockRelease(TransactionId xid); +extern void SpeculativeInsertionWait(TransactionId xid, uint32 token); + +/* Lock a general object (other than a relation) of the current database */ +extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); +extern void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); + +/* Lock a shared-across-databases object (other than a relation) */ +extern void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); +extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); + +extern void LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); +extern void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, + LOCKMODE lockmode); + +/* Describe a locktag for error messages */ +extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag); + +extern const char *GetLockNameFromTagType(uint16 locktag_type); + +#endif /* LMGR_H */ diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h new file mode 100644 index 0000000..e4e1495 --- /dev/null +++ b/src/include/storage/lock.h @@ -0,0 +1,616 @@ +/*------------------------------------------------------------------------- + * + * lock.h + * POSTGRES low-level lock mechanism + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/lock.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOCK_H_ +#define LOCK_H_ + +#ifdef FRONTEND +#error "lock.h may not be included from frontend code" +#endif + +#include "storage/backendid.h" +#include "storage/lockdefs.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "utils/timestamp.h" + +/* struct PGPROC is declared in proc.h, but must forward-reference it */ +typedef struct PGPROC PGPROC; + +typedef struct PROC_QUEUE +{ + SHM_QUEUE links; /* head of list of PGPROC objects */ + int size; /* number of entries in list */ +} PROC_QUEUE; + +/* GUC variables */ +extern PGDLLIMPORT int max_locks_per_xact; + +#ifdef LOCK_DEBUG +extern PGDLLIMPORT int Trace_lock_oidmin; +extern PGDLLIMPORT bool Trace_locks; +extern PGDLLIMPORT bool Trace_userlocks; +extern PGDLLIMPORT int Trace_lock_table; +extern PGDLLIMPORT bool Debug_deadlocks; +#endif /* LOCK_DEBUG */ + + +/* + * Top-level transactions are identified by VirtualTransactionIDs comprising + * PGPROC fields backendId and lxid. For recovered prepared transactions, the + * LocalTransactionId is an ordinary XID; LOCKTAG_VIRTUALTRANSACTION never + * refers to that kind. These are guaranteed unique over the short term, but + * will be reused after a database restart or XID wraparound; hence they + * should never be stored on disk. + * + * Note that struct VirtualTransactionId can not be assumed to be atomically + * assignable as a whole. However, type LocalTransactionId is assumed to + * be atomically assignable, and the backend ID doesn't change often enough + * to be a problem, so we can fetch or assign the two fields separately. + * We deliberately refrain from using the struct within PGPROC, to prevent + * coding errors from trying to use struct assignment with it; instead use + * GET_VXID_FROM_PGPROC(). + */ +typedef struct +{ + BackendId backendId; /* backendId from PGPROC */ + LocalTransactionId localTransactionId; /* lxid from PGPROC */ +} VirtualTransactionId; + +#define InvalidLocalTransactionId 0 +#define LocalTransactionIdIsValid(lxid) ((lxid) != InvalidLocalTransactionId) +#define VirtualTransactionIdIsValid(vxid) \ + (LocalTransactionIdIsValid((vxid).localTransactionId)) +#define VirtualTransactionIdIsRecoveredPreparedXact(vxid) \ + ((vxid).backendId == InvalidBackendId) +#define VirtualTransactionIdEquals(vxid1, vxid2) \ + ((vxid1).backendId == (vxid2).backendId && \ + (vxid1).localTransactionId == (vxid2).localTransactionId) +#define SetInvalidVirtualTransactionId(vxid) \ + ((vxid).backendId = InvalidBackendId, \ + (vxid).localTransactionId = InvalidLocalTransactionId) +#define GET_VXID_FROM_PGPROC(vxid, proc) \ + ((vxid).backendId = (proc).backendId, \ + (vxid).localTransactionId = (proc).lxid) + +/* MAX_LOCKMODES cannot be larger than the # of bits in LOCKMASK */ +#define MAX_LOCKMODES 10 + +#define LOCKBIT_ON(lockmode) (1 << (lockmode)) +#define LOCKBIT_OFF(lockmode) (~(1 << (lockmode))) + + +/* + * This data structure defines the locking semantics associated with a + * "lock method". The semantics specify the meaning of each lock mode + * (by defining which lock modes it conflicts with). + * All of this data is constant and is kept in const tables. + * + * numLockModes -- number of lock modes (READ,WRITE,etc) that + * are defined in this lock method. Must be less than MAX_LOCKMODES. + * + * conflictTab -- this is an array of bitmasks showing lock + * mode conflicts. conflictTab[i] is a mask with the j-th bit + * turned on if lock modes i and j conflict. Lock modes are + * numbered 1..numLockModes; conflictTab[0] is unused. + * + * lockModeNames -- ID strings for debug printouts. + * + * trace_flag -- pointer to GUC trace flag for this lock method. (The + * GUC variable is not constant, but we use "const" here to denote that + * it can't be changed through this reference.) + */ +typedef struct LockMethodData +{ + int numLockModes; + const LOCKMASK *conflictTab; + const char *const *lockModeNames; + const bool *trace_flag; +} LockMethodData; + +typedef const LockMethodData *LockMethod; + +/* + * Lock methods are identified by LOCKMETHODID. (Despite the declaration as + * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.) + */ +typedef uint16 LOCKMETHODID; + +/* These identify the known lock methods */ +#define DEFAULT_LOCKMETHOD 1 +#define USER_LOCKMETHOD 2 + +/* + * LOCKTAG is the key information needed to look up a LOCK item in the + * lock hashtable. A LOCKTAG value uniquely identifies a lockable object. + * + * The LockTagType enum defines the different kinds of objects we can lock. + * We can handle up to 256 different LockTagTypes. + */ +typedef enum LockTagType +{ + LOCKTAG_RELATION, /* whole relation */ + LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */ + LOCKTAG_DATABASE_FROZEN_IDS, /* pg_database.datfrozenxid */ + LOCKTAG_PAGE, /* one page of a relation */ + LOCKTAG_TUPLE, /* one physical tuple */ + LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */ + LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */ + LOCKTAG_SPECULATIVE_TOKEN, /* speculative insertion Xid and token */ + LOCKTAG_OBJECT, /* non-relation database object */ + LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */ + LOCKTAG_ADVISORY /* advisory user locks */ +} LockTagType; + +#define LOCKTAG_LAST_TYPE LOCKTAG_ADVISORY + +extern PGDLLIMPORT const char *const LockTagTypeNames[]; + +/* + * The LOCKTAG struct is defined with malice aforethought to fit into 16 + * bytes with no padding. Note that this would need adjustment if we were + * to widen Oid, BlockNumber, or TransactionId to more than 32 bits. + * + * We include lockmethodid in the locktag so that a single hash table in + * shared memory can store locks of different lockmethods. + */ +typedef struct LOCKTAG +{ + uint32 locktag_field1; /* a 32-bit ID field */ + uint32 locktag_field2; /* a 32-bit ID field */ + uint32 locktag_field3; /* a 32-bit ID field */ + uint16 locktag_field4; /* a 16-bit ID field */ + uint8 locktag_type; /* see enum LockTagType */ + uint8 locktag_lockmethodid; /* lockmethod indicator */ +} LOCKTAG; + +/* + * These macros define how we map logical IDs of lockable objects into + * the physical fields of LOCKTAG. Use these to set up LOCKTAG values, + * rather than accessing the fields directly. Note multiple eval of target! + */ + +/* ID info for a relation is DB OID + REL OID; DB OID = 0 if shared */ +#define SET_LOCKTAG_RELATION(locktag,dboid,reloid) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_RELATION, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* same ID info as RELATION */ +#define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_RELATION_EXTEND, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* ID info for frozen IDs is DB OID */ +#define SET_LOCKTAG_DATABASE_FROZEN_IDS(locktag,dboid) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = 0, \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_DATABASE_FROZEN_IDS, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* ID info for a page is RELATION info + BlockNumber */ +#define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = (blocknum), \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_PAGE, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* ID info for a tuple is PAGE info + OffsetNumber */ +#define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = (blocknum), \ + (locktag).locktag_field4 = (offnum), \ + (locktag).locktag_type = LOCKTAG_TUPLE, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* ID info for a transaction is its TransactionId */ +#define SET_LOCKTAG_TRANSACTION(locktag,xid) \ + ((locktag).locktag_field1 = (xid), \ + (locktag).locktag_field2 = 0, \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_TRANSACTION, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* ID info for a virtual transaction is its VirtualTransactionId */ +#define SET_LOCKTAG_VIRTUALTRANSACTION(locktag,vxid) \ + ((locktag).locktag_field1 = (vxid).backendId, \ + (locktag).locktag_field2 = (vxid).localTransactionId, \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_VIRTUALTRANSACTION, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* + * ID info for a speculative insert is TRANSACTION info + + * its speculative insert counter. + */ +#define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag,xid,token) \ + ((locktag).locktag_field1 = (xid), \ + (locktag).locktag_field2 = (token), \ + (locktag).locktag_field3 = 0, \ + (locktag).locktag_field4 = 0, \ + (locktag).locktag_type = LOCKTAG_SPECULATIVE_TOKEN, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +/* + * ID info for an object is DB OID + CLASS OID + OBJECT OID + SUBID + * + * Note: object ID has same representation as in pg_depend and + * pg_description, but notice that we are constraining SUBID to 16 bits. + * Also, we use DB OID = 0 for shared objects such as tablespaces. + */ +#define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (classoid), \ + (locktag).locktag_field3 = (objoid), \ + (locktag).locktag_field4 = (objsubid), \ + (locktag).locktag_type = LOCKTAG_OBJECT, \ + (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) + +#define SET_LOCKTAG_ADVISORY(locktag,id1,id2,id3,id4) \ + ((locktag).locktag_field1 = (id1), \ + (locktag).locktag_field2 = (id2), \ + (locktag).locktag_field3 = (id3), \ + (locktag).locktag_field4 = (id4), \ + (locktag).locktag_type = LOCKTAG_ADVISORY, \ + (locktag).locktag_lockmethodid = USER_LOCKMETHOD) + + +/* + * Per-locked-object lock information: + * + * tag -- uniquely identifies the object being locked + * grantMask -- bitmask for all lock types currently granted on this object. + * waitMask -- bitmask for all lock types currently awaited on this object. + * procLocks -- list of PROCLOCK objects for this lock. + * waitProcs -- queue of processes waiting for this lock. + * requested -- count of each lock type currently requested on the lock + * (includes requests already granted!!). + * nRequested -- total requested locks of all types. + * granted -- count of each lock type currently granted on the lock. + * nGranted -- total granted locks of all types. + * + * Note: these counts count 1 for each backend. Internally to a backend, + * there may be multiple grabs on a particular lock, but this is not reflected + * into shared memory. + */ +typedef struct LOCK +{ + /* hash key */ + LOCKTAG tag; /* unique identifier of lockable object */ + + /* data */ + LOCKMASK grantMask; /* bitmask for lock types already granted */ + LOCKMASK waitMask; /* bitmask for lock types awaited */ + SHM_QUEUE procLocks; /* list of PROCLOCK objects assoc. with lock */ + PROC_QUEUE waitProcs; /* list of PGPROC objects waiting on lock */ + int requested[MAX_LOCKMODES]; /* counts of requested locks */ + int nRequested; /* total of requested[] array */ + int granted[MAX_LOCKMODES]; /* counts of granted locks */ + int nGranted; /* total of granted[] array */ +} LOCK; + +#define LOCK_LOCKMETHOD(lock) ((LOCKMETHODID) (lock).tag.locktag_lockmethodid) +#define LOCK_LOCKTAG(lock) ((LockTagType) (lock).tag.locktag_type) + + +/* + * We may have several different backends holding or awaiting locks + * on the same lockable object. We need to store some per-holder/waiter + * information for each such holder (or would-be holder). This is kept in + * a PROCLOCK struct. + * + * PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the + * proclock hashtable. A PROCLOCKTAG value uniquely identifies the combination + * of a lockable object and a holder/waiter for that object. (We can use + * pointers here because the PROCLOCKTAG need only be unique for the lifespan + * of the PROCLOCK, and it will never outlive the lock or the proc.) + * + * Internally to a backend, it is possible for the same lock to be held + * for different purposes: the backend tracks transaction locks separately + * from session locks. However, this is not reflected in the shared-memory + * state: we only track which backend(s) hold the lock. This is OK since a + * backend can never block itself. + * + * The holdMask field shows the already-granted locks represented by this + * proclock. Note that there will be a proclock object, possibly with + * zero holdMask, for any lock that the process is currently waiting on. + * Otherwise, proclock objects whose holdMasks are zero are recycled + * as soon as convenient. + * + * releaseMask is workspace for LockReleaseAll(): it shows the locks due + * to be released during the current call. This must only be examined or + * set by the backend owning the PROCLOCK. + * + * Each PROCLOCK object is linked into lists for both the associated LOCK + * object and the owning PGPROC object. Note that the PROCLOCK is entered + * into these lists as soon as it is created, even if no lock has yet been + * granted. A PGPROC that is waiting for a lock to be granted will also be + * linked into the lock's waitProcs queue. + */ +typedef struct PROCLOCKTAG +{ + /* NB: we assume this struct contains no padding! */ + LOCK *myLock; /* link to per-lockable-object information */ + PGPROC *myProc; /* link to PGPROC of owning backend */ +} PROCLOCKTAG; + +typedef struct PROCLOCK +{ + /* tag */ + PROCLOCKTAG tag; /* unique identifier of proclock object */ + + /* data */ + PGPROC *groupLeader; /* proc's lock group leader, or proc itself */ + LOCKMASK holdMask; /* bitmask for lock types currently held */ + LOCKMASK releaseMask; /* bitmask for lock types to be released */ + SHM_QUEUE lockLink; /* list link in LOCK's list of proclocks */ + SHM_QUEUE procLink; /* list link in PGPROC's list of proclocks */ +} PROCLOCK; + +#define PROCLOCK_LOCKMETHOD(proclock) \ + LOCK_LOCKMETHOD(*((proclock).tag.myLock)) + +/* + * Each backend also maintains a local hash table with information about each + * lock it is currently interested in. In particular the local table counts + * the number of times that lock has been acquired. This allows multiple + * requests for the same lock to be executed without additional accesses to + * shared memory. We also track the number of lock acquisitions per + * ResourceOwner, so that we can release just those locks belonging to a + * particular ResourceOwner. + * + * When holding a lock taken "normally", the lock and proclock fields always + * point to the associated objects in shared memory. However, if we acquired + * the lock via the fast-path mechanism, the lock and proclock fields are set + * to NULL, since there probably aren't any such objects in shared memory. + * (If the lock later gets promoted to normal representation, we may eventually + * update our locallock's lock/proclock fields after finding the shared + * objects.) + * + * Caution: a locallock object can be left over from a failed lock acquisition + * attempt. In this case its lock/proclock fields are untrustworthy, since + * the shared lock object is neither held nor awaited, and hence is available + * to be reclaimed. If nLocks > 0 then these pointers must either be valid or + * NULL, but when nLocks == 0 they should be considered garbage. + */ +typedef struct LOCALLOCKTAG +{ + LOCKTAG lock; /* identifies the lockable object */ + LOCKMODE mode; /* lock mode for this table entry */ +} LOCALLOCKTAG; + +typedef struct LOCALLOCKOWNER +{ + /* + * Note: if owner is NULL then the lock is held on behalf of the session; + * otherwise it is held on behalf of my current transaction. + * + * Must use a forward struct reference to avoid circularity. + */ + struct ResourceOwnerData *owner; + int64 nLocks; /* # of times held by this owner */ +} LOCALLOCKOWNER; + +typedef struct LOCALLOCK +{ + /* tag */ + LOCALLOCKTAG tag; /* unique identifier of locallock entry */ + + /* data */ + uint32 hashcode; /* copy of LOCKTAG's hash value */ + LOCK *lock; /* associated LOCK object, if any */ + PROCLOCK *proclock; /* associated PROCLOCK object, if any */ + int64 nLocks; /* total number of times lock is held */ + int numLockOwners; /* # of relevant ResourceOwners */ + int maxLockOwners; /* allocated size of array */ + LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */ + bool holdsStrongLockCount; /* bumped FastPathStrongRelationLocks */ + bool lockCleared; /* we read all sinval msgs for lock */ +} LOCALLOCK; + +#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid) +#define LOCALLOCK_LOCKTAG(llock) ((LockTagType) (llock).tag.lock.locktag_type) + + +/* + * These structures hold information passed from lmgr internals to the lock + * listing user-level functions (in lockfuncs.c). + */ + +typedef struct LockInstanceData +{ + LOCKTAG locktag; /* tag for locked object */ + LOCKMASK holdMask; /* locks held by this PGPROC */ + LOCKMODE waitLockMode; /* lock awaited by this PGPROC, if any */ + BackendId backend; /* backend ID of this PGPROC */ + LocalTransactionId lxid; /* local transaction ID of this PGPROC */ + TimestampTz waitStart; /* time at which this PGPROC started waiting + * for lock */ + int pid; /* pid of this PGPROC */ + int leaderPid; /* pid of group leader; = pid if no group */ + bool fastpath; /* taken via fastpath? */ +} LockInstanceData; + +typedef struct LockData +{ + int nelements; /* The length of the array */ + LockInstanceData *locks; /* Array of per-PROCLOCK information */ +} LockData; + +typedef struct BlockedProcData +{ + int pid; /* pid of a blocked PGPROC */ + /* Per-PROCLOCK information about PROCLOCKs of the lock the pid awaits */ + /* (these fields refer to indexes in BlockedProcsData.locks[]) */ + int first_lock; /* index of first relevant LockInstanceData */ + int num_locks; /* number of relevant LockInstanceDatas */ + /* PIDs of PGPROCs that are ahead of "pid" in the lock's wait queue */ + /* (these fields refer to indexes in BlockedProcsData.waiter_pids[]) */ + int first_waiter; /* index of first preceding waiter */ + int num_waiters; /* number of preceding waiters */ +} BlockedProcData; + +typedef struct BlockedProcsData +{ + BlockedProcData *procs; /* Array of per-blocked-proc information */ + LockInstanceData *locks; /* Array of per-PROCLOCK information */ + int *waiter_pids; /* Array of PIDs of other blocked PGPROCs */ + int nprocs; /* # of valid entries in procs[] array */ + int maxprocs; /* Allocated length of procs[] array */ + int nlocks; /* # of valid entries in locks[] array */ + int maxlocks; /* Allocated length of locks[] array */ + int npids; /* # of valid entries in waiter_pids[] array */ + int maxpids; /* Allocated length of waiter_pids[] array */ +} BlockedProcsData; + + +/* Result codes for LockAcquire() */ +typedef enum +{ + LOCKACQUIRE_NOT_AVAIL, /* lock not available, and dontWait=true */ + LOCKACQUIRE_OK, /* lock successfully acquired */ + LOCKACQUIRE_ALREADY_HELD, /* incremented count for lock already held */ + LOCKACQUIRE_ALREADY_CLEAR /* incremented count for lock already clear */ +} LockAcquireResult; + +/* Deadlock states identified by DeadLockCheck() */ +typedef enum +{ + DS_NOT_YET_CHECKED, /* no deadlock check has run yet */ + DS_NO_DEADLOCK, /* no deadlock detected */ + DS_SOFT_DEADLOCK, /* deadlock avoided by queue rearrangement */ + DS_HARD_DEADLOCK, /* deadlock, no way out but ERROR */ + DS_BLOCKED_BY_AUTOVACUUM /* no deadlock; queue blocked by autovacuum + * worker */ +} DeadLockState; + +/* + * The lockmgr's shared hash tables are partitioned to reduce contention. + * To determine which partition a given locktag belongs to, compute the tag's + * hash code with LockTagHashCode(), then apply one of these macros. + * NB: NUM_LOCK_PARTITIONS must be a power of 2! + */ +#define LockHashPartition(hashcode) \ + ((hashcode) % NUM_LOCK_PARTITIONS) +#define LockHashPartitionLock(hashcode) \ + (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + \ + LockHashPartition(hashcode)].lock) +#define LockHashPartitionLockByIndex(i) \ + (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock) + +/* + * The deadlock detector needs to be able to access lockGroupLeader and + * related fields in the PGPROC, so we arrange for those fields to be protected + * by one of the lock hash partition locks. Since the deadlock detector + * acquires all such locks anyway, this makes it safe for it to access these + * fields without doing anything extra. To avoid contention as much as + * possible, we map different PGPROCs to different partition locks. The lock + * used for a given lock group is determined by the group leader's pgprocno. + */ +#define LockHashPartitionLockByProc(leader_pgproc) \ + LockHashPartitionLock((leader_pgproc)->pgprocno) + +/* + * function prototypes + */ +extern void InitLocks(void); +extern LockMethod GetLocksMethodTable(const LOCK *lock); +extern LockMethod GetLockTagsMethodTable(const LOCKTAG *locktag); +extern uint32 LockTagHashCode(const LOCKTAG *locktag); +extern bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2); +extern LockAcquireResult LockAcquire(const LOCKTAG *locktag, + LOCKMODE lockmode, + bool sessionLock, + bool dontWait); +extern LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag, + LOCKMODE lockmode, + bool sessionLock, + bool dontWait, + bool reportMemoryError, + LOCALLOCK **locallockp); +extern void AbortStrongLockAcquire(void); +extern void MarkLockClear(LOCALLOCK *locallock); +extern bool LockRelease(const LOCKTAG *locktag, + LOCKMODE lockmode, bool sessionLock); +extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks); +extern void LockReleaseSession(LOCKMETHODID lockmethodid); +extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks); +extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks); +extern bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode); +#ifdef USE_ASSERT_CHECKING +extern HTAB *GetLockMethodLocalHash(void); +#endif +extern bool LockHasWaiters(const LOCKTAG *locktag, + LOCKMODE lockmode, bool sessionLock); +extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag, + LOCKMODE lockmode, int *countp); +extern void AtPrepare_Locks(void); +extern void PostPrepare_Locks(TransactionId xid); +extern bool LockCheckConflicts(LockMethod lockMethodTable, + LOCKMODE lockmode, + LOCK *lock, PROCLOCK *proclock); +extern void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode); +extern void GrantAwaitedLock(void); +extern void RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode); +extern Size LockShmemSize(void); +extern LockData *GetLockStatusData(void); +extern BlockedProcsData *GetBlockerStatusData(int blocked_pid); + +extern xl_standby_lock *GetRunningTransactionLocks(int *nlocks); +extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode); + +extern void lock_twophase_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void lock_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void lock_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void lock_twophase_standby_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len); + +extern DeadLockState DeadLockCheck(PGPROC *proc); +extern PGPROC *GetBlockingAutoVacuumPgproc(void); +extern void DeadLockReport(void) pg_attribute_noreturn(); +extern void RememberSimpleDeadLock(PGPROC *proc1, + LOCKMODE lockmode, + LOCK *lock, + PGPROC *proc2); +extern void InitDeadLockChecking(void); + +extern int LockWaiterCount(const LOCKTAG *locktag); + +#ifdef LOCK_DEBUG +extern void DumpLocks(PGPROC *proc); +extern void DumpAllLocks(void); +#endif + +/* Lock a VXID (used to wait for a transaction to finish) */ +extern void VirtualXactLockTableInsert(VirtualTransactionId vxid); +extern void VirtualXactLockTableCleanup(void); +extern bool VirtualXactLock(VirtualTransactionId vxid, bool wait); + +#endif /* LOCK_H_ */ diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h new file mode 100644 index 0000000..350ddd4 --- /dev/null +++ b/src/include/storage/lockdefs.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- + * + * lockdefs.h + * Frontend exposed parts of postgres' low level lock mechanism + * + * The split between lockdefs.h and lock.h is not very principled. This file + * contains definition that have to (indirectly) be available when included by + * FRONTEND code. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/lockdefs.h + * + *------------------------------------------------------------------------- + */ +#ifndef LOCKDEFS_H_ +#define LOCKDEFS_H_ + +/* + * LOCKMODE is an integer (1..N) indicating a lock type. LOCKMASK is a bit + * mask indicating a set of held or requested lock types (the bit 1<<mode + * corresponds to a particular lock mode). + */ +typedef int LOCKMASK; +typedef int LOCKMODE; + +/* + * These are the valid values of type LOCKMODE for all the standard lock + * methods (both DEFAULT and USER). + */ + +/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */ +#define NoLock 0 + +#define AccessShareLock 1 /* SELECT */ +#define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */ +#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */ +#define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL),ANALYZE, CREATE INDEX + * CONCURRENTLY */ +#define ShareLock 5 /* CREATE INDEX (WITHOUT CONCURRENTLY) */ +#define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW + * SHARE */ +#define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR UPDATE */ +#define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM FULL, + * and unqualified LOCK TABLE */ + +#define MaxLockMode 8 /* highest standard lock mode */ + + +/* WAL representation of an AccessExclusiveLock on a table */ +typedef struct xl_standby_lock +{ + TransactionId xid; /* xid of holder of AccessExclusiveLock */ + Oid dbOid; /* DB containing table */ + Oid relOid; /* OID of table */ +} xl_standby_lock; + +#endif /* LOCKDEFS_H_ */ diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h new file mode 100644 index 0000000..e03d317 --- /dev/null +++ b/src/include/storage/lwlock.h @@ -0,0 +1,206 @@ +/*------------------------------------------------------------------------- + * + * lwlock.h + * Lightweight lock manager + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/lwlock.h + * + *------------------------------------------------------------------------- + */ +#ifndef LWLOCK_H +#define LWLOCK_H + +#ifdef FRONTEND +#error "lwlock.h may not be included from frontend code" +#endif + +#include "port/atomics.h" +#include "storage/proclist_types.h" + +struct PGPROC; + +/* + * Code outside of lwlock.c should not manipulate the contents of this + * structure directly, but we have to declare it here to allow LWLocks to be + * incorporated into other data structures. + */ +typedef struct LWLock +{ + uint16 tranche; /* tranche ID */ + pg_atomic_uint32 state; /* state of exclusive/nonexclusive lockers */ + proclist_head waiters; /* list of waiting PGPROCs */ +#ifdef LOCK_DEBUG + pg_atomic_uint32 nwaiters; /* number of waiters */ + struct PGPROC *owner; /* last exclusive owner of the lock */ +#endif +} LWLock; + +/* + * In most cases, it's desirable to force each tranche of LWLocks to be aligned + * on a cache line boundary and make the array stride a power of 2. This saves + * a few cycles in indexing, but more importantly ensures that individual + * LWLocks don't cross cache line boundaries. This reduces cache contention + * problems, especially on AMD Opterons. In some cases, it's useful to add + * even more padding so that each LWLock takes up an entire cache line; this is + * useful, for example, in the main LWLock array, where the overall number of + * locks is small but some are heavily contended. + */ +#define LWLOCK_PADDED_SIZE PG_CACHE_LINE_SIZE + +/* LWLock, padded to a full cache line size */ +typedef union LWLockPadded +{ + LWLock lock; + char pad[LWLOCK_PADDED_SIZE]; +} LWLockPadded; + +extern PGDLLIMPORT LWLockPadded *MainLWLockArray; + +/* struct for storing named tranche information */ +typedef struct NamedLWLockTranche +{ + int trancheId; + char *trancheName; +} NamedLWLockTranche; + +extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheArray; +extern PGDLLIMPORT int NamedLWLockTrancheRequests; + +/* Names for fixed lwlocks */ +#include "storage/lwlocknames.h" + +/* + * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS + * here, but we need them to figure out offsets within MainLWLockArray, and + * having this file include lock.h or bufmgr.h would be backwards. + */ + +/* Number of partitions of the shared buffer mapping hashtable */ +#define NUM_BUFFER_PARTITIONS 128 + +/* Number of partitions the shared lock tables are divided into */ +#define LOG2_NUM_LOCK_PARTITIONS 4 +#define NUM_LOCK_PARTITIONS (1 << LOG2_NUM_LOCK_PARTITIONS) + +/* Number of partitions the shared predicate lock tables are divided into */ +#define LOG2_NUM_PREDICATELOCK_PARTITIONS 4 +#define NUM_PREDICATELOCK_PARTITIONS (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS) + +/* Offsets for various chunks of preallocated lwlocks. */ +#define BUFFER_MAPPING_LWLOCK_OFFSET NUM_INDIVIDUAL_LWLOCKS +#define LOCK_MANAGER_LWLOCK_OFFSET \ + (BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS) +#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET \ + (LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS) +#define NUM_FIXED_LWLOCKS \ + (PREDICATELOCK_MANAGER_LWLOCK_OFFSET + NUM_PREDICATELOCK_PARTITIONS) + +typedef enum LWLockMode +{ + LW_EXCLUSIVE, + LW_SHARED, + LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwWaitMode, + * when waiting for lock to become free. Not + * to be used as LWLockAcquire argument */ +} LWLockMode; + + +#ifdef LOCK_DEBUG +extern PGDLLIMPORT bool Trace_lwlocks; +#endif + +extern bool LWLockAcquire(LWLock *lock, LWLockMode mode); +extern bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode); +extern bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode); +extern void LWLockRelease(LWLock *lock); +extern void LWLockReleaseClearVar(LWLock *lock, uint64 *valptr, uint64 val); +extern void LWLockReleaseAll(void); +extern bool LWLockHeldByMe(LWLock *lock); +extern bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride); +extern bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode); + +extern bool LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval); +extern void LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 value); + +extern Size LWLockShmemSize(void); +extern void CreateLWLocks(void); +extern void InitLWLockAccess(void); + +extern const char *GetLWLockIdentifier(uint32 classId, uint16 eventId); + +/* + * Extensions (or core code) can obtain an LWLocks by calling + * RequestNamedLWLockTranche() during postmaster startup. Subsequently, + * call GetNamedLWLockTranche() to obtain a pointer to an array containing + * the number of LWLocks requested. + */ +extern void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks); +extern LWLockPadded *GetNamedLWLockTranche(const char *tranche_name); + +/* + * There is another, more flexible method of obtaining lwlocks. First, call + * LWLockNewTrancheId just once to obtain a tranche ID; this allocates from + * a shared counter. Next, each individual process using the tranche should + * call LWLockRegisterTranche() to associate that tranche ID with a name. + * Finally, LWLockInitialize should be called just once per lwlock, passing + * the tranche ID as an argument. + * + * It may seem strange that each process using the tranche must register it + * separately, but dynamic shared memory segments aren't guaranteed to be + * mapped at the same address in all coordinating backends, so storing the + * registration in the main shared memory segment wouldn't work for that case. + */ +extern int LWLockNewTrancheId(void); +extern void LWLockRegisterTranche(int tranche_id, const char *tranche_name); +extern void LWLockInitialize(LWLock *lock, int tranche_id); + +/* + * Every tranche ID less than NUM_INDIVIDUAL_LWLOCKS is reserved; also, + * we reserve additional tranche IDs for builtin tranches not included in + * the set of individual LWLocks. A call to LWLockNewTrancheId will never + * return a value less than LWTRANCHE_FIRST_USER_DEFINED. + */ +typedef enum BuiltinTrancheIds +{ + LWTRANCHE_XACT_BUFFER = NUM_INDIVIDUAL_LWLOCKS, + LWTRANCHE_COMMITTS_BUFFER, + LWTRANCHE_SUBTRANS_BUFFER, + LWTRANCHE_MULTIXACTOFFSET_BUFFER, + LWTRANCHE_MULTIXACTMEMBER_BUFFER, + LWTRANCHE_NOTIFY_BUFFER, + LWTRANCHE_SERIAL_BUFFER, + LWTRANCHE_WAL_INSERT, + LWTRANCHE_BUFFER_CONTENT, + LWTRANCHE_REPLICATION_ORIGIN_STATE, + LWTRANCHE_REPLICATION_SLOT_IO, + LWTRANCHE_LOCK_FASTPATH, + LWTRANCHE_BUFFER_MAPPING, + LWTRANCHE_LOCK_MANAGER, + LWTRANCHE_PREDICATE_LOCK_MANAGER, + LWTRANCHE_PARALLEL_HASH_JOIN, + LWTRANCHE_PARALLEL_QUERY_DSA, + LWTRANCHE_PER_SESSION_DSA, + LWTRANCHE_PER_SESSION_RECORD_TYPE, + LWTRANCHE_PER_SESSION_RECORD_TYPMOD, + LWTRANCHE_SHARED_TUPLESTORE, + LWTRANCHE_SHARED_TIDBITMAP, + LWTRANCHE_PARALLEL_APPEND, + LWTRANCHE_PER_XACT_PREDICATE_LIST, + LWTRANCHE_PGSTATS_DSA, + LWTRANCHE_PGSTATS_HASH, + LWTRANCHE_PGSTATS_DATA, + LWTRANCHE_FIRST_USER_DEFINED +} BuiltinTrancheIds; + +/* + * Prior to PostgreSQL 9.4, we used an enum type called LWLockId to refer + * to LWLocks. New code should instead use LWLock *. However, for the + * convenience of third-party code, we include the following typedef. + */ +typedef LWLock *LWLockId; + +#endif /* LWLOCK_H */ diff --git a/src/include/storage/md.h b/src/include/storage/md.h new file mode 100644 index 0000000..ffffa40 --- /dev/null +++ b/src/include/storage/md.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * md.h + * magnetic disk storage manager public interface declarations. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/md.h + * + *------------------------------------------------------------------------- + */ +#ifndef MD_H +#define MD_H + +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "storage/smgr.h" +#include "storage/sync.h" + +/* md storage manager functionality */ +extern void mdinit(void); +extern void mdopen(SMgrRelation reln); +extern void mdclose(SMgrRelation reln, ForkNumber forknum); +extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); +extern bool mdexists(SMgrRelation reln, ForkNumber forknum); +extern void mdunlink(RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo); +extern void mdextend(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer, bool skipFsync); +extern bool mdprefetch(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum); +extern void mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, + char *buffer); +extern void mdwrite(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer, bool skipFsync); +extern void mdwriteback(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, BlockNumber nblocks); +extern BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum); +extern void mdtruncate(SMgrRelation reln, ForkNumber forknum, + BlockNumber nblocks); +extern void mdimmedsync(SMgrRelation reln, ForkNumber forknum); + +extern void ForgetDatabaseSyncRequests(Oid dbid); +extern void DropRelationFiles(RelFileNode *delrels, int ndelrels, bool isRedo); + +/* md sync callbacks */ +extern int mdsyncfiletag(const FileTag *ftag, char *path); +extern int mdunlinkfiletag(const FileTag *ftag, char *path); +extern bool mdfiletagmatches(const FileTag *ftag, const FileTag *candidate); + +#endif /* MD_H */ diff --git a/src/include/storage/off.h b/src/include/storage/off.h new file mode 100644 index 0000000..e6573ac --- /dev/null +++ b/src/include/storage/off.h @@ -0,0 +1,57 @@ +/*------------------------------------------------------------------------- + * + * off.h + * POSTGRES disk "offset" definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/off.h + * + *------------------------------------------------------------------------- + */ +#ifndef OFF_H +#define OFF_H + +#include "storage/itemid.h" +/* + * OffsetNumber: + * + * this is a 1-based index into the linp (ItemIdData) array in the + * header of each disk page. + */ +typedef uint16 OffsetNumber; + +#define InvalidOffsetNumber ((OffsetNumber) 0) +#define FirstOffsetNumber ((OffsetNumber) 1) +#define MaxOffsetNumber ((OffsetNumber) (BLCKSZ / sizeof(ItemIdData))) + +/* ---------------- + * support macros + * ---------------- + */ + +/* + * OffsetNumberIsValid + * True iff the offset number is valid. + */ +#define OffsetNumberIsValid(offsetNumber) \ + ((bool) ((offsetNumber != InvalidOffsetNumber) && \ + (offsetNumber <= MaxOffsetNumber))) + +/* + * OffsetNumberNext + * OffsetNumberPrev + * Increments/decrements the argument. These macros look pointless + * but they help us disambiguate the different manipulations on + * OffsetNumbers (e.g., sometimes we subtract one from an + * OffsetNumber to move back, and sometimes we do so to form a + * real C array index). + */ +#define OffsetNumberNext(offsetNumber) \ + ((OffsetNumber) (1 + (offsetNumber))) +#define OffsetNumberPrev(offsetNumber) \ + ((OffsetNumber) (-1 + (offsetNumber))) + +#endif /* OFF_H */ diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h new file mode 100644 index 0000000..5ca941a --- /dev/null +++ b/src/include/storage/pg_sema.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * pg_sema.h + * Platform-independent API for semaphores. + * + * PostgreSQL requires counting semaphores (the kind that keep track of + * multiple unlock operations, and will allow an equal number of subsequent + * lock operations before blocking). The underlying implementation is + * not the same on every platform. This file defines the API that must + * be provided by each port. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/pg_sema.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SEMA_H +#define PG_SEMA_H + +/* + * struct PGSemaphoreData and pointer type PGSemaphore are the data structure + * representing an individual semaphore. The contents of PGSemaphoreData vary + * across implementations and must never be touched by platform-independent + * code; hence, PGSemaphoreData is declared as an opaque struct here. + * + * However, Windows is sufficiently unlike our other ports that it doesn't + * seem worth insisting on ABI compatibility for Windows too. Hence, on + * that platform just define PGSemaphore as HANDLE. + */ +#ifndef USE_WIN32_SEMAPHORES +typedef struct PGSemaphoreData *PGSemaphore; +#else +typedef HANDLE PGSemaphore; +#endif + + +/* Report amount of shared memory needed */ +extern Size PGSemaphoreShmemSize(int maxSemas); + +/* Module initialization (called during postmaster start or shmem reinit) */ +extern void PGReserveSemaphores(int maxSemas); + +/* Allocate a PGSemaphore structure with initial count 1 */ +extern PGSemaphore PGSemaphoreCreate(void); + +/* Reset a previously-initialized PGSemaphore to have count 0 */ +extern void PGSemaphoreReset(PGSemaphore sema); + +/* Lock a semaphore (decrement count), blocking if count would be < 0 */ +extern void PGSemaphoreLock(PGSemaphore sema); + +/* Unlock a semaphore (increment count) */ +extern void PGSemaphoreUnlock(PGSemaphore sema); + +/* Lock a semaphore only if able to do so without blocking */ +extern bool PGSemaphoreTryLock(PGSemaphore sema); + +#endif /* PG_SEMA_H */ diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h new file mode 100644 index 0000000..da5962e --- /dev/null +++ b/src/include/storage/pg_shmem.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- + * + * pg_shmem.h + * Platform-independent API for shared memory support. + * + * Every port is expected to support shared memory with approximately + * SysV-ish semantics; in particular, a memory block is not anonymous + * but has an ID, and we must be able to tell whether there are any + * remaining processes attached to a block of a specified ID. + * + * To simplify life for the SysV implementation, the ID is assumed to + * consist of two unsigned long values (these are key and ID in SysV + * terms). Other platforms may ignore the second value if they need + * only one ID number. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/pg_shmem.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_SHMEM_H +#define PG_SHMEM_H + +#include "storage/dsm_impl.h" + +typedef struct PGShmemHeader /* standard header for all Postgres shmem */ +{ + int32 magic; /* magic # to identify Postgres segments */ +#define PGShmemMagic 679834894 + pid_t creatorPID; /* PID of creating process (set but unread) */ + Size totalsize; /* total size of segment */ + Size freeoffset; /* offset to first free space */ + dsm_handle dsm_control; /* ID of dynamic shared memory control seg */ + void *index; /* pointer to ShmemIndex table */ +#ifndef WIN32 /* Windows doesn't have useful inode#s */ + dev_t device; /* device data directory is on */ + ino_t inode; /* inode number of data directory */ +#endif +} PGShmemHeader; + +/* GUC variables */ +extern PGDLLIMPORT int shared_memory_type; +extern PGDLLIMPORT int huge_pages; +extern PGDLLIMPORT int huge_page_size; + +/* Possible values for huge_pages */ +typedef enum +{ + HUGE_PAGES_OFF, + HUGE_PAGES_ON, + HUGE_PAGES_TRY +} HugePagesType; + +/* Possible values for shared_memory_type */ +typedef enum +{ + SHMEM_TYPE_WINDOWS, + SHMEM_TYPE_SYSV, + SHMEM_TYPE_MMAP +} PGShmemType; + +#ifndef WIN32 +extern PGDLLIMPORT unsigned long UsedShmemSegID; +#else +extern PGDLLIMPORT HANDLE UsedShmemSegID; +extern PGDLLIMPORT void *ShmemProtectiveRegion; +#endif +extern PGDLLIMPORT void *UsedShmemSegAddr; + +#if !defined(WIN32) && !defined(EXEC_BACKEND) +#define DEFAULT_SHARED_MEMORY_TYPE SHMEM_TYPE_MMAP +#elif !defined(WIN32) +#define DEFAULT_SHARED_MEMORY_TYPE SHMEM_TYPE_SYSV +#else +#define DEFAULT_SHARED_MEMORY_TYPE SHMEM_TYPE_WINDOWS +#endif + +#ifdef EXEC_BACKEND +extern void PGSharedMemoryReAttach(void); +extern void PGSharedMemoryNoReAttach(void); +#endif + +extern PGShmemHeader *PGSharedMemoryCreate(Size size, + PGShmemHeader **shim); +extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); +extern void PGSharedMemoryDetach(void); +extern void GetHugePageSize(Size *hugepagesize, int *mmap_flags); + +#endif /* PG_SHMEM_H */ diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h new file mode 100644 index 0000000..58f4ddf --- /dev/null +++ b/src/include/storage/pmsignal.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------- + * + * pmsignal.h + * routines for signaling between the postmaster and its child processes + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/pmsignal.h + * + *------------------------------------------------------------------------- + */ +#ifndef PMSIGNAL_H +#define PMSIGNAL_H + +#include <signal.h> + +#ifdef HAVE_SYS_PRCTL_H +#include "sys/prctl.h" +#endif + +#ifdef HAVE_SYS_PROCCTL_H +#include "sys/procctl.h" +#endif + +/* + * Reasons for signaling the postmaster. We can cope with simultaneous + * signals for different reasons. If the same reason is signaled multiple + * times in quick succession, however, the postmaster is likely to observe + * only one notification of it. This is okay for the present uses. + */ +typedef enum +{ + PMSIGNAL_RECOVERY_STARTED, /* recovery has started */ + PMSIGNAL_BEGIN_HOT_STANDBY, /* begin Hot Standby */ + PMSIGNAL_ROTATE_LOGFILE, /* send SIGUSR1 to syslogger to rotate logfile */ + PMSIGNAL_START_AUTOVAC_LAUNCHER, /* start an autovacuum launcher */ + PMSIGNAL_START_AUTOVAC_WORKER, /* start an autovacuum worker */ + PMSIGNAL_BACKGROUND_WORKER_CHANGE, /* background worker state change */ + PMSIGNAL_START_WALRECEIVER, /* start a walreceiver */ + PMSIGNAL_ADVANCE_STATE_MACHINE, /* advance postmaster's state machine */ + + NUM_PMSIGNALS /* Must be last value of enum! */ +} PMSignalReason; + +/* + * Reasons why the postmaster would send SIGQUIT to its children. + */ +typedef enum +{ + PMQUIT_NOT_SENT = 0, /* postmaster hasn't sent SIGQUIT */ + PMQUIT_FOR_CRASH, /* some other backend bought the farm */ + PMQUIT_FOR_STOP /* immediate stop was commanded */ +} QuitSignalReason; + +/* PMSignalData is an opaque struct, details known only within pmsignal.c */ +typedef struct PMSignalData PMSignalData; + +/* + * prototypes for functions in pmsignal.c + */ +extern Size PMSignalShmemSize(void); +extern void PMSignalShmemInit(void); +extern void SendPostmasterSignal(PMSignalReason reason); +extern bool CheckPostmasterSignal(PMSignalReason reason); +extern void SetQuitSignalReason(QuitSignalReason reason); +extern QuitSignalReason GetQuitSignalReason(void); +extern int AssignPostmasterChildSlot(void); +extern bool ReleasePostmasterChildSlot(int slot); +extern bool IsPostmasterChildWalSender(int slot); +extern void MarkPostmasterChildActive(void); +extern void MarkPostmasterChildInactive(void); +extern void MarkPostmasterChildWalSender(void); +extern bool PostmasterIsAliveInternal(void); +extern void PostmasterDeathSignalInit(void); + + +/* + * Do we have a way to ask for a signal on parent death? + * + * If we do, pmsignal.c will set up a signal handler, that sets a flag when + * the parent dies. Checking the flag first makes PostmasterIsAlive() a lot + * cheaper in usual case that the postmaster is alive. + */ +#if (defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_PDEATHSIG)) || \ + (defined(HAVE_SYS_PROCCTL_H) && defined(PROC_PDEATHSIG_CTL)) +#define USE_POSTMASTER_DEATH_SIGNAL +#endif + +#ifdef USE_POSTMASTER_DEATH_SIGNAL +extern PGDLLIMPORT volatile sig_atomic_t postmaster_possibly_dead; + +static inline bool +PostmasterIsAlive(void) +{ + if (likely(!postmaster_possibly_dead)) + return true; + return PostmasterIsAliveInternal(); +} +#else +#define PostmasterIsAlive() PostmasterIsAliveInternal() +#endif + +#endif /* PMSIGNAL_H */ diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h new file mode 100644 index 0000000..8dfcb39 --- /dev/null +++ b/src/include/storage/predicate.h @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------- + * + * predicate.h + * POSTGRES public predicate locking definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/predicate.h + * + *------------------------------------------------------------------------- + */ +#ifndef PREDICATE_H +#define PREDICATE_H + +#include "storage/lock.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + + +/* + * GUC variables + */ +extern PGDLLIMPORT int max_predicate_locks_per_xact; +extern PGDLLIMPORT int max_predicate_locks_per_relation; +extern PGDLLIMPORT int max_predicate_locks_per_page; + + +/* Number of SLRU buffers to use for Serial SLRU */ +#define NUM_SERIAL_BUFFERS 16 + +/* + * A handle used for sharing SERIALIZABLEXACT objects between the participants + * in a parallel query. + */ +typedef void *SerializableXactHandle; + +/* + * function prototypes + */ + +/* housekeeping for shared memory predicate lock structures */ +extern void InitPredicateLocks(void); +extern Size PredicateLockShmemSize(void); + +extern void CheckPointPredicate(void); + +/* predicate lock reporting */ +extern bool PageIsPredicateLocked(Relation relation, BlockNumber blkno); + +/* predicate lock maintenance */ +extern Snapshot GetSerializableTransactionSnapshot(Snapshot snapshot); +extern void SetSerializableTransactionSnapshot(Snapshot snapshot, + VirtualTransactionId *sourcevxid, + int sourcepid); +extern void RegisterPredicateLockingXid(TransactionId xid); +extern void PredicateLockRelation(Relation relation, Snapshot snapshot); +extern void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot); +extern void PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot, + TransactionId insert_xid); +extern void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno); +extern void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno); +extern void TransferPredicateLocksToHeapRelation(Relation relation); +extern void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe); + +/* conflict detection (may also trigger rollback) */ +extern bool CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot); +extern void CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot); +extern void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno); +extern void CheckTableForSerializableConflictIn(Relation relation); + +/* final rollback checking */ +extern void PreCommit_CheckForSerializationFailure(void); + +/* two-phase commit support */ +extern void AtPrepare_PredicateLocks(void); +extern void PostPrepare_PredicateLocks(TransactionId xid); +extern void PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit); +extern void predicatelock_twophase_recover(TransactionId xid, uint16 info, + void *recdata, uint32 len); + +/* parallel query support */ +extern SerializableXactHandle ShareSerializableXact(void); +extern void AttachSerializableXact(SerializableXactHandle handle); + +#endif /* PREDICATE_H */ diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h new file mode 100644 index 0000000..2416d3c --- /dev/null +++ b/src/include/storage/predicate_internals.h @@ -0,0 +1,494 @@ +/*------------------------------------------------------------------------- + * + * predicate_internals.h + * POSTGRES internal predicate locking definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/predicate_internals.h + * + *------------------------------------------------------------------------- + */ +#ifndef PREDICATE_INTERNALS_H +#define PREDICATE_INTERNALS_H + +#include "storage/lock.h" +#include "storage/lwlock.h" + +/* + * Commit number. + */ +typedef uint64 SerCommitSeqNo; + +/* + * Reserved commit sequence numbers: + * - 0 is reserved to indicate a non-existent SLRU entry; it cannot be + * used as a SerCommitSeqNo, even an invalid one + * - InvalidSerCommitSeqNo is used to indicate a transaction that + * hasn't committed yet, so use a number greater than all valid + * ones to make comparison do the expected thing + * - RecoverySerCommitSeqNo is used to refer to transactions that + * happened before a crash/recovery, since we restart the sequence + * at that point. It's earlier than all normal sequence numbers, + * and is only used by recovered prepared transactions + */ +#define InvalidSerCommitSeqNo ((SerCommitSeqNo) PG_UINT64_MAX) +#define RecoverySerCommitSeqNo ((SerCommitSeqNo) 1) +#define FirstNormalSerCommitSeqNo ((SerCommitSeqNo) 2) + +/* + * The SERIALIZABLEXACT struct contains information needed for each + * serializable database transaction to support SSI techniques. + * + * A home-grown list is maintained in shared memory to manage these. + * An entry is used when the serializable transaction acquires a snapshot. + * Unless the transaction is rolled back, this entry must generally remain + * until all concurrent transactions have completed. (There are special + * optimizations for READ ONLY transactions which often allow them to be + * cleaned up earlier.) A transaction which is rolled back is cleaned up + * as soon as possible. + * + * Eligibility for cleanup of committed transactions is generally determined + * by comparing the transaction's finishedBefore field to + * SxactGlobalXmin. + */ +typedef struct SERIALIZABLEXACT +{ + VirtualTransactionId vxid; /* The executing process always has one of + * these. */ + + /* + * We use two numbers to track the order that transactions commit. Before + * commit, a transaction is marked as prepared, and prepareSeqNo is set. + * Shortly after commit, it's marked as committed, and commitSeqNo is set. + * This doesn't give a strict commit order, but these two values together + * are good enough for us, as we can always err on the safe side and + * assume that there's a conflict, if we can't be sure of the exact + * ordering of two commits. + * + * Note that a transaction is marked as prepared for a short period during + * commit processing, even if two-phase commit is not used. But with + * two-phase commit, a transaction can stay in prepared state for some + * time. + */ + SerCommitSeqNo prepareSeqNo; + SerCommitSeqNo commitSeqNo; + + /* these values are not both interesting at the same time */ + union + { + SerCommitSeqNo earliestOutConflictCommit; /* when committed with + * conflict out */ + SerCommitSeqNo lastCommitBeforeSnapshot; /* when not committed or + * no conflict out */ + } SeqNo; + SHM_QUEUE outConflicts; /* list of write transactions whose data we + * couldn't read. */ + SHM_QUEUE inConflicts; /* list of read transactions which couldn't + * see our write. */ + SHM_QUEUE predicateLocks; /* list of associated PREDICATELOCK objects */ + SHM_QUEUE finishedLink; /* list link in + * FinishedSerializableTransactions */ + + /* + * perXactPredicateListLock is only used in parallel queries: it protects + * this SERIALIZABLEXACT's predicate lock list against other workers of + * the same session. + */ + LWLock perXactPredicateListLock; + + /* + * for r/o transactions: list of concurrent r/w transactions that we could + * potentially have conflicts with, and vice versa for r/w transactions + */ + SHM_QUEUE possibleUnsafeConflicts; + + TransactionId topXid; /* top level xid for the transaction, if one + * exists; else invalid */ + TransactionId finishedBefore; /* invalid means still running; else the + * struct expires when no serializable + * xids are before this. */ + TransactionId xmin; /* the transaction's snapshot xmin */ + uint32 flags; /* OR'd combination of values defined below */ + int pid; /* pid of associated process */ + int pgprocno; /* pgprocno of associated process */ +} SERIALIZABLEXACT; + +#define SXACT_FLAG_COMMITTED 0x00000001 /* already committed */ +#define SXACT_FLAG_PREPARED 0x00000002 /* about to commit */ +#define SXACT_FLAG_ROLLED_BACK 0x00000004 /* already rolled back */ +#define SXACT_FLAG_DOOMED 0x00000008 /* will roll back */ +/* + * The following flag actually means that the flagged transaction has a + * conflict out *to a transaction which committed ahead of it*. It's hard + * to get that into a name of a reasonable length. + */ +#define SXACT_FLAG_CONFLICT_OUT 0x00000010 +#define SXACT_FLAG_READ_ONLY 0x00000020 +#define SXACT_FLAG_DEFERRABLE_WAITING 0x00000040 +#define SXACT_FLAG_RO_SAFE 0x00000080 +#define SXACT_FLAG_RO_UNSAFE 0x00000100 +#define SXACT_FLAG_SUMMARY_CONFLICT_IN 0x00000200 +#define SXACT_FLAG_SUMMARY_CONFLICT_OUT 0x00000400 +/* + * The following flag means the transaction has been partially released + * already, but is being preserved because parallel workers might have a + * reference to it. It'll be recycled by the leader at end-of-transaction. + */ +#define SXACT_FLAG_PARTIALLY_RELEASED 0x00000800 + +/* + * The following types are used to provide an ad hoc list for holding + * SERIALIZABLEXACT objects. An HTAB is overkill, since there is no need to + * access these by key -- there are direct pointers to these objects where + * needed. If a shared memory list is created, these types can probably be + * eliminated in favor of using the general solution. + */ +typedef struct PredXactListElementData +{ + SHM_QUEUE link; + SERIALIZABLEXACT sxact; +} PredXactListElementData; + +typedef struct PredXactListElementData *PredXactListElement; + +#define PredXactListElementDataSize \ + ((Size)MAXALIGN(sizeof(PredXactListElementData))) + +typedef struct PredXactListData +{ + SHM_QUEUE availableList; + SHM_QUEUE activeList; + + /* + * These global variables are maintained when registering and cleaning up + * serializable transactions. They must be global across all backends, + * but are not needed outside the predicate.c source file. Protected by + * SerializableXactHashLock. + */ + TransactionId SxactGlobalXmin; /* global xmin for active serializable + * transactions */ + int SxactGlobalXminCount; /* how many active serializable + * transactions have this xmin */ + int WritableSxactCount; /* how many non-read-only serializable + * transactions are active */ + SerCommitSeqNo LastSxactCommitSeqNo; /* a strictly monotonically + * increasing number for commits + * of serializable transactions */ + /* Protected by SerializableXactHashLock. */ + SerCommitSeqNo CanPartialClearThrough; /* can clear predicate locks and + * inConflicts for committed + * transactions through this seq + * no */ + /* Protected by SerializableFinishedListLock. */ + SerCommitSeqNo HavePartialClearedThrough; /* have cleared through this + * seq no */ + SERIALIZABLEXACT *OldCommittedSxact; /* shared copy of dummy sxact */ + + PredXactListElement element; +} PredXactListData; + +typedef struct PredXactListData *PredXactList; + +#define PredXactListDataSize \ + ((Size)MAXALIGN(sizeof(PredXactListData))) + + +/* + * The following types are used to provide lists of rw-conflicts between + * pairs of transactions. Since exactly the same information is needed, + * they are also used to record possible unsafe transaction relationships + * for purposes of identifying safe snapshots for read-only transactions. + * + * When a RWConflictData is not in use to record either type of relationship + * between a pair of transactions, it is kept on an "available" list. The + * outLink field is used for maintaining that list. + */ +typedef struct RWConflictData +{ + SHM_QUEUE outLink; /* link for list of conflicts out from a sxact */ + SHM_QUEUE inLink; /* link for list of conflicts in to a sxact */ + SERIALIZABLEXACT *sxactOut; + SERIALIZABLEXACT *sxactIn; +} RWConflictData; + +typedef struct RWConflictData *RWConflict; + +#define RWConflictDataSize \ + ((Size)MAXALIGN(sizeof(RWConflictData))) + +typedef struct RWConflictPoolHeaderData +{ + SHM_QUEUE availableList; + RWConflict element; +} RWConflictPoolHeaderData; + +typedef struct RWConflictPoolHeaderData *RWConflictPoolHeader; + +#define RWConflictPoolHeaderDataSize \ + ((Size)MAXALIGN(sizeof(RWConflictPoolHeaderData))) + + +/* + * The SERIALIZABLEXIDTAG struct identifies an xid assigned to a serializable + * transaction or any of its subtransactions. + */ +typedef struct SERIALIZABLEXIDTAG +{ + TransactionId xid; +} SERIALIZABLEXIDTAG; + +/* + * The SERIALIZABLEXID struct provides a link from a TransactionId for a + * serializable transaction to the related SERIALIZABLEXACT record, even if + * the transaction has completed and its connection has been closed. + * + * These are created as new top level transaction IDs are first assigned to + * transactions which are participating in predicate locking. This may + * never happen for a particular transaction if it doesn't write anything. + * They are removed with their related serializable transaction objects. + * + * The SubTransGetTopmostTransaction method is used where necessary to get + * from an XID which might be from a subtransaction to the top level XID. + */ +typedef struct SERIALIZABLEXID +{ + /* hash key */ + SERIALIZABLEXIDTAG tag; + + /* data */ + SERIALIZABLEXACT *myXact; /* pointer to the top level transaction data */ +} SERIALIZABLEXID; + + +/* + * The PREDICATELOCKTARGETTAG struct identifies a database object which can + * be the target of predicate locks. + * + * Note that the hash function being used doesn't properly respect tag + * length -- if the length of the structure isn't a multiple of four bytes it + * will go to a four byte boundary past the end of the tag. If you change + * this struct, make sure any slack space is initialized, so that any random + * bytes in the middle or at the end are not included in the hash. + * + * TODO SSI: If we always use the same fields for the same type of value, we + * should rename these. Holding off until it's clear there are no exceptions. + * Since indexes are relations with blocks and tuples, it's looking likely that + * the rename will be possible. If not, we may need to divide the last field + * and use part of it for a target type, so that we know how to interpret the + * data.. + */ +typedef struct PREDICATELOCKTARGETTAG +{ + uint32 locktag_field1; /* a 32-bit ID field */ + uint32 locktag_field2; /* a 32-bit ID field */ + uint32 locktag_field3; /* a 32-bit ID field */ + uint32 locktag_field4; /* a 32-bit ID field */ +} PREDICATELOCKTARGETTAG; + +/* + * The PREDICATELOCKTARGET struct represents a database object on which there + * are predicate locks. + * + * A hash list of these objects is maintained in shared memory. An entry is + * added when a predicate lock is requested on an object which doesn't + * already have one. An entry is removed when the last lock is removed from + * its list. + */ +typedef struct PREDICATELOCKTARGET +{ + /* hash key */ + PREDICATELOCKTARGETTAG tag; /* unique identifier of lockable object */ + + /* data */ + SHM_QUEUE predicateLocks; /* list of PREDICATELOCK objects assoc. with + * predicate lock target */ +} PREDICATELOCKTARGET; + + +/* + * The PREDICATELOCKTAG struct identifies an individual predicate lock. + * + * It is the combination of predicate lock target (which is a lockable + * object) and a serializable transaction which has acquired a lock on that + * target. + */ +typedef struct PREDICATELOCKTAG +{ + PREDICATELOCKTARGET *myTarget; + SERIALIZABLEXACT *myXact; +} PREDICATELOCKTAG; + +/* + * The PREDICATELOCK struct represents an individual lock. + * + * An entry can be created here when the related database object is read, or + * by promotion of multiple finer-grained targets. All entries related to a + * serializable transaction are removed when that serializable transaction is + * cleaned up. Entries can also be removed when they are combined into a + * single coarser-grained lock entry. + */ +typedef struct PREDICATELOCK +{ + /* hash key */ + PREDICATELOCKTAG tag; /* unique identifier of lock */ + + /* data */ + SHM_QUEUE targetLink; /* list link in PREDICATELOCKTARGET's list of + * predicate locks */ + SHM_QUEUE xactLink; /* list link in SERIALIZABLEXACT's list of + * predicate locks */ + SerCommitSeqNo commitSeqNo; /* only used for summarized predicate locks */ +} PREDICATELOCK; + + +/* + * The LOCALPREDICATELOCK struct represents a local copy of data which is + * also present in the PREDICATELOCK table, organized for fast access without + * needing to acquire a LWLock. It is strictly for optimization. + * + * Each serializable transaction creates its own local hash table to hold a + * collection of these. This information is used to determine when a number + * of fine-grained locks should be promoted to a single coarser-grained lock. + * The information is maintained more-or-less in parallel to the + * PREDICATELOCK data, but because this data is not protected by locks and is + * only used in an optimization heuristic, it is allowed to drift in a few + * corner cases where maintaining exact data would be expensive. + * + * The hash table is created when the serializable transaction acquires its + * snapshot, and its memory is released upon completion of the transaction. + */ +typedef struct LOCALPREDICATELOCK +{ + /* hash key */ + PREDICATELOCKTARGETTAG tag; /* unique identifier of lockable object */ + + /* data */ + bool held; /* is lock held, or just its children? */ + int childLocks; /* number of child locks currently held */ +} LOCALPREDICATELOCK; + + +/* + * The types of predicate locks which can be acquired. + */ +typedef enum PredicateLockTargetType +{ + PREDLOCKTAG_RELATION, + PREDLOCKTAG_PAGE, + PREDLOCKTAG_TUPLE + /* TODO SSI: Other types may be needed for index locking */ +} PredicateLockTargetType; + + +/* + * This structure is used to quickly capture a copy of all predicate + * locks. This is currently used only by the pg_lock_status function, + * which in turn is used by the pg_locks view. + */ +typedef struct PredicateLockData +{ + int nelements; + PREDICATELOCKTARGETTAG *locktags; + SERIALIZABLEXACT *xacts; +} PredicateLockData; + + +/* + * These macros define how we map logical IDs of lockable objects into the + * physical fields of PREDICATELOCKTARGETTAG. Use these to set up values, + * rather than accessing the fields directly. Note multiple eval of target! + */ +#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag,dboid,reloid) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = InvalidBlockNumber, \ + (locktag).locktag_field4 = InvalidOffsetNumber) + +#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag,dboid,reloid,blocknum) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = (blocknum), \ + (locktag).locktag_field4 = InvalidOffsetNumber) + +#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \ + ((locktag).locktag_field1 = (dboid), \ + (locktag).locktag_field2 = (reloid), \ + (locktag).locktag_field3 = (blocknum), \ + (locktag).locktag_field4 = (offnum)) + +#define GET_PREDICATELOCKTARGETTAG_DB(locktag) \ + ((Oid) (locktag).locktag_field1) +#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag) \ + ((Oid) (locktag).locktag_field2) +#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag) \ + ((BlockNumber) (locktag).locktag_field3) +#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag) \ + ((OffsetNumber) (locktag).locktag_field4) +#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag) \ + (((locktag).locktag_field4 != InvalidOffsetNumber) ? PREDLOCKTAG_TUPLE : \ + (((locktag).locktag_field3 != InvalidBlockNumber) ? PREDLOCKTAG_PAGE : \ + PREDLOCKTAG_RELATION)) + +/* + * Two-phase commit statefile records. There are two types: for each + * transaction, we generate one per-transaction record and a variable + * number of per-predicate-lock records. + */ +typedef enum TwoPhasePredicateRecordType +{ + TWOPHASEPREDICATERECORD_XACT, + TWOPHASEPREDICATERECORD_LOCK +} TwoPhasePredicateRecordType; + +/* + * Per-transaction information to reconstruct a SERIALIZABLEXACT. Not + * much is needed because most of it not meaningful for a recovered + * prepared transaction. + * + * In particular, we do not record the in and out conflict lists for a + * prepared transaction because the associated SERIALIZABLEXACTs will + * not be available after recovery. Instead, we simply record the + * existence of each type of conflict by setting the transaction's + * summary conflict in/out flag. + */ +typedef struct TwoPhasePredicateXactRecord +{ + TransactionId xmin; + uint32 flags; +} TwoPhasePredicateXactRecord; + +/* Per-lock state */ +typedef struct TwoPhasePredicateLockRecord +{ + PREDICATELOCKTARGETTAG target; + uint32 filler; /* to avoid length change in back-patched fix */ +} TwoPhasePredicateLockRecord; + +typedef struct TwoPhasePredicateRecord +{ + TwoPhasePredicateRecordType type; + union + { + TwoPhasePredicateXactRecord xactRecord; + TwoPhasePredicateLockRecord lockRecord; + } data; +} TwoPhasePredicateRecord; + +/* + * Define a macro to use for an "empty" SERIALIZABLEXACT reference. + */ +#define InvalidSerializableXact ((SERIALIZABLEXACT *) NULL) + + +/* + * Function definitions for functions needing awareness of predicate + * locking internals. + */ +extern PredicateLockData *GetPredicateLockStatusData(void); +extern int GetSafeSnapshotBlockingPids(int blocked_pid, + int *output, int output_size); + +#endif /* PREDICATE_INTERNALS_H */ diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h new file mode 100644 index 0000000..2579e61 --- /dev/null +++ b/src/include/storage/proc.h @@ -0,0 +1,461 @@ +/*------------------------------------------------------------------------- + * + * proc.h + * per-process shared memory data structures + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/proc.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PROC_H_ +#define _PROC_H_ + +#include "access/clog.h" +#include "access/xlogdefs.h" +#include "lib/ilist.h" +#include "storage/latch.h" +#include "storage/lock.h" +#include "storage/pg_sema.h" +#include "storage/proclist_types.h" + +/* + * Each backend advertises up to PGPROC_MAX_CACHED_SUBXIDS TransactionIds + * for non-aborted subtransactions of its current top transaction. These + * have to be treated as running XIDs by other backends. + * + * We also keep track of whether the cache overflowed (ie, the transaction has + * generated at least one subtransaction that didn't fit in the cache). + * If none of the caches have overflowed, we can assume that an XID that's not + * listed anywhere in the PGPROC array is not a running transaction. Else we + * have to look at pg_subtrans. + */ +#define PGPROC_MAX_CACHED_SUBXIDS 64 /* XXX guessed-at value */ + +typedef struct XidCacheStatus +{ + /* number of cached subxids, never more than PGPROC_MAX_CACHED_SUBXIDS */ + uint8 count; + /* has PGPROC->subxids overflowed */ + bool overflowed; +} XidCacheStatus; + +struct XidCache +{ + TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]; +}; + +/* + * Flags for PGPROC->statusFlags and PROC_HDR->statusFlags[] + */ +#define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ +#define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_IC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ +#define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ +#define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical + * decoding outside xact */ +#define PROC_AFFECTS_ALL_HORIZONS 0x20 /* this proc's xmin must be + * included in vacuum horizons + * in all databases */ + +/* flags reset at EOXact */ +#define PROC_VACUUM_STATE_MASK \ + (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND) + +/* + * Xmin-related flags. Make sure any flags that affect how the process' Xmin + * value is interpreted by VACUUM are included here. + */ +#define PROC_XMIN_FLAGS (PROC_IN_VACUUM | PROC_IN_SAFE_IC) + +/* + * We allow a small number of "weak" relation locks (AccessShareLock, + * RowShareLock, RowExclusiveLock) to be recorded in the PGPROC structure + * rather than the main lock table. This eases contention on the lock + * manager LWLocks. See storage/lmgr/README for additional details. + */ +#define FP_LOCK_SLOTS_PER_BACKEND 16 + +/* + * An invalid pgprocno. Must be larger than the maximum number of PGPROC + * structures we could possibly have. See comments for MAX_BACKENDS. + */ +#define INVALID_PGPROCNO PG_INT32_MAX + +/* + * Flags for PGPROC.delayChkpt + * + * These flags can be used to delay the start or completion of a checkpoint + * for short periods. A flag is in effect if the corresponding bit is set in + * the PGPROC of any backend. + * + * For our purposes here, a checkpoint has three phases: (1) determine the + * location to which the redo pointer will be moved, (2) write all the + * data durably to disk, and (3) WAL-log the checkpoint. + * + * Setting DELAY_CHKPT_START prevents the system from moving from phase 1 + * to phase 2. This is useful when we are performing a WAL-logged modification + * of data that will be flushed to disk in phase 2. By setting this flag + * before writing WAL and clearing it after we've both written WAL and + * performed the corresponding modification, we ensure that if the WAL record + * is inserted prior to the new redo point, the corresponding data changes will + * also be flushed to disk before the checkpoint can complete. (In the + * extremely common case where the data being modified is in shared buffers + * and we acquire an exclusive content lock on the relevant buffers before + * writing WAL, this mechanism is not needed, because phase 2 will block + * until we release the content lock and then flush the modified data to + * disk.) + * + * Setting DELAY_CHKPT_COMPLETE prevents the system from moving from phase 2 + * to phase 3. This is useful if we are performing a WAL-logged operation that + * might invalidate buffers, such as relation truncation. In this case, we need + * to ensure that any buffers which were invalidated and thus not flushed by + * the checkpoint are actaully destroyed on disk. Replay can cope with a file + * or block that doesn't exist, but not with a block that has the wrong + * contents. + */ +#define DELAY_CHKPT_START (1<<0) +#define DELAY_CHKPT_COMPLETE (1<<1) + +typedef enum +{ + PROC_WAIT_STATUS_OK, + PROC_WAIT_STATUS_WAITING, + PROC_WAIT_STATUS_ERROR, +} ProcWaitStatus; + +/* + * Each backend has a PGPROC struct in shared memory. There is also a list of + * currently-unused PGPROC structs that will be reallocated to new backends. + * + * links: list link for any list the PGPROC is in. When waiting for a lock, + * the PGPROC is linked into that lock's waitProcs queue. A recycled PGPROC + * is linked into ProcGlobal's freeProcs list. + * + * Note: twophase.c also sets up a dummy PGPROC struct for each currently + * prepared transaction. These PGPROCs appear in the ProcArray data structure + * so that the prepared transactions appear to be still running and are + * correctly shown as holding locks. A prepared transaction PGPROC can be + * distinguished from a real one at need by the fact that it has pid == 0. + * The semaphore and lock-activity fields in a prepared-xact PGPROC are unused, + * but its myProcLocks[] lists are valid. + * + * We allow many fields of this struct to be accessed without locks, such as + * delayChkpt and isBackgroundWorker. However, keep in mind that writing + * mirrored ones (see below) requires holding ProcArrayLock or XidGenLock in + * at least shared mode, so that pgxactoff does not change concurrently. + * + * Mirrored fields: + * + * Some fields in PGPROC (see "mirrored in ..." comment) are mirrored into an + * element of more densely packed ProcGlobal arrays. These arrays are indexed + * by PGPROC->pgxactoff. Both copies need to be maintained coherently. + * + * NB: The pgxactoff indexed value can *never* be accessed without holding + * locks. + * + * See PROC_HDR for details. + */ +struct PGPROC +{ + /* proc->links MUST BE FIRST IN STRUCT (see ProcSleep,ProcWakeup,etc) */ + SHM_QUEUE links; /* list link if process is in a list */ + PGPROC **procgloballist; /* procglobal list that owns this PGPROC */ + + PGSemaphore sem; /* ONE semaphore to sleep on */ + ProcWaitStatus waitStatus; + + Latch procLatch; /* generic latch for process */ + + + TransactionId xid; /* id of top-level transaction currently being + * executed by this proc, if running and XID + * is assigned; else InvalidTransactionId. + * mirrored in ProcGlobal->xids[pgxactoff] */ + + TransactionId xmin; /* minimal running XID as it was when we were + * starting our xact, excluding LAZY VACUUM: + * vacuum must not remove tuples deleted by + * xid >= xmin ! */ + + LocalTransactionId lxid; /* local id of top-level transaction currently + * being executed by this proc, if running; + * else InvalidLocalTransactionId */ + int pid; /* Backend's process ID; 0 if prepared xact */ + + int pgxactoff; /* offset into various ProcGlobal->arrays with + * data mirrored from this PGPROC */ + int pgprocno; + + /* These fields are zero while a backend is still starting up: */ + BackendId backendId; /* This backend's backend ID (if assigned) */ + Oid databaseId; /* OID of database this backend is using */ + Oid roleId; /* OID of role using this backend */ + + Oid tempNamespaceId; /* OID of temp schema this backend is + * using */ + + bool isBackgroundWorker; /* true if background worker. */ + + /* + * While in hot standby mode, shows that a conflict signal has been sent + * for the current transaction. Set/cleared while holding ProcArrayLock, + * though not required. Accessed without lock, if needed. + */ + bool recoveryConflictPending; + + /* Info about LWLock the process is currently waiting for, if any. */ + bool lwWaiting; /* true if waiting for an LW lock */ + uint8 lwWaitMode; /* lwlock mode being waited for */ + proclist_node lwWaitLink; /* position in LW lock wait list */ + + /* Support for condition variables. */ + proclist_node cvWaitLink; /* position in CV wait list */ + + /* Info about lock the process is currently waiting for, if any. */ + /* waitLock and waitProcLock are NULL if not currently waiting. */ + LOCK *waitLock; /* Lock object we're sleeping on ... */ + PROCLOCK *waitProcLock; /* Per-holder info for awaited lock */ + LOCKMODE waitLockMode; /* type of lock we're waiting for */ + LOCKMASK heldLocks; /* bitmask for lock types already held on this + * lock object by this backend */ + pg_atomic_uint64 waitStart; /* time at which wait for lock acquisition + * started */ + + int delayChkptFlags; /* for DELAY_CHKPT_* flags */ + + uint8 statusFlags; /* this backend's status flags, see PROC_* + * above. mirrored in + * ProcGlobal->statusFlags[pgxactoff] */ + + /* + * Info to allow us to wait for synchronous replication, if needed. + * waitLSN is InvalidXLogRecPtr if not waiting; set only by user backend. + * syncRepState must not be touched except by owning process or WALSender. + * syncRepLinks used only while holding SyncRepLock. + */ + XLogRecPtr waitLSN; /* waiting for this LSN or higher */ + int syncRepState; /* wait state for sync rep */ + SHM_QUEUE syncRepLinks; /* list link if process is in syncrep queue */ + + /* + * All PROCLOCK objects for locks held or awaited by this backend are + * linked into one of these lists, according to the partition number of + * their lock. + */ + SHM_QUEUE myProcLocks[NUM_LOCK_PARTITIONS]; + + XidCacheStatus subxidStatus; /* mirrored with + * ProcGlobal->subxidStates[i] */ + struct XidCache subxids; /* cache for subtransaction XIDs */ + + /* Support for group XID clearing. */ + /* true, if member of ProcArray group waiting for XID clear */ + bool procArrayGroupMember; + /* next ProcArray group member waiting for XID clear */ + pg_atomic_uint32 procArrayGroupNext; + + /* + * latest transaction id among the transaction's main XID and + * subtransactions + */ + TransactionId procArrayGroupMemberXid; + + uint32 wait_event_info; /* proc's wait information */ + + /* Support for group transaction status update. */ + bool clogGroupMember; /* true, if member of clog group */ + pg_atomic_uint32 clogGroupNext; /* next clog group member */ + TransactionId clogGroupMemberXid; /* transaction id of clog group member */ + XidStatus clogGroupMemberXidStatus; /* transaction status of clog + * group member */ + int clogGroupMemberPage; /* clog page corresponding to + * transaction id of clog group member */ + XLogRecPtr clogGroupMemberLsn; /* WAL location of commit record for clog + * group member */ + + /* Lock manager data, recording fast-path locks taken by this backend. */ + LWLock fpInfoLock; /* protects per-backend fast-path state */ + uint64 fpLockBits; /* lock modes held for each fast-path slot */ + Oid fpRelId[FP_LOCK_SLOTS_PER_BACKEND]; /* slots for rel oids */ + bool fpVXIDLock; /* are we holding a fast-path VXID lock? */ + LocalTransactionId fpLocalTransactionId; /* lxid for fast-path VXID + * lock */ + + /* + * Support for lock groups. Use LockHashPartitionLockByProc on the group + * leader to get the LWLock protecting these fields. + */ + PGPROC *lockGroupLeader; /* lock group leader, if I'm a member */ + dlist_head lockGroupMembers; /* list of members, if I'm a leader */ + dlist_node lockGroupLink; /* my member link, if I'm a member */ +}; + +/* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */ + + +extern PGDLLIMPORT PGPROC *MyProc; + +/* + * There is one ProcGlobal struct for the whole database cluster. + * + * Adding/Removing an entry into the procarray requires holding *both* + * ProcArrayLock and XidGenLock in exclusive mode (in that order). Both are + * needed because the dense arrays (see below) are accessed from + * GetNewTransactionId() and GetSnapshotData(), and we don't want to add + * further contention by both using the same lock. Adding/Removing a procarray + * entry is much less frequent. + * + * Some fields in PGPROC are mirrored into more densely packed arrays (e.g. + * xids), with one entry for each backend. These arrays only contain entries + * for PGPROCs that have been added to the shared array with ProcArrayAdd() + * (in contrast to PGPROC array which has unused PGPROCs interspersed). + * + * The dense arrays are indexed by PGPROC->pgxactoff. Any concurrent + * ProcArrayAdd() / ProcArrayRemove() can lead to pgxactoff of a procarray + * member to change. Therefore it is only safe to use PGPROC->pgxactoff to + * access the dense array while holding either ProcArrayLock or XidGenLock. + * + * As long as a PGPROC is in the procarray, the mirrored values need to be + * maintained in both places in a coherent manner. + * + * The denser separate arrays are beneficial for three main reasons: First, to + * allow for as tight loops accessing the data as possible. Second, to prevent + * updates of frequently changing data (e.g. xmin) from invalidating + * cachelines also containing less frequently changing data (e.g. xid, + * statusFlags). Third to condense frequently accessed data into as few + * cachelines as possible. + * + * There are two main reasons to have the data mirrored between these dense + * arrays and PGPROC. First, as explained above, a PGPROC's array entries can + * only be accessed with either ProcArrayLock or XidGenLock held, whereas the + * PGPROC entries do not require that (obviously there may still be locking + * requirements around the individual field, separate from the concerns + * here). That is particularly important for a backend to efficiently checks + * it own values, which it often can safely do without locking. Second, the + * PGPROC fields allow to avoid unnecessary accesses and modification to the + * dense arrays. A backend's own PGPROC is more likely to be in a local cache, + * whereas the cachelines for the dense array will be modified by other + * backends (often removing it from the cache for other cores/sockets). At + * commit/abort time a check of the PGPROC value can avoid accessing/dirtying + * the corresponding array value. + * + * Basically it makes sense to access the PGPROC variable when checking a + * single backend's data, especially when already looking at the PGPROC for + * other reasons already. It makes sense to look at the "dense" arrays if we + * need to look at many / most entries, because we then benefit from the + * reduced indirection and better cross-process cache-ability. + * + * When entering a PGPROC for 2PC transactions with ProcArrayAdd(), the data + * in the dense arrays is initialized from the PGPROC while it already holds + * ProcArrayLock. + */ +typedef struct PROC_HDR +{ + /* Array of PGPROC structures (not including dummies for prepared txns) */ + PGPROC *allProcs; + + /* Array mirroring PGPROC.xid for each PGPROC currently in the procarray */ + TransactionId *xids; + + /* + * Array mirroring PGPROC.subxidStatus for each PGPROC currently in the + * procarray. + */ + XidCacheStatus *subxidStates; + + /* + * Array mirroring PGPROC.statusFlags for each PGPROC currently in the + * procarray. + */ + uint8 *statusFlags; + + /* Length of allProcs array */ + uint32 allProcCount; + /* Head of list of free PGPROC structures */ + PGPROC *freeProcs; + /* Head of list of autovacuum's free PGPROC structures */ + PGPROC *autovacFreeProcs; + /* Head of list of bgworker free PGPROC structures */ + PGPROC *bgworkerFreeProcs; + /* Head of list of walsender free PGPROC structures */ + PGPROC *walsenderFreeProcs; + /* First pgproc waiting for group XID clear */ + pg_atomic_uint32 procArrayGroupFirst; + /* First pgproc waiting for group transaction status update */ + pg_atomic_uint32 clogGroupFirst; + /* WALWriter process's latch */ + Latch *walwriterLatch; + /* Checkpointer process's latch */ + Latch *checkpointerLatch; + /* Current shared estimate of appropriate spins_per_delay value */ + int spins_per_delay; + /* Buffer id of the buffer that Startup process waits for pin on, or -1 */ + int startupBufferPinWaitBufId; +} PROC_HDR; + +extern PGDLLIMPORT PROC_HDR *ProcGlobal; + +extern PGDLLIMPORT PGPROC *PreparedXactProcs; + +/* Accessor for PGPROC given a pgprocno. */ +#define GetPGProcByNumber(n) (&ProcGlobal->allProcs[(n)]) + +/* + * We set aside some extra PGPROC structures for auxiliary processes, + * ie things that aren't full-fledged backends but need shmem access. + * + * Background writer, checkpointer, WAL writer and archiver run during normal + * operation. Startup process and WAL receiver also consume 2 slots, but WAL + * writer is launched only after startup has exited, so we only need 5 slots. + */ +#define NUM_AUXILIARY_PROCS 5 + +/* configurable options */ +extern PGDLLIMPORT int DeadlockTimeout; +extern PGDLLIMPORT int StatementTimeout; +extern PGDLLIMPORT int LockTimeout; +extern PGDLLIMPORT int IdleInTransactionSessionTimeout; +extern PGDLLIMPORT int IdleSessionTimeout; +extern PGDLLIMPORT bool log_lock_waits; + + +/* + * Function Prototypes + */ +extern int ProcGlobalSemas(void); +extern Size ProcGlobalShmemSize(void); +extern void InitProcGlobal(void); +extern void InitProcess(void); +extern void InitProcessPhase2(void); +extern void InitAuxiliaryProcess(void); + +extern void SetStartupBufferPinWaitBufId(int bufid); +extern int GetStartupBufferPinWaitBufId(void); + +extern bool HaveNFreeProcs(int n); +extern void ProcReleaseLocks(bool isCommit); + +extern void ProcQueueInit(PROC_QUEUE *queue); +extern ProcWaitStatus ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable); +extern PGPROC *ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus); +extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock); +extern void CheckDeadLockAlert(void); +extern bool IsWaitingForLock(void); +extern void LockErrorCleanup(void); + +extern void ProcWaitForSignal(uint32 wait_event_info); +extern void ProcSendSignal(int pgprocno); + +extern PGPROC *AuxiliaryPidGetProc(int pid); + +extern void BecomeLockGroupLeader(void); +extern bool BecomeLockGroupMember(PGPROC *leader, int pid); + +#endif /* _PROC_H_ */ diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h new file mode 100644 index 0000000..781e3f6 --- /dev/null +++ b/src/include/storage/procarray.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * procarray.h + * POSTGRES process array definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/procarray.h + * + *------------------------------------------------------------------------- + */ +#ifndef PROCARRAY_H +#define PROCARRAY_H + +#include "storage/lock.h" +#include "storage/standby.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + + +extern Size ProcArrayShmemSize(void); +extern void CreateSharedProcArray(void); +extern void ProcArrayAdd(PGPROC *proc); +extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid); + +extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid); +extern void ProcArrayClearTransaction(PGPROC *proc); + +extern void ProcArrayInitRecovery(TransactionId initializedUptoXID); +extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); +extern void ProcArrayApplyXidAssignment(TransactionId topxid, + int nsubxids, TransactionId *subxids); + +extern void RecordKnownAssignedTransactionIds(TransactionId xid); +extern void ExpireTreeKnownAssignedTransactionIds(TransactionId xid, + int nsubxids, TransactionId *subxids, + TransactionId max_xid); +extern void ExpireAllKnownAssignedTransactionIds(void); +extern void ExpireOldKnownAssignedTransactionIds(TransactionId xid); +extern void KnownAssignedTransactionIdsIdleMaintenance(void); + +extern int GetMaxSnapshotXidCount(void); +extern int GetMaxSnapshotSubxidCount(void); + +extern Snapshot GetSnapshotData(Snapshot snapshot); + +extern bool ProcArrayInstallImportedXmin(TransactionId xmin, + VirtualTransactionId *sourcevxid); +extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc); + +extern RunningTransactions GetRunningTransactionData(void); + +extern bool TransactionIdIsInProgress(TransactionId xid); +extern bool TransactionIdIsActive(TransactionId xid); +extern TransactionId GetOldestNonRemovableTransactionId(Relation rel); +extern TransactionId GetOldestTransactionIdConsideredRunning(void); +extern TransactionId GetOldestActiveTransactionId(void); +extern TransactionId GetOldestSafeDecodingTransactionId(bool catalogOnly); +extern void GetReplicationHorizons(TransactionId *slot_xmin, TransactionId *catalog_xmin); + +extern VirtualTransactionId *GetVirtualXIDsDelayingChkpt(int *nvxids, int type); +extern bool HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, + int nvxids, int type); + +extern PGPROC *BackendPidGetProc(int pid); +extern PGPROC *BackendPidGetProcWithLock(int pid); +extern int BackendXidGetPid(TransactionId xid); +extern bool IsBackendPid(int pid); + +extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin, + bool excludeXmin0, bool allDbs, int excludeVacuum, + int *nvxids); +extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid); +extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode); +extern pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, + bool conflictPending); + +extern bool MinimumActiveBackends(int min); +extern int CountDBBackends(Oid databaseid); +extern int CountDBConnections(Oid databaseid); +extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending); +extern int CountUserBackends(Oid roleid); +extern bool CountOtherDBBackends(Oid databaseId, + int *nbackends, int *nprepared); +extern void TerminateOtherDBBackends(Oid databaseId); + +extern void XidCacheRemoveRunningXids(TransactionId xid, + int nxids, const TransactionId *xids, + TransactionId latestXid); + +extern void ProcArraySetReplicationSlotXmin(TransactionId xmin, + TransactionId catalog_xmin, bool already_locked); + +extern void ProcArrayGetReplicationSlotXmin(TransactionId *xmin, + TransactionId *catalog_xmin); + +#endif /* PROCARRAY_H */ diff --git a/src/include/storage/proclist.h b/src/include/storage/proclist.h new file mode 100644 index 0000000..509e341 --- /dev/null +++ b/src/include/storage/proclist.h @@ -0,0 +1,219 @@ +/*------------------------------------------------------------------------- + * + * proclist.h + * operations on doubly-linked lists of pgprocnos + * + * The interface is similar to dlist from ilist.h, but uses pgprocno instead + * of pointers. This allows proclist_head to be mapped at different addresses + * in different backends. + * + * See proclist_types.h for the structs that these functions operate on. They + * are separated to break a header dependency cycle with proc.h. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/storage/proclist.h + *------------------------------------------------------------------------- + */ +#ifndef PROCLIST_H +#define PROCLIST_H + +#include "storage/proc.h" +#include "storage/proclist_types.h" + +/* + * Initialize a proclist. + */ +static inline void +proclist_init(proclist_head *list) +{ + list->head = list->tail = INVALID_PGPROCNO; +} + +/* + * Is the list empty? + */ +static inline bool +proclist_is_empty(proclist_head *list) +{ + return list->head == INVALID_PGPROCNO; +} + +/* + * Get a pointer to a proclist_node inside a given PGPROC, given a procno and + * the proclist_node field's offset within struct PGPROC. + */ +static inline proclist_node * +proclist_node_get(int procno, size_t node_offset) +{ + char *entry = (char *) GetPGProcByNumber(procno); + + return (proclist_node *) (entry + node_offset); +} + +/* + * Insert a process at the beginning of a list. + */ +static inline void +proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + Assert(node->next == 0 && node->prev == 0); + + if (list->head == INVALID_PGPROCNO) + { + Assert(list->tail == INVALID_PGPROCNO); + node->next = node->prev = INVALID_PGPROCNO; + list->head = list->tail = procno; + } + else + { + Assert(list->tail != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); + node->next = list->head; + proclist_node_get(node->next, node_offset)->prev = procno; + node->prev = INVALID_PGPROCNO; + list->head = procno; + } +} + +/* + * Insert a process at the end of a list. + */ +static inline void +proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + Assert(node->next == 0 && node->prev == 0); + + if (list->tail == INVALID_PGPROCNO) + { + Assert(list->head == INVALID_PGPROCNO); + node->next = node->prev = INVALID_PGPROCNO; + list->head = list->tail = procno; + } + else + { + Assert(list->head != INVALID_PGPROCNO); + Assert(list->head != procno); + Assert(list->tail != procno); + node->prev = list->tail; + proclist_node_get(node->prev, node_offset)->next = procno; + node->next = INVALID_PGPROCNO; + list->tail = procno; + } +} + +/* + * Delete a process from a list --- it must be in the list! + */ +static inline void +proclist_delete_offset(proclist_head *list, int procno, size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + Assert(node->next != 0 || node->prev != 0); + + if (node->prev == INVALID_PGPROCNO) + { + Assert(list->head == procno); + list->head = node->next; + } + else + proclist_node_get(node->prev, node_offset)->next = node->next; + + if (node->next == INVALID_PGPROCNO) + { + Assert(list->tail == procno); + list->tail = node->prev; + } + else + proclist_node_get(node->next, node_offset)->prev = node->prev; + + node->next = node->prev = 0; +} + +/* + * Check if a process is currently in a list. It must be known that the + * process is not in any _other_ proclist that uses the same proclist_node, + * so that the only possibilities are that it is in this list or none. + */ +static inline bool +proclist_contains_offset(proclist_head *list, int procno, + size_t node_offset) +{ + proclist_node *node = proclist_node_get(procno, node_offset); + + /* If it's not in any list, it's definitely not in this one. */ + if (node->prev == 0 && node->next == 0) + return false; + + /* + * It must, in fact, be in this list. Ideally, in assert-enabled builds, + * we'd verify that. But since this function is typically used while + * holding a spinlock, crawling the whole list is unacceptable. However, + * we can verify matters in O(1) time when the node is a list head or + * tail, and that seems worth doing, since in practice that should often + * be enough to catch mistakes. + */ + Assert(node->prev != INVALID_PGPROCNO || list->head == procno); + Assert(node->next != INVALID_PGPROCNO || list->tail == procno); + + return true; +} + +/* + * Remove and return the first process from a list (there must be one). + */ +static inline PGPROC * +proclist_pop_head_node_offset(proclist_head *list, size_t node_offset) +{ + PGPROC *proc; + + Assert(!proclist_is_empty(list)); + proc = GetPGProcByNumber(list->head); + proclist_delete_offset(list, list->head, node_offset); + return proc; +} + +/* + * Helper macros to avoid repetition of offsetof(PGPROC, <member>). + * 'link_member' is the name of a proclist_node member in PGPROC. + */ +#define proclist_delete(list, procno, link_member) \ + proclist_delete_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_push_head(list, procno, link_member) \ + proclist_push_head_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_push_tail(list, procno, link_member) \ + proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member)) +#define proclist_pop_head_node(list, link_member) \ + proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member)) +#define proclist_contains(list, procno, link_member) \ + proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member)) + +/* + * Iterate through the list pointed at by 'lhead', storing the current + * position in 'iter'. 'link_member' is the name of a proclist_node member in + * PGPROC. Access the current position with iter.cur. + * + * The only list modification allowed while iterating is deleting the current + * node with proclist_delete(list, iter.cur, node_offset). + */ +#define proclist_foreach_modify(iter, lhead, link_member) \ + for (AssertVariableIsOfTypeMacro(iter, proclist_mutable_iter), \ + AssertVariableIsOfTypeMacro(lhead, proclist_head *), \ + (iter).cur = (lhead)->head, \ + (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \ + proclist_node_get((iter).cur, \ + offsetof(PGPROC, link_member))->next; \ + (iter).cur != INVALID_PGPROCNO; \ + (iter).cur = (iter).next, \ + (iter).next = (iter).cur == INVALID_PGPROCNO ? INVALID_PGPROCNO : \ + proclist_node_get((iter).cur, \ + offsetof(PGPROC, link_member))->next) + +#endif /* PROCLIST_H */ diff --git a/src/include/storage/proclist_types.h b/src/include/storage/proclist_types.h new file mode 100644 index 0000000..5232679 --- /dev/null +++ b/src/include/storage/proclist_types.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * proclist_types.h + * doubly-linked lists of pgprocnos + * + * See proclist.h for functions that operate on these types. + * + * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/storage/proclist_types.h + *------------------------------------------------------------------------- + */ + +#ifndef PROCLIST_TYPES_H +#define PROCLIST_TYPES_H + +/* + * A node in a doubly-linked list of processes. The link fields contain + * the 0-based PGPROC indexes of the next and previous process, or + * INVALID_PGPROCNO in the next-link of the last node and the prev-link + * of the first node. A node that is currently not in any list + * should have next == prev == 0; this is not a possible state for a node + * that is in a list, because we disallow circularity. + */ +typedef struct proclist_node +{ + int next; /* pgprocno of the next PGPROC */ + int prev; /* pgprocno of the prev PGPROC */ +} proclist_node; + +/* + * Header of a doubly-linked list of PGPROCs, identified by pgprocno. + * An empty list is represented by head == tail == INVALID_PGPROCNO. + */ +typedef struct proclist_head +{ + int head; /* pgprocno of the head PGPROC */ + int tail; /* pgprocno of the tail PGPROC */ +} proclist_head; + +/* + * List iterator allowing some modifications while iterating. + */ +typedef struct proclist_mutable_iter +{ + int cur; /* pgprocno of the current PGPROC */ + int next; /* pgprocno of the next PGPROC */ +} proclist_mutable_iter; + +#endif /* PROCLIST_TYPES_H */ diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h new file mode 100644 index 0000000..ee63690 --- /dev/null +++ b/src/include/storage/procsignal.h @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------- + * + * procsignal.h + * Routines for interprocess signaling + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/procsignal.h + * + *------------------------------------------------------------------------- + */ +#ifndef PROCSIGNAL_H +#define PROCSIGNAL_H + +#include "storage/backendid.h" + + +/* + * Reasons for signaling a Postgres child process (a backend or an auxiliary + * process, like checkpointer). We can cope with concurrent signals for different + * reasons. However, if the same reason is signaled multiple times in quick + * succession, the process is likely to observe only one notification of it. + * This is okay for the present uses. + * + * Also, because of race conditions, it's important that all the signals be + * defined so that no harm is done if a process mistakenly receives one. + */ +typedef enum +{ + PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ + PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ + PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */ + PROCSIG_WALSND_INIT_STOPPING, /* ask walsenders to prepare for shutdown */ + PROCSIG_BARRIER, /* global barrier interrupt */ + PROCSIG_LOG_MEMORY_CONTEXT, /* ask backend to log the memory contexts */ + + /* Recovery conflict reasons */ + PROCSIG_RECOVERY_CONFLICT_DATABASE, + PROCSIG_RECOVERY_CONFLICT_TABLESPACE, + PROCSIG_RECOVERY_CONFLICT_LOCK, + PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, + PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, + PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + + NUM_PROCSIGNALS /* Must be last! */ +} ProcSignalReason; + +typedef enum +{ + PROCSIGNAL_BARRIER_SMGRRELEASE /* ask smgr to close files */ +} ProcSignalBarrierType; + +/* + * prototypes for functions in procsignal.c + */ +extern Size ProcSignalShmemSize(void); +extern void ProcSignalShmemInit(void); + +extern void ProcSignalInit(int pss_idx); +extern int SendProcSignal(pid_t pid, ProcSignalReason reason, + BackendId backendId); + +extern uint64 EmitProcSignalBarrier(ProcSignalBarrierType type); +extern void WaitForProcSignalBarrier(uint64 generation); +extern void ProcessProcSignalBarrier(void); + +extern void procsignal_sigusr1_handler(SIGNAL_ARGS); + +#endif /* PROCSIGNAL_H */ diff --git a/src/include/storage/reinit.h b/src/include/storage/reinit.h new file mode 100644 index 0000000..bf2c10d --- /dev/null +++ b/src/include/storage/reinit.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * reinit.h + * Reinitialization of unlogged relations + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/reinit.h + * + *------------------------------------------------------------------------- + */ + +#ifndef REINIT_H +#define REINIT_H + +#include "common/relpath.h" + + +extern void ResetUnloggedRelations(int op); +extern bool parse_filename_for_nontemp_relation(const char *name, + int *oidchars, ForkNumber *fork); + +#define UNLOGGED_RELATION_CLEANUP 0x0001 +#define UNLOGGED_RELATION_INIT 0x0002 + +#endif /* REINIT_H */ diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h new file mode 100644 index 0000000..4fdc606 --- /dev/null +++ b/src/include/storage/relfilenode.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * relfilenode.h + * Physical access information for relations. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/relfilenode.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELFILENODE_H +#define RELFILENODE_H + +#include "common/relpath.h" +#include "storage/backendid.h" + +/* + * RelFileNode must provide all that we need to know to physically access + * a relation, with the exception of the backend ID, which can be provided + * separately. Note, however, that a "physical" relation is comprised of + * multiple files on the filesystem, as each fork is stored as a separate + * file, and each fork can be divided into multiple segments. See md.c. + * + * spcNode identifies the tablespace of the relation. It corresponds to + * pg_tablespace.oid. + * + * dbNode identifies the database of the relation. It is zero for + * "shared" relations (those common to all databases of a cluster). + * Nonzero dbNode values correspond to pg_database.oid. + * + * relNode identifies the specific relation. relNode corresponds to + * pg_class.relfilenode (NOT pg_class.oid, because we need to be able + * to assign new physical files to relations in some situations). + * Notice that relNode is only unique within a database in a particular + * tablespace. + * + * Note: spcNode must be GLOBALTABLESPACE_OID if and only if dbNode is + * zero. We support shared relations only in the "global" tablespace. + * + * Note: in pg_class we allow reltablespace == 0 to denote that the + * relation is stored in its database's "default" tablespace (as + * identified by pg_database.dattablespace). However this shorthand + * is NOT allowed in RelFileNode structs --- the real tablespace ID + * must be supplied when setting spcNode. + * + * Note: in pg_class, relfilenode can be zero to denote that the relation + * is a "mapped" relation, whose current true filenode number is available + * from relmapper.c. Again, this case is NOT allowed in RelFileNodes. + * + * Note: various places use RelFileNode in hashtable keys. Therefore, + * there *must not* be any unused padding bytes in this struct. That + * should be safe as long as all the fields are of type Oid. + */ +typedef struct RelFileNode +{ + Oid spcNode; /* tablespace */ + Oid dbNode; /* database */ + Oid relNode; /* relation */ +} RelFileNode; + +/* + * Augmenting a relfilenode with the backend ID provides all the information + * we need to locate the physical storage. The backend ID is InvalidBackendId + * for regular relations (those accessible to more than one backend), or the + * owning backend's ID for backend-local relations. Backend-local relations + * are always transient and removed in case of a database crash; they are + * never WAL-logged or fsync'd. + */ +typedef struct RelFileNodeBackend +{ + RelFileNode node; + BackendId backend; +} RelFileNodeBackend; + +#define RelFileNodeBackendIsTemp(rnode) \ + ((rnode).backend != InvalidBackendId) + +/* + * Note: RelFileNodeEquals and RelFileNodeBackendEquals compare relNode first + * since that is most likely to be different in two unequal RelFileNodes. It + * is probably redundant to compare spcNode if the other fields are found equal, + * but do it anyway to be sure. Likewise for checking the backend ID in + * RelFileNodeBackendEquals. + */ +#define RelFileNodeEquals(node1, node2) \ + ((node1).relNode == (node2).relNode && \ + (node1).dbNode == (node2).dbNode && \ + (node1).spcNode == (node2).spcNode) + +#define RelFileNodeBackendEquals(node1, node2) \ + ((node1).node.relNode == (node2).node.relNode && \ + (node1).node.dbNode == (node2).node.dbNode && \ + (node1).backend == (node2).backend && \ + (node1).node.spcNode == (node2).node.spcNode) + +#endif /* RELFILENODE_H */ diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h new file mode 100644 index 0000000..4d3ffc7 --- /dev/null +++ b/src/include/storage/s_lock.h @@ -0,0 +1,1110 @@ +/*------------------------------------------------------------------------- + * + * s_lock.h + * Hardware-dependent implementation of spinlocks. + * + * NOTE: none of the macros in this file are intended to be called directly. + * Call them through the hardware-independent macros in spin.h. + * + * The following hardware-dependent macros must be provided for each + * supported platform: + * + * void S_INIT_LOCK(slock_t *lock) + * Initialize a spinlock (to the unlocked state). + * + * int S_LOCK(slock_t *lock) + * Acquire a spinlock, waiting if necessary. + * Time out and abort() if unable to acquire the lock in a + * "reasonable" amount of time --- typically ~ 1 minute. + * Should return number of "delays"; see s_lock.c + * + * void S_UNLOCK(slock_t *lock) + * Unlock a previously acquired lock. + * + * bool S_LOCK_FREE(slock_t *lock) + * Tests if the lock is free. Returns true if free, false if locked. + * This does *not* change the state of the lock. + * + * void SPIN_DELAY(void) + * Delay operation to occur inside spinlock wait loop. + * + * Note to implementors: there are default implementations for all these + * macros at the bottom of the file. Check if your platform can use + * these or needs to override them. + * + * Usually, S_LOCK() is implemented in terms of even lower-level macros + * TAS() and TAS_SPIN(): + * + * int TAS(slock_t *lock) + * Atomic test-and-set instruction. Attempt to acquire the lock, + * but do *not* wait. Returns 0 if successful, nonzero if unable + * to acquire the lock. + * + * int TAS_SPIN(slock_t *lock) + * Like TAS(), but this version is used when waiting for a lock + * previously found to be contended. By default, this is the + * same as TAS(), but on some architectures it's better to poll a + * contended lock using an unlocked instruction and retry the + * atomic test-and-set only when it appears free. + * + * TAS() and TAS_SPIN() are NOT part of the API, and should never be called + * directly. + * + * CAUTION: on some platforms TAS() and/or TAS_SPIN() may sometimes report + * failure to acquire a lock even when the lock is not locked. For example, + * on Alpha TAS() will "fail" if interrupted. Therefore a retry loop must + * always be used, even if you are certain the lock is free. + * + * It is the responsibility of these macros to make sure that the compiler + * does not re-order accesses to shared memory to precede the actual lock + * acquisition, or follow the lock release. Prior to PostgreSQL 9.5, this + * was the caller's responsibility, which meant that callers had to use + * volatile-qualified pointers to refer to both the spinlock itself and the + * shared data being accessed within the spinlocked critical section. This + * was notationally awkward, easy to forget (and thus error-prone), and + * prevented some useful compiler optimizations. For these reasons, we + * now require that the macros themselves prevent compiler re-ordering, + * so that the caller doesn't need to take special precautions. + * + * On platforms with weak memory ordering, the TAS(), TAS_SPIN(), and + * S_UNLOCK() macros must further include hardware-level memory fence + * instructions to prevent similar re-ordering at the hardware level. + * TAS() and TAS_SPIN() must guarantee that loads and stores issued after + * the macro are not executed until the lock has been obtained. Conversely, + * S_UNLOCK() must guarantee that loads and stores issued before the macro + * have been executed before the lock is released. + * + * On most supported platforms, TAS() uses a tas() function written + * in assembly language to execute a hardware atomic-test-and-set + * instruction. Equivalent OS-supplied mutex routines could be used too. + * + * If no system-specific TAS() is available (ie, HAVE_SPINLOCKS is not + * defined), then we fall back on an emulation that uses SysV semaphores + * (see spin.c). This emulation will be MUCH MUCH slower than a proper TAS() + * implementation, because of the cost of a kernel call per lock or unlock. + * An old report is that Postgres spends around 40% of its time in semop(2) + * when using the SysV semaphore code. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/s_lock.h + * + *------------------------------------------------------------------------- + */ +#ifndef S_LOCK_H +#define S_LOCK_H + +#ifdef FRONTEND +#error "s_lock.h may not be included from frontend code" +#endif + +#ifdef HAVE_SPINLOCKS /* skip spinlocks if requested */ + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +/************************************************************************* + * All the gcc inlines + * Gcc consistently defines the CPU as __cpu__. + * Other compilers use __cpu or __cpu__ so we test for both in those cases. + */ + +/*---------- + * Standard gcc asm format (assuming "volatile slock_t *lock"): + + __asm__ __volatile__( + " instruction \n" + " instruction \n" + " instruction \n" +: "=r"(_res), "+m"(*lock) // return register, in/out lock value +: "r"(lock) // lock pointer, in input register +: "memory", "cc"); // show clobbered registers here + + * The output-operands list (after first colon) should always include + * "+m"(*lock), whether or not the asm code actually refers to this + * operand directly. This ensures that gcc believes the value in the + * lock variable is used and set by the asm code. Also, the clobbers + * list (after third colon) should always include "memory"; this prevents + * gcc from thinking it can cache the values of shared-memory fields + * across the asm code. Add "cc" if your asm code changes the condition + * code register, and also list any temp registers the code uses. + *---------- + */ + + +#ifdef __i386__ /* 32-bit i386 */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res = 1; + + /* + * Use a non-locking test before asserting the bus lock. Note that the + * extra test appears to be a small loss on some x86 platforms and a small + * win on others; it's by no means clear that we should keep it. + * + * When this was last tested, we didn't have separate TAS() and TAS_SPIN() + * macros. Nowadays it probably would be better to do a non-locking test + * in TAS_SPIN() but not in TAS(), like on x86_64, but no-one's done the + * testing to verify that. Without some empirical evidence, better to + * leave it alone. + */ + __asm__ __volatile__( + " cmpb $0,%1 \n" + " jne 1f \n" + " lock \n" + " xchgb %0,%1 \n" + "1: \n" +: "+q"(_res), "+m"(*lock) +: /* no inputs */ +: "memory", "cc"); + return (int) _res; +} + +#define SPIN_DELAY() spin_delay() + +static __inline__ void +spin_delay(void) +{ + /* + * This sequence is equivalent to the PAUSE instruction ("rep" is + * ignored by old IA32 processors if the following instruction is + * not a string operation); the IA-32 Architecture Software + * Developer's Manual, Vol. 3, Section 7.7.2 describes why using + * PAUSE in the inner loop of a spin lock is necessary for good + * performance: + * + * The PAUSE instruction improves the performance of IA-32 + * processors supporting Hyper-Threading Technology when + * executing spin-wait loops and other routines where one + * thread is accessing a shared lock or semaphore in a tight + * polling loop. When executing a spin-wait loop, the + * processor can suffer a severe performance penalty when + * exiting the loop because it detects a possible memory order + * violation and flushes the core processor's pipeline. The + * PAUSE instruction provides a hint to the processor that the + * code sequence is a spin-wait loop. The processor uses this + * hint to avoid the memory order violation and prevent the + * pipeline flush. In addition, the PAUSE instruction + * de-pipelines the spin-wait loop to prevent it from + * consuming execution resources excessively. + */ + __asm__ __volatile__( + " rep; nop \n"); +} + +#endif /* __i386__ */ + + +#ifdef __x86_64__ /* AMD Opteron, Intel EM64T */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +/* + * On Intel EM64T, it's a win to use a non-locking test before the xchg proper, + * but only when spinning. + * + * See also Implementing Scalable Atomic Locks for Multi-Core Intel(tm) EM64T + * and IA32, by Michael Chynoweth and Mary R. Lee. As of this writing, it is + * available at: + * http://software.intel.com/en-us/articles/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architectures + */ +#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock)) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res = 1; + + __asm__ __volatile__( + " lock \n" + " xchgb %0,%1 \n" +: "+q"(_res), "+m"(*lock) +: /* no inputs */ +: "memory", "cc"); + return (int) _res; +} + +#define SPIN_DELAY() spin_delay() + +static __inline__ void +spin_delay(void) +{ + /* + * Adding a PAUSE in the spin delay loop is demonstrably a no-op on + * Opteron, but it may be of some use on EM64T, so we keep it. + */ + __asm__ __volatile__( + " rep; nop \n"); +} + +#endif /* __x86_64__ */ + + +#if defined(__ia64__) || defined(__ia64) +/* + * Intel Itanium, gcc or Intel's compiler. + * + * Itanium has weak memory ordering, but we rely on the compiler to enforce + * strict ordering of accesses to volatile data. In particular, while the + * xchg instruction implicitly acts as a memory barrier with 'acquire' + * semantics, we do not have an explicit memory fence instruction in the + * S_UNLOCK macro. We use a regular assignment to clear the spinlock, and + * trust that the compiler marks the generated store instruction with the + * ".rel" opcode. + * + * Testing shows that assumption to hold on gcc, although I could not find + * any explicit statement on that in the gcc manual. In Intel's compiler, + * the -m[no-]serialize-volatile option controls that, and testing shows that + * it is enabled by default. + * + * While icc accepts gcc asm blocks on x86[_64], this is not true on ia64 + * (at least not in icc versions before 12.x). So we have to carry a separate + * compiler-intrinsic-based implementation for it. + */ +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +/* On IA64, it's a win to use a non-locking test before the xchg proper */ +#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock)) + +#ifndef __INTEL_COMPILER + +static __inline__ int +tas(volatile slock_t *lock) +{ + long int ret; + + __asm__ __volatile__( + " xchg4 %0=%1,%2 \n" +: "=r"(ret), "+m"(*lock) +: "r"(1) +: "memory"); + return (int) ret; +} + +#else /* __INTEL_COMPILER */ + +static __inline__ int +tas(volatile slock_t *lock) +{ + int ret; + + ret = _InterlockedExchange(lock,1); /* this is a xchg asm macro */ + + return ret; +} + +/* icc can't use the regular gcc S_UNLOCK() macro either in this case */ +#define S_UNLOCK(lock) \ + do { __memory_barrier(); *(lock) = 0; } while (0) + +#endif /* __INTEL_COMPILER */ +#endif /* __ia64__ || __ia64 */ + + +/* + * On ARM and ARM64, we use __sync_lock_test_and_set(int *, int) if available. + * + * We use the int-width variant of the builtin because it works on more chips + * than other widths. + */ +#if defined(__arm__) || defined(__arm) || defined(__aarch64__) || defined(__aarch64) +#ifdef HAVE_GCC__SYNC_INT32_TAS +#define HAS_TEST_AND_SET + +#define TAS(lock) tas(lock) + +typedef int slock_t; + +static __inline__ int +tas(volatile slock_t *lock) +{ + return __sync_lock_test_and_set(lock, 1); +} + +#define S_UNLOCK(lock) __sync_lock_release(lock) + +/* + * Using an ISB instruction to delay in spinlock loops appears beneficial on + * high-core-count ARM64 processors. It seems mostly a wash for smaller gear, + * and ISB doesn't exist at all on pre-v7 ARM chips. + */ +#if defined(__aarch64__) || defined(__aarch64) + +#define SPIN_DELAY() spin_delay() + +static __inline__ void +spin_delay(void) +{ + __asm__ __volatile__( + " isb; \n"); +} + +#endif /* __aarch64__ || __aarch64 */ +#endif /* HAVE_GCC__SYNC_INT32_TAS */ +#endif /* __arm__ || __arm || __aarch64__ || __aarch64 */ + + +/* S/390 and S/390x Linux (32- and 64-bit zSeries) */ +#if defined(__s390__) || defined(__s390x__) +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + int _res = 0; + + __asm__ __volatile__( + " cs %0,%3,0(%2) \n" +: "+d"(_res), "+m"(*lock) +: "a"(lock), "d"(1) +: "memory", "cc"); + return _res; +} + +#endif /* __s390__ || __s390x__ */ + + +#if defined(__sparc__) /* Sparc */ +/* + * Solaris has always run sparc processors in TSO (total store) mode, but + * linux didn't use to and the *BSDs still don't. So, be careful about + * acquire/release semantics. The CPU will treat superfluous membars as + * NOPs, so it's just code space. + */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res; + + /* + * See comment in src/backend/port/tas/sunstudio_sparc.s for why this + * uses "ldstub", and that file uses "cas". gcc currently generates + * sparcv7-targeted binaries, so "cas" use isn't possible. + */ + __asm__ __volatile__( + " ldstub [%2], %0 \n" +: "=r"(_res), "+m"(*lock) +: "r"(lock) +: "memory"); +#if defined(__sparcv7) || defined(__sparc_v7__) + /* + * No stbar or membar available, luckily no actually produced hardware + * requires a barrier. + */ +#elif defined(__sparcv8) || defined(__sparc_v8__) + /* stbar is available (and required for both PSO, RMO), membar isn't */ + __asm__ __volatile__ ("stbar \n":::"memory"); +#else + /* + * #LoadStore (RMO) | #LoadLoad (RMO) together are the appropriate acquire + * barrier for sparcv8+ upwards. + */ + __asm__ __volatile__ ("membar #LoadStore | #LoadLoad \n":::"memory"); +#endif + return (int) _res; +} + +#if defined(__sparcv7) || defined(__sparc_v7__) +/* + * No stbar or membar available, luckily no actually produced hardware + * requires a barrier. We fall through to the default gcc definition of + * S_UNLOCK in this case. + */ +#elif defined(__sparcv8) || defined(__sparc_v8__) +/* stbar is available (and required for both PSO, RMO), membar isn't */ +#define S_UNLOCK(lock) \ +do \ +{ \ + __asm__ __volatile__ ("stbar \n":::"memory"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) +#else +/* + * #LoadStore (RMO) | #StoreStore (RMO, PSO) together are the appropriate + * release barrier for sparcv8+ upwards. + */ +#define S_UNLOCK(lock) \ +do \ +{ \ + __asm__ __volatile__ ("membar #LoadStore | #StoreStore \n":::"memory"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) +#endif + +#endif /* __sparc__ */ + + +/* PowerPC */ +#if defined(__ppc__) || defined(__powerpc__) || defined(__ppc64__) || defined(__powerpc64__) +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +/* On PPC, it's a win to use a non-locking test before the lwarx */ +#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock)) + +/* + * The second operand of addi can hold a constant zero or a register number, + * hence constraint "=&b" to avoid allocating r0. "b" stands for "address + * base register"; most operands having this register-or-zero property are + * address bases, e.g. the second operand of lwax. + * + * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002, + * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop. + * On newer machines, we can use lwsync instead for better performance. + * + * Ordinarily, we'd code the branches here using GNU-style local symbols, that + * is "1f" referencing "1:" and so on. But some people run gcc on AIX with + * IBM's assembler as backend, and IBM's assembler doesn't do local symbols. + * So hand-code the branch offsets; fortunately, all PPC instructions are + * exactly 4 bytes each, so it's not too hard to count. + */ +static __inline__ int +tas(volatile slock_t *lock) +{ + slock_t _t; + int _res; + + __asm__ __volatile__( +#ifdef USE_PPC_LWARX_MUTEX_HINT +" lwarx %0,0,%3,1 \n" +#else +" lwarx %0,0,%3 \n" +#endif +" cmpwi %0,0 \n" +" bne $+16 \n" /* branch to li %1,1 */ +" addi %0,%0,1 \n" +" stwcx. %0,0,%3 \n" +" beq $+12 \n" /* branch to lwsync/isync */ +" li %1,1 \n" +" b $+12 \n" /* branch to end of asm sequence */ +#ifdef USE_PPC_LWSYNC +" lwsync \n" +#else +" isync \n" +#endif +" li %1,0 \n" + +: "=&b"(_t), "=r"(_res), "+m"(*lock) +: "r"(lock) +: "memory", "cc"); + return _res; +} + +/* + * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction. + * On newer machines, we can use lwsync instead for better performance. + */ +#ifdef USE_PPC_LWSYNC +#define S_UNLOCK(lock) \ +do \ +{ \ + __asm__ __volatile__ (" lwsync \n" ::: "memory"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) +#else +#define S_UNLOCK(lock) \ +do \ +{ \ + __asm__ __volatile__ (" sync \n" ::: "memory"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) +#endif /* USE_PPC_LWSYNC */ + +#endif /* powerpc */ + + +/* Linux Motorola 68k */ +#if (defined(__mc68000__) || defined(__m68k__)) && defined(__linux__) +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register int rv; + + __asm__ __volatile__( + " clrl %0 \n" + " tas %1 \n" + " sne %0 \n" +: "=d"(rv), "+m"(*lock) +: /* no inputs */ +: "memory", "cc"); + return rv; +} + +#endif /* (__mc68000__ || __m68k__) && __linux__ */ + + +/* Motorola 88k */ +#if defined(__m88k__) +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register slock_t _res = 1; + + __asm__ __volatile__( + " xmem %0, %2, %%r0 \n" +: "+r"(_res), "+m"(*lock) +: "r"(lock) +: "memory"); + return (int) _res; +} + +#endif /* __m88k__ */ + + +/* + * VAXen -- even multiprocessor ones + * (thanks to Tom Ivar Helbekkmo) + */ +#if defined(__vax__) +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register int _res; + + __asm__ __volatile__( + " movl $1, %0 \n" + " bbssi $0, (%2), 1f \n" + " clrl %0 \n" + "1: \n" +: "=&r"(_res), "+m"(*lock) +: "r"(lock) +: "memory"); + return _res; +} + +#endif /* __vax__ */ + + +#if defined(__mips__) && !defined(__sgi) /* non-SGI MIPS */ +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#define TAS(lock) tas(lock) + +/* + * Original MIPS-I processors lacked the LL/SC instructions, but if we are + * so unfortunate as to be running on one of those, we expect that the kernel + * will handle the illegal-instruction traps and emulate them for us. On + * anything newer (and really, MIPS-I is extinct) LL/SC is the only sane + * choice because any other synchronization method must involve a kernel + * call. Unfortunately, many toolchains still default to MIPS-I as the + * codegen target; if the symbol __mips shows that that's the case, we + * have to force the assembler to accept LL/SC. + * + * R10000 and up processors require a separate SYNC, which has the same + * issues as LL/SC. + */ +#if __mips < 2 +#define MIPS_SET_MIPS2 " .set mips2 \n" +#else +#define MIPS_SET_MIPS2 +#endif + +static __inline__ int +tas(volatile slock_t *lock) +{ + register volatile slock_t *_l = lock; + register int _res; + register int _tmp; + + __asm__ __volatile__( + " .set push \n" + MIPS_SET_MIPS2 + " .set noreorder \n" + " .set nomacro \n" + " ll %0, %2 \n" + " or %1, %0, 1 \n" + " sc %1, %2 \n" + " xori %1, 1 \n" + " or %0, %0, %1 \n" + " sync \n" + " .set pop " +: "=&r" (_res), "=&r" (_tmp), "+R" (*_l) +: /* no inputs */ +: "memory"); + return _res; +} + +/* MIPS S_UNLOCK is almost standard but requires a "sync" instruction */ +#define S_UNLOCK(lock) \ +do \ +{ \ + __asm__ __volatile__( \ + " .set push \n" \ + MIPS_SET_MIPS2 \ + " .set noreorder \n" \ + " .set nomacro \n" \ + " sync \n" \ + " .set pop " \ +: /* no outputs */ \ +: /* no inputs */ \ +: "memory"); \ + *((volatile slock_t *) (lock)) = 0; \ +} while (0) + +#endif /* __mips__ && !__sgi */ + + +#if defined(__m32r__) && defined(HAVE_SYS_TAS_H) /* Renesas' M32R */ +#define HAS_TEST_AND_SET + +#include <sys/tas.h> + +typedef int slock_t; + +#define TAS(lock) tas(lock) + +#endif /* __m32r__ */ + + +#if defined(__sh__) /* Renesas' SuperH */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; + +#define TAS(lock) tas(lock) + +static __inline__ int +tas(volatile slock_t *lock) +{ + register int _res; + + /* + * This asm is coded as if %0 could be any register, but actually SuperH + * restricts the target of xor-immediate to be R0. That's handled by + * the "z" constraint on _res. + */ + __asm__ __volatile__( + " tas.b @%2 \n" + " movt %0 \n" + " xor #1,%0 \n" +: "=z"(_res), "+m"(*lock) +: "r"(lock) +: "memory", "t"); + return _res; +} + +#endif /* __sh__ */ + + +/* These live in s_lock.c, but only for gcc */ + + +#if defined(__m68k__) && !defined(__linux__) /* non-Linux Motorola 68k */ +#define HAS_TEST_AND_SET + +typedef unsigned char slock_t; +#endif + + +/* + * If we have no platform-specific knowledge, but we found that the compiler + * provides __sync_lock_test_and_set(), use that. Prefer the int-width + * version over the char-width version if we have both, on the rather dubious + * grounds that that's known to be more likely to work in the ARM ecosystem. + * (But we dealt with ARM above.) + */ +#if !defined(HAS_TEST_AND_SET) + +#if defined(HAVE_GCC__SYNC_INT32_TAS) +#define HAS_TEST_AND_SET + +#define TAS(lock) tas(lock) + +typedef int slock_t; + +static __inline__ int +tas(volatile slock_t *lock) +{ + return __sync_lock_test_and_set(lock, 1); +} + +#define S_UNLOCK(lock) __sync_lock_release(lock) + +#elif defined(HAVE_GCC__SYNC_CHAR_TAS) +#define HAS_TEST_AND_SET + +#define TAS(lock) tas(lock) + +typedef char slock_t; + +static __inline__ int +tas(volatile slock_t *lock) +{ + return __sync_lock_test_and_set(lock, 1); +} + +#define S_UNLOCK(lock) __sync_lock_release(lock) + +#endif /* HAVE_GCC__SYNC_INT32_TAS */ + +#endif /* !defined(HAS_TEST_AND_SET) */ + + +/* + * Default implementation of S_UNLOCK() for gcc/icc. + * + * Note that this implementation is unsafe for any platform that can reorder + * a memory access (either load or store) after a following store. That + * happens not to be possible on x86 and most legacy architectures (some are + * single-processor!), but many modern systems have weaker memory ordering. + * Those that do must define their own version of S_UNLOCK() rather than + * relying on this one. + */ +#if !defined(S_UNLOCK) +#define S_UNLOCK(lock) \ + do { __asm__ __volatile__("" : : : "memory"); *(lock) = 0; } while (0) +#endif + +#endif /* defined(__GNUC__) || defined(__INTEL_COMPILER) */ + + + +/* + * --------------------------------------------------------------------- + * Platforms that use non-gcc inline assembly: + * --------------------------------------------------------------------- + */ + +#if !defined(HAS_TEST_AND_SET) /* We didn't trigger above, let's try here */ + + +#if defined(__hppa) || defined(__hppa__) /* HP PA-RISC, GCC and HP compilers */ +/* + * HP's PA-RISC + * + * See src/backend/port/hpux/tas.c.template for details about LDCWX. Because + * LDCWX requires a 16-byte-aligned address, we declare slock_t as a 16-byte + * struct. The active word in the struct is whichever has the aligned address; + * the other three words just sit at -1. + * + * When using gcc, we can inline the required assembly code. + */ +#define HAS_TEST_AND_SET + +typedef struct +{ + int sema[4]; +} slock_t; + +#define TAS_ACTIVE_WORD(lock) ((volatile int *) (((uintptr_t) (lock) + 15) & ~15)) + +#if defined(__GNUC__) + +static __inline__ int +tas(volatile slock_t *lock) +{ + volatile int *lockword = TAS_ACTIVE_WORD(lock); + register int lockval; + + __asm__ __volatile__( + " ldcwx 0(0,%2),%0 \n" +: "=r"(lockval), "+m"(*lockword) +: "r"(lockword) +: "memory"); + return (lockval == 0); +} + +/* + * The hppa implementation doesn't follow the rules of this files and provides + * a gcc specific implementation outside of the above defined(__GNUC__). It + * does so to avoid duplication between the HP compiler and gcc. So undefine + * the generic fallback S_UNLOCK from above. + */ +#ifdef S_UNLOCK +#undef S_UNLOCK +#endif +#define S_UNLOCK(lock) \ + do { \ + __asm__ __volatile__("" : : : "memory"); \ + *TAS_ACTIVE_WORD(lock) = -1; \ + } while (0) + +#endif /* __GNUC__ */ + +#define S_INIT_LOCK(lock) \ + do { \ + volatile slock_t *lock_ = (lock); \ + lock_->sema[0] = -1; \ + lock_->sema[1] = -1; \ + lock_->sema[2] = -1; \ + lock_->sema[3] = -1; \ + } while (0) + +#define S_LOCK_FREE(lock) (*TAS_ACTIVE_WORD(lock) != 0) + +#endif /* __hppa || __hppa__ */ + + +#if defined(__hpux) && defined(__ia64) && !defined(__GNUC__) +/* + * HP-UX on Itanium, non-gcc/icc compiler + * + * We assume that the compiler enforces strict ordering of loads/stores on + * volatile data (see comments on the gcc-version earlier in this file). + * Note that this assumption does *not* hold if you use the + * +Ovolatile=__unordered option on the HP-UX compiler, so don't do that. + * + * See also Implementing Spinlocks on the Intel Itanium Architecture and + * PA-RISC, by Tor Ekqvist and David Graves, for more information. As of + * this writing, version 1.0 of the manual is available at: + * http://h21007.www2.hp.com/portal/download/files/unprot/itanium/spinlocks.pdf + */ +#define HAS_TEST_AND_SET + +typedef unsigned int slock_t; + +#include <ia64/sys/inline.h> +#define TAS(lock) _Asm_xchg(_SZ_W, lock, 1, _LDHINT_NONE) +/* On IA64, it's a win to use a non-locking test before the xchg proper */ +#define TAS_SPIN(lock) (*(lock) ? 1 : TAS(lock)) +#define S_UNLOCK(lock) \ + do { _Asm_mf(); (*(lock)) = 0; } while (0) + +#endif /* HPUX on IA64, non gcc/icc */ + +#if defined(_AIX) /* AIX */ +/* + * AIX (POWER) + */ +#define HAS_TEST_AND_SET + +#include <sys/atomic_op.h> + +typedef int slock_t; + +#define TAS(lock) _check_lock((slock_t *) (lock), 0, 1) +#define S_UNLOCK(lock) _clear_lock((slock_t *) (lock), 0) +#endif /* _AIX */ + + +/* These are in sunstudio_(sparc|x86).s */ + +#if defined(__SUNPRO_C) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc)) +#define HAS_TEST_AND_SET + +#if defined(__i386) || defined(__x86_64__) || defined(__sparcv9) || defined(__sparcv8plus) +typedef unsigned int slock_t; +#else +typedef unsigned char slock_t; +#endif + +extern slock_t pg_atomic_cas(volatile slock_t *lock, slock_t with, + slock_t cmp); + +#define TAS(a) (pg_atomic_cas((a), 1, 0) != 0) +#endif + + +#ifdef _MSC_VER +typedef LONG slock_t; + +#define HAS_TEST_AND_SET +#define TAS(lock) (InterlockedCompareExchange(lock, 1, 0)) + +#define SPIN_DELAY() spin_delay() + +/* If using Visual C++ on Win64, inline assembly is unavailable. + * Use a _mm_pause intrinsic instead of rep nop. + */ +#if defined(_WIN64) +static __forceinline void +spin_delay(void) +{ + _mm_pause(); +} +#else +static __forceinline void +spin_delay(void) +{ + /* See comment for gcc code. Same code, MASM syntax */ + __asm rep nop; +} +#endif + +#include <intrin.h> +#pragma intrinsic(_ReadWriteBarrier) + +#define S_UNLOCK(lock) \ + do { _ReadWriteBarrier(); (*(lock)) = 0; } while (0) + +#endif + + +#endif /* !defined(HAS_TEST_AND_SET) */ + + +/* Blow up if we didn't have any way to do spinlocks */ +#ifndef HAS_TEST_AND_SET +#error PostgreSQL does not have native spinlock support on this platform. To continue the compilation, rerun configure using --disable-spinlocks. However, performance will be poor. Please report this to pgsql-bugs@lists.postgresql.org. +#endif + + +#else /* !HAVE_SPINLOCKS */ + + +/* + * Fake spinlock implementation using semaphores --- slow and prone + * to fall foul of kernel limits on number of semaphores, so don't use this + * unless you must! The subroutines appear in spin.c. + */ +typedef int slock_t; + +extern bool s_lock_free_sema(volatile slock_t *lock); +extern void s_unlock_sema(volatile slock_t *lock); +extern void s_init_lock_sema(volatile slock_t *lock, bool nested); +extern int tas_sema(volatile slock_t *lock); + +#define S_LOCK_FREE(lock) s_lock_free_sema(lock) +#define S_UNLOCK(lock) s_unlock_sema(lock) +#define S_INIT_LOCK(lock) s_init_lock_sema(lock, false) +#define TAS(lock) tas_sema(lock) + + +#endif /* HAVE_SPINLOCKS */ + + +/* + * Default Definitions - override these above as needed. + */ + +#if !defined(S_LOCK) +#define S_LOCK(lock) \ + (TAS(lock) ? s_lock((lock), __FILE__, __LINE__, PG_FUNCNAME_MACRO) : 0) +#endif /* S_LOCK */ + +#if !defined(S_LOCK_FREE) +#define S_LOCK_FREE(lock) (*(lock) == 0) +#endif /* S_LOCK_FREE */ + +#if !defined(S_UNLOCK) +/* + * Our default implementation of S_UNLOCK is essentially *(lock) = 0. This + * is unsafe if the platform can reorder a memory access (either load or + * store) after a following store; platforms where this is possible must + * define their own S_UNLOCK. But CPU reordering is not the only concern: + * if we simply defined S_UNLOCK() as an inline macro, the compiler might + * reorder instructions from inside the critical section to occur after the + * lock release. Since the compiler probably can't know what the external + * function s_unlock is doing, putting the same logic there should be adequate. + * A sufficiently-smart globally optimizing compiler could break that + * assumption, though, and the cost of a function call for every spinlock + * release may hurt performance significantly, so we use this implementation + * only for platforms where we don't know of a suitable intrinsic. For the + * most part, those are relatively obscure platform/compiler combinations to + * which the PostgreSQL project does not have access. + */ +#define USE_DEFAULT_S_UNLOCK +extern void s_unlock(volatile slock_t *lock); +#define S_UNLOCK(lock) s_unlock(lock) +#endif /* S_UNLOCK */ + +#if !defined(S_INIT_LOCK) +#define S_INIT_LOCK(lock) S_UNLOCK(lock) +#endif /* S_INIT_LOCK */ + +#if !defined(SPIN_DELAY) +#define SPIN_DELAY() ((void) 0) +#endif /* SPIN_DELAY */ + +#if !defined(TAS) +extern int tas(volatile slock_t *lock); /* in port/.../tas.s, or + * s_lock.c */ + +#define TAS(lock) tas(lock) +#endif /* TAS */ + +#if !defined(TAS_SPIN) +#define TAS_SPIN(lock) TAS(lock) +#endif /* TAS_SPIN */ + +extern PGDLLIMPORT slock_t dummy_spinlock; + +/* + * Platform-independent out-of-line support routines + */ +extern int s_lock(volatile slock_t *lock, const char *file, int line, const char *func); + +/* Support for dynamic adjustment of spins_per_delay */ +#define DEFAULT_SPINS_PER_DELAY 100 + +extern void set_spins_per_delay(int shared_spins_per_delay); +extern int update_spins_per_delay(int shared_spins_per_delay); + +/* + * Support for spin delay which is useful in various places where + * spinlock-like procedures take place. + */ +typedef struct +{ + int spins; + int delays; + int cur_delay; + const char *file; + int line; + const char *func; +} SpinDelayStatus; + +static inline void +init_spin_delay(SpinDelayStatus *status, + const char *file, int line, const char *func) +{ + status->spins = 0; + status->delays = 0; + status->cur_delay = 0; + status->file = file; + status->line = line; + status->func = func; +} + +#define init_local_spin_delay(status) init_spin_delay(status, __FILE__, __LINE__, PG_FUNCNAME_MACRO) +extern void perform_spin_delay(SpinDelayStatus *status); +extern void finish_spin_delay(SpinDelayStatus *status); + +#endif /* S_LOCK_H */ diff --git a/src/include/storage/sharedfileset.h b/src/include/storage/sharedfileset.h new file mode 100644 index 0000000..b1cde36 --- /dev/null +++ b/src/include/storage/sharedfileset.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * sharedfileset.h + * Shared temporary file management. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/sharedfileset.h + * + *------------------------------------------------------------------------- + */ + +#ifndef SHAREDFILESET_H +#define SHAREDFILESET_H + +#include "storage/dsm.h" +#include "storage/fd.h" +#include "storage/fileset.h" +#include "storage/spin.h" + +/* + * A set of temporary files that can be shared by multiple backends. + */ +typedef struct SharedFileSet +{ + FileSet fs; + slock_t mutex; /* mutex protecting the reference count */ + int refcnt; /* number of attached backends */ +} SharedFileSet; + +extern void SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg); +extern void SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg); +extern void SharedFileSetDeleteAll(SharedFileSet *fileset); + +#endif diff --git a/src/include/storage/shm_mq.h b/src/include/storage/shm_mq.h new file mode 100644 index 0000000..b6fe687 --- /dev/null +++ b/src/include/storage/shm_mq.h @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------- + * + * shm_mq.h + * single-reader, single-writer shared memory message queue + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/shm_mq.h + * + *------------------------------------------------------------------------- + */ +#ifndef SHM_MQ_H +#define SHM_MQ_H + +#include "postmaster/bgworker.h" +#include "storage/dsm.h" +#include "storage/proc.h" + +/* The queue itself, in shared memory. */ +struct shm_mq; +typedef struct shm_mq shm_mq; + +/* Backend-private state. */ +struct shm_mq_handle; +typedef struct shm_mq_handle shm_mq_handle; + +/* Descriptors for a single write spanning multiple locations. */ +typedef struct +{ + const char *data; + Size len; +} shm_mq_iovec; + +/* Possible results of a send or receive operation. */ +typedef enum +{ + SHM_MQ_SUCCESS, /* Sent or received a message. */ + SHM_MQ_WOULD_BLOCK, /* Not completed; retry later. */ + SHM_MQ_DETACHED /* Other process has detached queue. */ +} shm_mq_result; + +/* + * Primitives to create a queue and set the sender and receiver. + * + * Both the sender and the receiver must be set before any messages are read + * or written, but they need not be set by the same process. Each must be + * set exactly once. + */ +extern shm_mq *shm_mq_create(void *address, Size size); +extern void shm_mq_set_receiver(shm_mq *mq, PGPROC *); +extern void shm_mq_set_sender(shm_mq *mq, PGPROC *); + +/* Accessor methods for sender and receiver. */ +extern PGPROC *shm_mq_get_receiver(shm_mq *); +extern PGPROC *shm_mq_get_sender(shm_mq *); + +/* Set up backend-local queue state. */ +extern shm_mq_handle *shm_mq_attach(shm_mq *mq, dsm_segment *seg, + BackgroundWorkerHandle *handle); + +/* Associate worker handle with shm_mq. */ +extern void shm_mq_set_handle(shm_mq_handle *, BackgroundWorkerHandle *); + +/* Break connection, release handle resources. */ +extern void shm_mq_detach(shm_mq_handle *mqh); + +/* Get the shm_mq from handle. */ +extern shm_mq *shm_mq_get_queue(shm_mq_handle *mqh); + +/* Send or receive messages. */ +extern shm_mq_result shm_mq_send(shm_mq_handle *mqh, + Size nbytes, const void *data, bool nowait, + bool force_flush); +extern shm_mq_result shm_mq_sendv(shm_mq_handle *mqh, shm_mq_iovec *iov, + int iovcnt, bool nowait, bool force_flush); +extern shm_mq_result shm_mq_receive(shm_mq_handle *mqh, + Size *nbytesp, void **datap, bool nowait); + +/* Wait for our counterparty to attach to the queue. */ +extern shm_mq_result shm_mq_wait_for_attach(shm_mq_handle *mqh); + +/* Smallest possible queue. */ +extern PGDLLIMPORT const Size shm_mq_minimum_size; + +#endif /* SHM_MQ_H */ diff --git a/src/include/storage/shm_toc.h b/src/include/storage/shm_toc.h new file mode 100644 index 0000000..153a57c --- /dev/null +++ b/src/include/storage/shm_toc.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * shm_toc.h + * shared memory segment table of contents + * + * This is intended to provide a simple way to divide a chunk of shared + * memory (probably dynamic shared memory allocated via dsm_create) into + * a number of regions and keep track of the addresses of those regions or + * key data structures within those regions. This is not intended to + * scale to a large number of keys and will perform poorly if used that + * way; if you need a large number of pointers, store them within some + * other data structure within the segment and only put the pointer to + * the data structure itself in the table of contents. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/shm_toc.h + * + *------------------------------------------------------------------------- + */ +#ifndef SHM_TOC_H +#define SHM_TOC_H + +#include "storage/shmem.h" /* for add_size() */ + +/* shm_toc is an opaque type known only within shm_toc.c */ +typedef struct shm_toc shm_toc; + +extern shm_toc *shm_toc_create(uint64 magic, void *address, Size nbytes); +extern shm_toc *shm_toc_attach(uint64 magic, void *address); +extern void *shm_toc_allocate(shm_toc *toc, Size nbytes); +extern Size shm_toc_freespace(shm_toc *toc); +extern void shm_toc_insert(shm_toc *toc, uint64 key, void *address); +extern void *shm_toc_lookup(shm_toc *toc, uint64 key, bool noError); + +/* + * Tools for estimating how large a chunk of shared memory will be needed + * to store a TOC and its dependent objects. Note: we don't really support + * large numbers of keys, but it's convenient to declare number_of_keys + * as a Size anyway. + */ +typedef struct +{ + Size space_for_chunks; + Size number_of_keys; +} shm_toc_estimator; + +#define shm_toc_initialize_estimator(e) \ + ((e)->space_for_chunks = 0, (e)->number_of_keys = 0) +#define shm_toc_estimate_chunk(e, sz) \ + ((e)->space_for_chunks = add_size((e)->space_for_chunks, BUFFERALIGN(sz))) +#define shm_toc_estimate_keys(e, cnt) \ + ((e)->number_of_keys = add_size((e)->number_of_keys, cnt)) + +extern Size shm_toc_estimate(shm_toc_estimator *e); + +#endif /* SHM_TOC_H */ diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h new file mode 100644 index 0000000..de9e7c6 --- /dev/null +++ b/src/include/storage/shmem.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * shmem.h + * shared memory management structures + * + * Historical note: + * A long time ago, Postgres' shared memory region was allowed to be mapped + * at a different address in each process, and shared memory "pointers" were + * passed around as offsets relative to the start of the shared memory region. + * That is no longer the case: each process must map the shared memory region + * at the same address. This means shared memory pointers can be passed + * around directly between different processes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/shmem.h + * + *------------------------------------------------------------------------- + */ +#ifndef SHMEM_H +#define SHMEM_H + +#include "utils/hsearch.h" + + +/* shmqueue.c */ +typedef struct SHM_QUEUE +{ + struct SHM_QUEUE *prev; + struct SHM_QUEUE *next; +} SHM_QUEUE; + +/* shmem.c */ +extern void InitShmemAccess(void *seghdr); +extern void InitShmemAllocation(void); +extern void *ShmemAlloc(Size size); +extern void *ShmemAllocNoError(Size size); +extern void *ShmemAllocUnlocked(Size size); +extern bool ShmemAddrIsValid(const void *addr); +extern void InitShmemIndex(void); +extern HTAB *ShmemInitHash(const char *name, long init_size, long max_size, + HASHCTL *infoP, int hash_flags); +extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr); +extern Size add_size(Size s1, Size s2); +extern Size mul_size(Size s1, Size s2); + +/* ipci.c */ +extern void RequestAddinShmemSpace(Size size); + +/* size constants for the shmem index table */ + /* max size of data structure string name */ +#define SHMEM_INDEX_KEYSIZE (48) + /* estimated size of the shmem index table (not a hard limit) */ +#define SHMEM_INDEX_SIZE (64) + +/* this is a hash bucket in the shmem index table */ +typedef struct +{ + char key[SHMEM_INDEX_KEYSIZE]; /* string name */ + void *location; /* location in shared mem */ + Size size; /* # bytes requested for the structure */ + Size allocated_size; /* # bytes actually allocated */ +} ShmemIndexEnt; + +/* + * prototypes for functions in shmqueue.c + */ +extern void SHMQueueInit(SHM_QUEUE *queue); +extern void SHMQueueElemInit(SHM_QUEUE *queue); +extern void SHMQueueDelete(SHM_QUEUE *queue); +extern void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem); +extern void SHMQueueInsertAfter(SHM_QUEUE *queue, SHM_QUEUE *elem); +extern Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, + Size linkOffset); +extern Pointer SHMQueuePrev(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, + Size linkOffset); +extern bool SHMQueueEmpty(const SHM_QUEUE *queue); +extern bool SHMQueueIsDetached(const SHM_QUEUE *queue); + +#endif /* SHMEM_H */ diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h new file mode 100644 index 0000000..e7cd456 --- /dev/null +++ b/src/include/storage/sinval.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- + * + * sinval.h + * POSTGRES shared cache invalidation communication definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/sinval.h + * + *------------------------------------------------------------------------- + */ +#ifndef SINVAL_H +#define SINVAL_H + +#include <signal.h> + +#include "storage/relfilenode.h" + +/* + * We support several types of shared-invalidation messages: + * * invalidate a specific tuple in a specific catcache + * * invalidate all catcache entries from a given system catalog + * * invalidate a relcache entry for a specific logical relation + * * invalidate all relcache entries + * * invalidate an smgr cache entry for a specific physical relation + * * invalidate the mapped-relation mapping for a given database + * * invalidate any saved snapshot that might be used to scan a given relation + * More types could be added if needed. The message type is identified by + * the first "int8" field of the message struct. Zero or positive means a + * specific-catcache inval message (and also serves as the catcache ID field). + * Negative values identify the other message types, as per codes below. + * + * Catcache inval events are initially driven by detecting tuple inserts, + * updates and deletions in system catalogs (see CacheInvalidateHeapTuple). + * An update can generate two inval events, one for the old tuple and one for + * the new, but this is reduced to one event if the tuple's hash key doesn't + * change. Note that the inval events themselves don't actually say whether + * the tuple is being inserted or deleted. Also, since we transmit only a + * hash key, there is a small risk of unnecessary invalidations due to chance + * matches of hash keys. + * + * Note that some system catalogs have multiple caches on them (with different + * indexes). On detecting a tuple invalidation in such a catalog, separate + * catcache inval messages must be generated for each of its caches, since + * the hash keys will generally be different. + * + * Catcache, relcache, and snapshot invalidations are transactional, and so + * are sent to other backends upon commit. Internally to the generating + * backend, they are also processed at CommandCounterIncrement so that later + * commands in the same transaction see the new state. The generating backend + * also has to process them at abort, to flush out any cache state it's loaded + * from no-longer-valid entries. + * + * smgr and relation mapping invalidations are non-transactional: they are + * sent immediately when the underlying file change is made. + */ + +typedef struct +{ + int8 id; /* cache ID --- must be first */ + Oid dbId; /* database ID, or 0 if a shared relation */ + uint32 hashValue; /* hash value of key for this catcache */ +} SharedInvalCatcacheMsg; + +#define SHAREDINVALCATALOG_ID (-1) + +typedef struct +{ + int8 id; /* type field --- must be first */ + Oid dbId; /* database ID, or 0 if a shared catalog */ + Oid catId; /* ID of catalog whose contents are invalid */ +} SharedInvalCatalogMsg; + +#define SHAREDINVALRELCACHE_ID (-2) + +typedef struct +{ + int8 id; /* type field --- must be first */ + Oid dbId; /* database ID, or 0 if a shared relation */ + Oid relId; /* relation ID, or 0 if whole relcache */ +} SharedInvalRelcacheMsg; + +#define SHAREDINVALSMGR_ID (-3) + +typedef struct +{ + /* note: field layout chosen to pack into 16 bytes */ + int8 id; /* type field --- must be first */ + int8 backend_hi; /* high bits of backend ID, if temprel */ + uint16 backend_lo; /* low bits of backend ID, if temprel */ + RelFileNode rnode; /* spcNode, dbNode, relNode */ +} SharedInvalSmgrMsg; + +#define SHAREDINVALRELMAP_ID (-4) + +typedef struct +{ + int8 id; /* type field --- must be first */ + Oid dbId; /* database ID, or 0 for shared catalogs */ +} SharedInvalRelmapMsg; + +#define SHAREDINVALSNAPSHOT_ID (-5) + +typedef struct +{ + int8 id; /* type field --- must be first */ + Oid dbId; /* database ID, or 0 if a shared relation */ + Oid relId; /* relation ID */ +} SharedInvalSnapshotMsg; + +typedef union +{ + int8 id; /* type field --- must be first */ + SharedInvalCatcacheMsg cc; + SharedInvalCatalogMsg cat; + SharedInvalRelcacheMsg rc; + SharedInvalSmgrMsg sm; + SharedInvalRelmapMsg rm; + SharedInvalSnapshotMsg sn; +} SharedInvalidationMessage; + + +/* Counter of messages processed; don't worry about overflow. */ +extern PGDLLIMPORT uint64 SharedInvalidMessageCounter; + +extern PGDLLIMPORT volatile sig_atomic_t catchupInterruptPending; + +extern void SendSharedInvalidMessages(const SharedInvalidationMessage *msgs, + int n); +extern void ReceiveSharedInvalidMessages(void (*invalFunction) (SharedInvalidationMessage *msg), + void (*resetFunction) (void)); + +/* signal handler for catchup events (PROCSIG_CATCHUP_INTERRUPT) */ +extern void HandleCatchupInterrupt(void); + +/* + * enable/disable processing of catchup events directly from signal handler. + * The enable routine first performs processing of any catchup events that + * have occurred since the last disable. + */ +extern void ProcessCatchupInterrupt(void); + +extern int xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs, + bool *RelcacheInitFileInval); +extern void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, + int nmsgs, bool RelcacheInitFileInval, + Oid dbid, Oid tsid); + +extern void LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg); + +#endif /* SINVAL_H */ diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h new file mode 100644 index 0000000..91e2418 --- /dev/null +++ b/src/include/storage/sinvaladt.h @@ -0,0 +1,43 @@ +/*------------------------------------------------------------------------- + * + * sinvaladt.h + * POSTGRES shared cache invalidation data manager. + * + * The shared cache invalidation manager is responsible for transmitting + * invalidation messages between backends. Any message sent by any backend + * must be delivered to all already-running backends before it can be + * forgotten. (If we run out of space, we instead deliver a "RESET" + * message to backends that have fallen too far behind.) + * + * The struct type SharedInvalidationMessage, defining the contents of + * a single message, is defined in sinval.h. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/sinvaladt.h + * + *------------------------------------------------------------------------- + */ +#ifndef SINVALADT_H +#define SINVALADT_H + +#include "storage/lock.h" +#include "storage/sinval.h" + +/* + * prototypes for functions in sinvaladt.c + */ +extern Size SInvalShmemSize(void); +extern void CreateSharedInvalidationState(void); +extern void SharedInvalBackendInit(bool sendOnly); +extern PGPROC *BackendIdGetProc(int backendID); +extern void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin); + +extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n); +extern int SIGetDataEntries(SharedInvalidationMessage *data, int datasize); +extern void SICleanupQueue(bool callerHasWriteLock, int minFree); + +extern LocalTransactionId GetNextLocalTransactionId(void); + +#endif /* SINVALADT_H */ diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h new file mode 100644 index 0000000..6b63c60 --- /dev/null +++ b/src/include/storage/smgr.h @@ -0,0 +1,111 @@ +/*------------------------------------------------------------------------- + * + * smgr.h + * storage manager switch public interface declarations. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/smgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef SMGR_H +#define SMGR_H + +#include "lib/ilist.h" +#include "storage/block.h" +#include "storage/relfilenode.h" + +/* + * smgr.c maintains a table of SMgrRelation objects, which are essentially + * cached file handles. An SMgrRelation is created (if not already present) + * by smgropen(), and destroyed by smgrclose(). Note that neither of these + * operations imply I/O, they just create or destroy a hashtable entry. + * (But smgrclose() may release associated resources, such as OS-level file + * descriptors.) + * + * An SMgrRelation may have an "owner", which is just a pointer to it from + * somewhere else; smgr.c will clear this pointer if the SMgrRelation is + * closed. We use this to avoid dangling pointers from relcache to smgr + * without having to make the smgr explicitly aware of relcache. There + * can't be more than one "owner" pointer per SMgrRelation, but that's + * all we need. + * + * SMgrRelations that do not have an "owner" are considered to be transient, + * and are deleted at end of transaction. + */ +typedef struct SMgrRelationData +{ + /* rnode is the hashtable lookup key, so it must be first! */ + RelFileNodeBackend smgr_rnode; /* relation physical identifier */ + + /* pointer to owning pointer, or NULL if none */ + struct SMgrRelationData **smgr_owner; + + /* + * The following fields are reset to InvalidBlockNumber upon a cache flush + * event, and hold the last known size for each fork. This information is + * currently only reliable during recovery, since there is no cache + * invalidation for fork extension. + */ + BlockNumber smgr_targblock; /* current insertion target block */ + BlockNumber smgr_cached_nblocks[MAX_FORKNUM + 1]; /* last known size */ + + /* additional public fields may someday exist here */ + + /* + * Fields below here are intended to be private to smgr.c and its + * submodules. Do not touch them from elsewhere. + */ + int smgr_which; /* storage manager selector */ + + /* + * for md.c; per-fork arrays of the number of open segments + * (md_num_open_segs) and the segments themselves (md_seg_fds). + */ + int md_num_open_segs[MAX_FORKNUM + 1]; + struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1]; + + /* if unowned, list link in list of all unowned SMgrRelations */ + dlist_node node; +} SMgrRelationData; + +typedef SMgrRelationData *SMgrRelation; + +#define SmgrIsTemp(smgr) \ + RelFileNodeBackendIsTemp((smgr)->smgr_rnode) + +extern void smgrinit(void); +extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend); +extern bool smgrexists(SMgrRelation reln, ForkNumber forknum); +extern void smgrsetowner(SMgrRelation *owner, SMgrRelation reln); +extern void smgrclearowner(SMgrRelation *owner, SMgrRelation reln); +extern void smgrclose(SMgrRelation reln); +extern void smgrcloseall(void); +extern void smgrclosenode(RelFileNodeBackend rnode); +extern void smgrrelease(SMgrRelation reln); +extern void smgrreleaseall(void); +extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo); +extern void smgrdosyncall(SMgrRelation *rels, int nrels); +extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo); +extern void smgrextend(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer, bool skipFsync); +extern bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum); +extern void smgrread(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer); +extern void smgrwrite(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, char *buffer, bool skipFsync); +extern void smgrwriteback(SMgrRelation reln, ForkNumber forknum, + BlockNumber blocknum, BlockNumber nblocks); +extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum); +extern BlockNumber smgrnblocks_cached(SMgrRelation reln, ForkNumber forknum); +extern void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, + int nforks, BlockNumber *nblocks); +extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); +extern void AtEOXact_SMgr(void); +extern bool ProcessBarrierSmgrRelease(void); + +#endif /* SMGR_H */ diff --git a/src/include/storage/spin.h b/src/include/storage/spin.h new file mode 100644 index 0000000..7031f1d --- /dev/null +++ b/src/include/storage/spin.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * spin.h + * Hardware-independent implementation of spinlocks. + * + * + * The hardware-independent interface to spinlocks is defined by the + * typedef "slock_t" and these macros: + * + * void SpinLockInit(volatile slock_t *lock) + * Initialize a spinlock (to the unlocked state). + * + * void SpinLockAcquire(volatile slock_t *lock) + * Acquire a spinlock, waiting if necessary. + * Time out and abort() if unable to acquire the lock in a + * "reasonable" amount of time --- typically ~ 1 minute. + * + * void SpinLockRelease(volatile slock_t *lock) + * Unlock a previously acquired lock. + * + * bool SpinLockFree(slock_t *lock) + * Tests if the lock is free. Returns true if free, false if locked. + * This does *not* change the state of the lock. + * + * Callers must beware that the macro argument may be evaluated multiple + * times! + * + * Load and store operations in calling code are guaranteed not to be + * reordered with respect to these operations, because they include a + * compiler barrier. (Before PostgreSQL 9.5, callers needed to use a + * volatile qualifier to access data protected by spinlocks.) + * + * Keep in mind the coding rule that spinlocks must not be held for more + * than a few instructions. In particular, we assume it is not possible + * for a CHECK_FOR_INTERRUPTS() to occur while holding a spinlock, and so + * it is not necessary to do HOLD/RESUME_INTERRUPTS() in these macros. + * + * These macros are implemented in terms of hardware-dependent macros + * supplied by s_lock.h. There is not currently any extra functionality + * added by this header, but there has been in the past and may someday + * be again. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/spin.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPIN_H +#define SPIN_H + +#include "storage/s_lock.h" +#ifndef HAVE_SPINLOCKS +#include "storage/pg_sema.h" +#endif + + +#define SpinLockInit(lock) S_INIT_LOCK(lock) + +#define SpinLockAcquire(lock) S_LOCK(lock) + +#define SpinLockRelease(lock) S_UNLOCK(lock) + +#define SpinLockFree(lock) S_LOCK_FREE(lock) + + +extern int SpinlockSemas(void); +extern Size SpinlockSemaSize(void); + +#ifndef HAVE_SPINLOCKS +extern void SpinlockSemaInit(void); +extern PGDLLIMPORT PGSemaphore *SpinlockSemaArray; +#endif + +#endif /* SPIN_H */ diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h new file mode 100644 index 0000000..6a77632 --- /dev/null +++ b/src/include/storage/standby.h @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + * + * standby.h + * Definitions for hot standby mode. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/standby.h + * + *------------------------------------------------------------------------- + */ +#ifndef STANDBY_H +#define STANDBY_H + +#include "datatype/timestamp.h" +#include "storage/lock.h" +#include "storage/procsignal.h" +#include "storage/relfilenode.h" +#include "storage/standbydefs.h" + +/* User-settable GUC parameters */ +extern PGDLLIMPORT int vacuum_defer_cleanup_age; +extern PGDLLIMPORT int max_standby_archive_delay; +extern PGDLLIMPORT int max_standby_streaming_delay; +extern PGDLLIMPORT bool log_recovery_conflict_waits; + +extern void InitRecoveryTransactionEnvironment(void); +extern void ShutdownRecoveryTransactionEnvironment(void); + +extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, + RelFileNode node); +extern void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId latestRemovedFullXid, + RelFileNode node); +extern void ResolveRecoveryConflictWithTablespace(Oid tsid); +extern void ResolveRecoveryConflictWithDatabase(Oid dbid); + +extern void ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict); +extern void ResolveRecoveryConflictWithBufferPin(void); +extern void CheckRecoveryConflictDeadlock(void); +extern void StandbyDeadLockHandler(void); +extern void StandbyTimeoutHandler(void); +extern void StandbyLockTimeoutHandler(void); +extern void LogRecoveryConflict(ProcSignalReason reason, TimestampTz wait_start, + TimestampTz cur_ts, VirtualTransactionId *wait_list, + bool still_waiting); + +/* + * Standby Rmgr (RM_STANDBY_ID) + * + * Standby recovery manager exists to perform actions that are required + * to make hot standby work. That includes logging AccessExclusiveLocks taken + * by transactions and running-xacts snapshots. + */ +extern void StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid); +extern void StandbyReleaseLockTree(TransactionId xid, + int nsubxids, TransactionId *subxids); +extern void StandbyReleaseAllLocks(void); +extern void StandbyReleaseOldLocks(TransactionId oldxid); + +#define MinSizeOfXactRunningXacts offsetof(xl_running_xacts, xids) + + +/* + * Declarations for GetRunningTransactionData(). Similar to Snapshots, but + * not quite. This has nothing at all to do with visibility on this server, + * so this is completely separate from snapmgr.c and snapmgr.h. + * This data is important for creating the initial snapshot state on a + * standby server. We need lots more information than a normal snapshot, + * hence we use a specific data structure for our needs. This data + * is written to WAL as a separate record immediately after each + * checkpoint. That means that wherever we start a standby from we will + * almost immediately see the data we need to begin executing queries. + */ + +typedef struct RunningTransactionsData +{ + int xcnt; /* # of xact ids in xids[] */ + int subxcnt; /* # of subxact ids in xids[] */ + bool subxid_overflow; /* snapshot overflowed, subxids missing */ + TransactionId nextXid; /* xid from ShmemVariableCache->nextXid */ + TransactionId oldestRunningXid; /* *not* oldestXmin */ + TransactionId latestCompletedXid; /* so we can set xmax */ + + TransactionId *xids; /* array of (sub)xids still running */ +} RunningTransactionsData; + +typedef RunningTransactionsData *RunningTransactions; + +extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid); +extern void LogAccessExclusiveLockPrepare(void); + +extern XLogRecPtr LogStandbySnapshot(void); +extern void LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, + bool relcacheInitFileInval); + +#endif /* STANDBY_H */ diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h new file mode 100644 index 0000000..c0234b6 --- /dev/null +++ b/src/include/storage/standbydefs.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * standbydefs.h + * Frontend exposed definitions for hot standby mode. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/standbydefs.h + * + *------------------------------------------------------------------------- + */ +#ifndef STANDBYDEFS_H +#define STANDBYDEFS_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" +#include "storage/lockdefs.h" +#include "storage/sinval.h" + +/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */ +extern void standby_redo(XLogReaderState *record); +extern void standby_desc(StringInfo buf, XLogReaderState *record); +extern const char *standby_identify(uint8 info); +extern void standby_desc_invalidations(StringInfo buf, + int nmsgs, SharedInvalidationMessage *msgs, + Oid dbId, Oid tsId, + bool relcacheInitFileInval); + +/* + * XLOG message types + */ +#define XLOG_STANDBY_LOCK 0x00 +#define XLOG_RUNNING_XACTS 0x10 +#define XLOG_INVALIDATIONS 0x20 + +typedef struct xl_standby_locks +{ + int nlocks; /* number of entries in locks array */ + xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER]; +} xl_standby_locks; + +/* + * When we write running xact data to WAL, we use this structure. + */ +typedef struct xl_running_xacts +{ + int xcnt; /* # of xact ids in xids[] */ + int subxcnt; /* # of subxact ids in xids[] */ + bool subxid_overflow; /* snapshot overflowed, subxids missing */ + TransactionId nextXid; /* xid from ShmemVariableCache->nextXid */ + TransactionId oldestRunningXid; /* *not* oldestXmin */ + TransactionId latestCompletedXid; /* so we can set xmax */ + + TransactionId xids[FLEXIBLE_ARRAY_MEMBER]; +} xl_running_xacts; + +/* + * Invalidations for standby, currently only when transactions without an + * assigned xid commit. + */ +typedef struct xl_invalidations +{ + Oid dbId; /* MyDatabaseId */ + Oid tsId; /* MyDatabaseTableSpace */ + bool relcacheInitFileInval; /* invalidate relcache init files */ + int nmsgs; /* number of shared inval msgs */ + SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER]; +} xl_invalidations; + +#define MinSizeOfInvalidations offsetof(xl_invalidations, msgs) + +#endif /* STANDBYDEFS_H */ diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h new file mode 100644 index 0000000..9737e1e --- /dev/null +++ b/src/include/storage/sync.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * sync.h + * File synchronization management code. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/sync.h + * + *------------------------------------------------------------------------- + */ +#ifndef SYNC_H +#define SYNC_H + +#include "storage/relfilenode.h" + +/* + * Type of sync request. These are used to manage the set of pending + * requests to call a sync handler's sync or unlink functions at the next + * checkpoint. + */ +typedef enum SyncRequestType +{ + SYNC_REQUEST, /* schedule a call of sync function */ + SYNC_UNLINK_REQUEST, /* schedule a call of unlink function */ + SYNC_FORGET_REQUEST, /* forget all calls for a tag */ + SYNC_FILTER_REQUEST /* forget all calls satisfying match fn */ +} SyncRequestType; + +/* + * Which set of functions to use to handle a given request. The values of + * the enumerators must match the indexes of the function table in sync.c. + */ +typedef enum SyncRequestHandler +{ + SYNC_HANDLER_MD = 0, + SYNC_HANDLER_CLOG, + SYNC_HANDLER_COMMIT_TS, + SYNC_HANDLER_MULTIXACT_OFFSET, + SYNC_HANDLER_MULTIXACT_MEMBER, + SYNC_HANDLER_NONE +} SyncRequestHandler; + +/* + * A tag identifying a file. Currently it has the members required for md.c's + * usage, but sync.c has no knowledge of the internal structure, and it is + * liable to change as required by future handlers. + */ +typedef struct FileTag +{ + int16 handler; /* SyncRequestHandler value, saving space */ + int16 forknum; /* ForkNumber, saving space */ + RelFileNode rnode; + uint32 segno; +} FileTag; + +extern void InitSync(void); +extern void SyncPreCheckpoint(void); +extern void SyncPostCheckpoint(void); +extern void ProcessSyncRequests(void); +extern void RememberSyncRequest(const FileTag *ftag, SyncRequestType type); +extern bool RegisterSyncRequest(const FileTag *ftag, SyncRequestType type, + bool retryOnError); + +#endif /* SYNC_H */ diff --git a/src/include/tcop/cmdtag.h b/src/include/tcop/cmdtag.h new file mode 100644 index 0000000..b9e8992 --- /dev/null +++ b/src/include/tcop/cmdtag.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * cmdtag.h + * Declarations for commandtag names and enumeration. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/cmdtag.h + * + *------------------------------------------------------------------------- + */ +#ifndef CMDTAG_H +#define CMDTAG_H + + +#define PG_CMDTAG(tag, name, evtrgok, rwrok, rowcnt) \ + tag, + +typedef enum CommandTag +{ +#include "tcop/cmdtaglist.h" + COMMAND_TAG_NEXTTAG +} CommandTag; + +#undef PG_CMDTAG + +typedef struct QueryCompletion +{ + CommandTag commandTag; + uint64 nprocessed; +} QueryCompletion; + + +static inline void +SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, + uint64 nprocessed) +{ + qc->commandTag = commandTag; + qc->nprocessed = nprocessed; +} + +static inline void +CopyQueryCompletion(QueryCompletion *dst, const QueryCompletion *src) +{ + dst->commandTag = src->commandTag; + dst->nprocessed = src->nprocessed; +} + + +extern void InitializeQueryCompletion(QueryCompletion *qc); +extern const char *GetCommandTagName(CommandTag commandTag); +extern bool command_tag_display_rowcount(CommandTag commandTag); +extern bool command_tag_event_trigger_ok(CommandTag commandTag); +extern bool command_tag_table_rewrite_ok(CommandTag commandTag); +extern CommandTag GetCommandTagEnum(const char *tagname); + +#endif /* CMDTAG_H */ diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h new file mode 100644 index 0000000..9e94f44 --- /dev/null +++ b/src/include/tcop/cmdtaglist.h @@ -0,0 +1,218 @@ +/*---------------------------------------------------------------------- + * + * cmdtaglist.h + * Command tags + * + * The command tag list is kept in its own source file for possible use + * by automatic tools. The exact representation of a command tag is + * determined by the PG_CMDTAG macro, which is not defined in this file; + * it can be defined by the caller for special purposes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/cmdtaglist.h + * + *---------------------------------------------------------------------- + */ + +/* there is deliberately not an #ifndef CMDTAGLIST_H here */ + +/* + * List of command tags. The entries must be sorted alphabetically on their + * textual name, so that we can bsearch on it; see GetCommandTagEnum(). + */ + +/* symbol name, textual name, event_trigger_ok, table_rewrite_ok, rowcount */ +PG_CMDTAG(CMDTAG_UNKNOWN, "???", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_ACCESS_METHOD, "ALTER ACCESS METHOD", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_AGGREGATE, "ALTER AGGREGATE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_CAST, "ALTER CAST", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_COLLATION, "ALTER COLLATION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_CONSTRAINT, "ALTER CONSTRAINT", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_CONVERSION, "ALTER CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_DATABASE, "ALTER DATABASE", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_DEFAULT_PRIVILEGES, "ALTER DEFAULT PRIVILEGES", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_DOMAIN, "ALTER DOMAIN", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_EVENT_TRIGGER, "ALTER EVENT TRIGGER", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_EXTENSION, "ALTER EXTENSION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_FOREIGN_DATA_WRAPPER, "ALTER FOREIGN DATA WRAPPER", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_FOREIGN_TABLE, "ALTER FOREIGN TABLE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_FUNCTION, "ALTER FUNCTION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_INDEX, "ALTER INDEX", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_LANGUAGE, "ALTER LANGUAGE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_LARGE_OBJECT, "ALTER LARGE OBJECT", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_MATERIALIZED_VIEW, "ALTER MATERIALIZED VIEW", true, true, false) +PG_CMDTAG(CMDTAG_ALTER_OPERATOR, "ALTER OPERATOR", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_OPERATOR_CLASS, "ALTER OPERATOR CLASS", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_OPERATOR_FAMILY, "ALTER OPERATOR FAMILY", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_POLICY, "ALTER POLICY", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_PROCEDURE, "ALTER PROCEDURE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_PUBLICATION, "ALTER PUBLICATION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_ROLE, "ALTER ROLE", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_ROUTINE, "ALTER ROUTINE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_RULE, "ALTER RULE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_SCHEMA, "ALTER SCHEMA", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_SEQUENCE, "ALTER SEQUENCE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_SERVER, "ALTER SERVER", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_STATISTICS, "ALTER STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_SUBSCRIPTION, "ALTER SUBSCRIPTION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_SYSTEM, "ALTER SYSTEM", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_TABLE, "ALTER TABLE", true, true, false) +PG_CMDTAG(CMDTAG_ALTER_TABLESPACE, "ALTER TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION, "ALTER TEXT SEARCH CONFIGURATION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY, "ALTER TEXT SEARCH DICTIONARY", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_PARSER, "ALTER TEXT SEARCH PARSER", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE, "ALTER TEXT SEARCH TEMPLATE", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TRANSFORM, "ALTER TRANSFORM", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TRIGGER, "ALTER TRIGGER", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_TYPE, "ALTER TYPE", true, true, false) +PG_CMDTAG(CMDTAG_ALTER_USER_MAPPING, "ALTER USER MAPPING", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_VIEW, "ALTER VIEW", true, false, false) +PG_CMDTAG(CMDTAG_ANALYZE, "ANALYZE", false, false, false) +PG_CMDTAG(CMDTAG_BEGIN, "BEGIN", false, false, false) +PG_CMDTAG(CMDTAG_CALL, "CALL", false, false, false) +PG_CMDTAG(CMDTAG_CHECKPOINT, "CHECKPOINT", false, false, false) +PG_CMDTAG(CMDTAG_CLOSE, "CLOSE", false, false, false) +PG_CMDTAG(CMDTAG_CLOSE_CURSOR, "CLOSE CURSOR", false, false, false) +PG_CMDTAG(CMDTAG_CLOSE_CURSOR_ALL, "CLOSE CURSOR ALL", false, false, false) +PG_CMDTAG(CMDTAG_CLUSTER, "CLUSTER", false, false, false) +PG_CMDTAG(CMDTAG_COMMENT, "COMMENT", true, false, false) +PG_CMDTAG(CMDTAG_COMMIT, "COMMIT", false, false, false) +PG_CMDTAG(CMDTAG_COMMIT_PREPARED, "COMMIT PREPARED", false, false, false) +PG_CMDTAG(CMDTAG_COPY, "COPY", false, false, true) +PG_CMDTAG(CMDTAG_COPY_FROM, "COPY FROM", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_ACCESS_METHOD, "CREATE ACCESS METHOD", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_AGGREGATE, "CREATE AGGREGATE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_CAST, "CREATE CAST", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_COLLATION, "CREATE COLLATION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_CONSTRAINT, "CREATE CONSTRAINT", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_CONVERSION, "CREATE CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_DATABASE, "CREATE DATABASE", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_DOMAIN, "CREATE DOMAIN", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_EVENT_TRIGGER, "CREATE EVENT TRIGGER", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_EXTENSION, "CREATE EXTENSION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_FOREIGN_DATA_WRAPPER, "CREATE FOREIGN DATA WRAPPER", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_FOREIGN_TABLE, "CREATE FOREIGN TABLE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_FUNCTION, "CREATE FUNCTION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_INDEX, "CREATE INDEX", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_LANGUAGE, "CREATE LANGUAGE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_MATERIALIZED_VIEW, "CREATE MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_OPERATOR, "CREATE OPERATOR", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_OPERATOR_CLASS, "CREATE OPERATOR CLASS", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_OPERATOR_FAMILY, "CREATE OPERATOR FAMILY", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_POLICY, "CREATE POLICY", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_PROCEDURE, "CREATE PROCEDURE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_PUBLICATION, "CREATE PUBLICATION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_ROLE, "CREATE ROLE", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_ROUTINE, "CREATE ROUTINE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_RULE, "CREATE RULE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_SCHEMA, "CREATE SCHEMA", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_SEQUENCE, "CREATE SEQUENCE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_SERVER, "CREATE SERVER", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_STATISTICS, "CREATE STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_SUBSCRIPTION, "CREATE SUBSCRIPTION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TABLE, "CREATE TABLE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TABLE_AS, "CREATE TABLE AS", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TABLESPACE, "CREATE TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION, "CREATE TEXT SEARCH CONFIGURATION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY, "CREATE TEXT SEARCH DICTIONARY", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_PARSER, "CREATE TEXT SEARCH PARSER", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE, "CREATE TEXT SEARCH TEMPLATE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TRANSFORM, "CREATE TRANSFORM", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TRIGGER, "CREATE TRIGGER", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_TYPE, "CREATE TYPE", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_USER_MAPPING, "CREATE USER MAPPING", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_VIEW, "CREATE VIEW", true, false, false) +PG_CMDTAG(CMDTAG_DEALLOCATE, "DEALLOCATE", false, false, false) +PG_CMDTAG(CMDTAG_DEALLOCATE_ALL, "DEALLOCATE ALL", false, false, false) +PG_CMDTAG(CMDTAG_DECLARE_CURSOR, "DECLARE CURSOR", false, false, false) +PG_CMDTAG(CMDTAG_DELETE, "DELETE", false, false, true) +PG_CMDTAG(CMDTAG_DISCARD, "DISCARD", false, false, false) +PG_CMDTAG(CMDTAG_DISCARD_ALL, "DISCARD ALL", false, false, false) +PG_CMDTAG(CMDTAG_DISCARD_PLANS, "DISCARD PLANS", false, false, false) +PG_CMDTAG(CMDTAG_DISCARD_SEQUENCES, "DISCARD SEQUENCES", false, false, false) +PG_CMDTAG(CMDTAG_DISCARD_TEMP, "DISCARD TEMP", false, false, false) +PG_CMDTAG(CMDTAG_DO, "DO", false, false, false) +PG_CMDTAG(CMDTAG_DROP_ACCESS_METHOD, "DROP ACCESS METHOD", true, false, false) +PG_CMDTAG(CMDTAG_DROP_AGGREGATE, "DROP AGGREGATE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_CAST, "DROP CAST", true, false, false) +PG_CMDTAG(CMDTAG_DROP_COLLATION, "DROP COLLATION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_CONSTRAINT, "DROP CONSTRAINT", true, false, false) +PG_CMDTAG(CMDTAG_DROP_CONVERSION, "DROP CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_DATABASE, "DROP DATABASE", false, false, false) +PG_CMDTAG(CMDTAG_DROP_DOMAIN, "DROP DOMAIN", true, false, false) +PG_CMDTAG(CMDTAG_DROP_EVENT_TRIGGER, "DROP EVENT TRIGGER", false, false, false) +PG_CMDTAG(CMDTAG_DROP_EXTENSION, "DROP EXTENSION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_FOREIGN_DATA_WRAPPER, "DROP FOREIGN DATA WRAPPER", true, false, false) +PG_CMDTAG(CMDTAG_DROP_FOREIGN_TABLE, "DROP FOREIGN TABLE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_FUNCTION, "DROP FUNCTION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_INDEX, "DROP INDEX", true, false, false) +PG_CMDTAG(CMDTAG_DROP_LANGUAGE, "DROP LANGUAGE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_MATERIALIZED_VIEW, "DROP MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_DROP_OPERATOR, "DROP OPERATOR", true, false, false) +PG_CMDTAG(CMDTAG_DROP_OPERATOR_CLASS, "DROP OPERATOR CLASS", true, false, false) +PG_CMDTAG(CMDTAG_DROP_OPERATOR_FAMILY, "DROP OPERATOR FAMILY", true, false, false) +PG_CMDTAG(CMDTAG_DROP_OWNED, "DROP OWNED", true, false, false) +PG_CMDTAG(CMDTAG_DROP_POLICY, "DROP POLICY", true, false, false) +PG_CMDTAG(CMDTAG_DROP_PROCEDURE, "DROP PROCEDURE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_PUBLICATION, "DROP PUBLICATION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_ROLE, "DROP ROLE", false, false, false) +PG_CMDTAG(CMDTAG_DROP_ROUTINE, "DROP ROUTINE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_RULE, "DROP RULE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_SCHEMA, "DROP SCHEMA", true, false, false) +PG_CMDTAG(CMDTAG_DROP_SEQUENCE, "DROP SEQUENCE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_SERVER, "DROP SERVER", true, false, false) +PG_CMDTAG(CMDTAG_DROP_STATISTICS, "DROP STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_DROP_SUBSCRIPTION, "DROP SUBSCRIPTION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TABLE, "DROP TABLE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TABLESPACE, "DROP TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION, "DROP TEXT SEARCH CONFIGURATION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_DICTIONARY, "DROP TEXT SEARCH DICTIONARY", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_PARSER, "DROP TEXT SEARCH PARSER", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_TEMPLATE, "DROP TEXT SEARCH TEMPLATE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TRANSFORM, "DROP TRANSFORM", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TRIGGER, "DROP TRIGGER", true, false, false) +PG_CMDTAG(CMDTAG_DROP_TYPE, "DROP TYPE", true, false, false) +PG_CMDTAG(CMDTAG_DROP_USER_MAPPING, "DROP USER MAPPING", true, false, false) +PG_CMDTAG(CMDTAG_DROP_VIEW, "DROP VIEW", true, false, false) +PG_CMDTAG(CMDTAG_EXECUTE, "EXECUTE", false, false, false) +PG_CMDTAG(CMDTAG_EXPLAIN, "EXPLAIN", false, false, false) +PG_CMDTAG(CMDTAG_FETCH, "FETCH", false, false, true) +PG_CMDTAG(CMDTAG_GRANT, "GRANT", true, false, false) +PG_CMDTAG(CMDTAG_GRANT_ROLE, "GRANT ROLE", false, false, false) +PG_CMDTAG(CMDTAG_IMPORT_FOREIGN_SCHEMA, "IMPORT FOREIGN SCHEMA", true, false, false) +PG_CMDTAG(CMDTAG_INSERT, "INSERT", false, false, true) +PG_CMDTAG(CMDTAG_LISTEN, "LISTEN", false, false, false) +PG_CMDTAG(CMDTAG_LOAD, "LOAD", false, false, false) +PG_CMDTAG(CMDTAG_LOCK_TABLE, "LOCK TABLE", false, false, false) +PG_CMDTAG(CMDTAG_MERGE, "MERGE", false, false, true) +PG_CMDTAG(CMDTAG_MOVE, "MOVE", false, false, true) +PG_CMDTAG(CMDTAG_NOTIFY, "NOTIFY", false, false, false) +PG_CMDTAG(CMDTAG_PREPARE, "PREPARE", false, false, false) +PG_CMDTAG(CMDTAG_PREPARE_TRANSACTION, "PREPARE TRANSACTION", false, false, false) +PG_CMDTAG(CMDTAG_REASSIGN_OWNED, "REASSIGN OWNED", false, false, false) +PG_CMDTAG(CMDTAG_REFRESH_MATERIALIZED_VIEW, "REFRESH MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_REINDEX, "REINDEX", false, false, false) +PG_CMDTAG(CMDTAG_RELEASE, "RELEASE", false, false, false) +PG_CMDTAG(CMDTAG_RESET, "RESET", false, false, false) +PG_CMDTAG(CMDTAG_REVOKE, "REVOKE", true, false, false) +PG_CMDTAG(CMDTAG_REVOKE_ROLE, "REVOKE ROLE", false, false, false) +PG_CMDTAG(CMDTAG_ROLLBACK, "ROLLBACK", false, false, false) +PG_CMDTAG(CMDTAG_ROLLBACK_PREPARED, "ROLLBACK PREPARED", false, false, false) +PG_CMDTAG(CMDTAG_SAVEPOINT, "SAVEPOINT", false, false, false) +PG_CMDTAG(CMDTAG_SECURITY_LABEL, "SECURITY LABEL", true, false, false) +PG_CMDTAG(CMDTAG_SELECT, "SELECT", false, false, true) +PG_CMDTAG(CMDTAG_SELECT_FOR_KEY_SHARE, "SELECT FOR KEY SHARE", false, false, false) +PG_CMDTAG(CMDTAG_SELECT_FOR_NO_KEY_UPDATE, "SELECT FOR NO KEY UPDATE", false, false, false) +PG_CMDTAG(CMDTAG_SELECT_FOR_SHARE, "SELECT FOR SHARE", false, false, false) +PG_CMDTAG(CMDTAG_SELECT_FOR_UPDATE, "SELECT FOR UPDATE", false, false, false) +PG_CMDTAG(CMDTAG_SELECT_INTO, "SELECT INTO", true, false, false) +PG_CMDTAG(CMDTAG_SET, "SET", false, false, false) +PG_CMDTAG(CMDTAG_SET_CONSTRAINTS, "SET CONSTRAINTS", false, false, false) +PG_CMDTAG(CMDTAG_SHOW, "SHOW", false, false, false) +PG_CMDTAG(CMDTAG_START_TRANSACTION, "START TRANSACTION", false, false, false) +PG_CMDTAG(CMDTAG_TRUNCATE_TABLE, "TRUNCATE TABLE", false, false, false) +PG_CMDTAG(CMDTAG_UNLISTEN, "UNLISTEN", false, false, false) +PG_CMDTAG(CMDTAG_UPDATE, "UPDATE", false, false, true) +PG_CMDTAG(CMDTAG_VACUUM, "VACUUM", false, false, false) diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h new file mode 100644 index 0000000..94de13d --- /dev/null +++ b/src/include/tcop/deparse_utility.h @@ -0,0 +1,108 @@ +/*------------------------------------------------------------------------- + * + * deparse_utility.h + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/deparse_utility.h + * + *------------------------------------------------------------------------- + */ +#ifndef DEPARSE_UTILITY_H +#define DEPARSE_UTILITY_H + +#include "access/attnum.h" +#include "catalog/objectaddress.h" +#include "nodes/nodes.h" +#include "utils/aclchk_internal.h" + + +/* + * Support for keeping track of collected commands. + */ +typedef enum CollectedCommandType +{ + SCT_Simple, + SCT_AlterTable, + SCT_Grant, + SCT_AlterOpFamily, + SCT_AlterDefaultPrivileges, + SCT_CreateOpClass, + SCT_AlterTSConfig +} CollectedCommandType; + +/* + * For ALTER TABLE commands, we keep a list of the subcommands therein. + */ +typedef struct CollectedATSubcmd +{ + ObjectAddress address; /* affected column, constraint, index, ... */ + Node *parsetree; +} CollectedATSubcmd; + +typedef struct CollectedCommand +{ + CollectedCommandType type; + + bool in_extension; + Node *parsetree; + + union + { + /* most commands */ + struct + { + ObjectAddress address; + ObjectAddress secondaryObject; + } simple; + + /* ALTER TABLE, and internal uses thereof */ + struct + { + Oid objectId; + Oid classId; + List *subcmds; + } alterTable; + + /* GRANT / REVOKE */ + struct + { + InternalGrant *istmt; + } grant; + + /* ALTER OPERATOR FAMILY */ + struct + { + ObjectAddress address; + List *operators; + List *procedures; + } opfam; + + /* CREATE OPERATOR CLASS */ + struct + { + ObjectAddress address; + List *operators; + List *procedures; + } createopc; + + /* ALTER TEXT SEARCH CONFIGURATION ADD/ALTER/DROP MAPPING */ + struct + { + ObjectAddress address; + Oid *dictIds; + int ndicts; + } atscfg; + + /* ALTER DEFAULT PRIVILEGES */ + struct + { + ObjectType objtype; + } defprivs; + } d; + + struct CollectedCommand *parent; /* when nested */ +} CollectedCommand; + +#endif /* DEPARSE_UTILITY_H */ diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h new file mode 100644 index 0000000..3c3eaba --- /dev/null +++ b/src/include/tcop/dest.h @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------- + * + * dest.h + * support for communication destinations + * + * Whenever the backend executes a query that returns tuples, the results + * have to go someplace. For example: + * + * - stdout is the destination only when we are running a + * standalone backend (no postmaster) and are returning results + * back to an interactive user. + * + * - a remote process is the destination when we are + * running a backend with a frontend and the frontend executes + * PQexec() or PQfn(). In this case, the results are sent + * to the frontend via the functions in backend/libpq. + * + * - DestNone is the destination when the system executes + * a query internally. The results are discarded. + * + * dest.c defines three functions that implement destination management: + * + * BeginCommand: initialize the destination at start of command. + * CreateDestReceiver: return a pointer to a struct of destination-specific + * receiver functions. + * EndCommand: clean up the destination at end of command. + * + * BeginCommand/EndCommand are executed once per received SQL query. + * + * CreateDestReceiver returns a receiver object appropriate to the specified + * destination. The executor, as well as utility statements that can return + * tuples, are passed the resulting DestReceiver* pointer. Each executor run + * or utility execution calls the receiver's rStartup method, then the + * receiveSlot method (zero or more times), then the rShutdown method. + * The same receiver object may be re-used multiple times; eventually it is + * destroyed by calling its rDestroy method. + * + * In some cases, receiver objects require additional parameters that must + * be passed to them after calling CreateDestReceiver. Since the set of + * parameters varies for different receiver types, this is not handled by + * this module, but by direct calls from the calling code to receiver type + * specific functions. + * + * The DestReceiver object returned by CreateDestReceiver may be a statically + * allocated object (for destination types that require no local state), + * in which case rDestroy is a no-op. Alternatively it can be a palloc'd + * object that has DestReceiver as its first field and contains additional + * fields (see printtup.c for an example). These additional fields are then + * accessible to the DestReceiver functions by casting the DestReceiver* + * pointer passed to them. The palloc'd object is pfree'd by the rDestroy + * method. Note that the caller of CreateDestReceiver should take care to + * do so in a memory context that is long-lived enough for the receiver + * object not to disappear while still needed. + * + * Special provision: None_Receiver is a permanently available receiver + * object for the DestNone destination. This avoids useless creation/destroy + * calls in portal and cursor manipulations. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/dest.h + * + *------------------------------------------------------------------------- + */ +#ifndef DEST_H +#define DEST_H + +#include "executor/tuptable.h" +#include "tcop/cmdtag.h" + + +/* buffer size to use for command completion tags */ +#define COMPLETION_TAG_BUFSIZE 64 + + +/* ---------------- + * CommandDest is a simplistic means of identifying the desired + * destination. Someday this will probably need to be improved. + * + * Note: only the values DestNone, DestDebug, DestRemote are legal for the + * global variable whereToSendOutput. The other values may be used + * as the destination for individual commands. + * ---------------- + */ +typedef enum +{ + DestNone, /* results are discarded */ + DestDebug, /* results go to debugging output */ + DestRemote, /* results sent to frontend process */ + DestRemoteExecute, /* sent to frontend, in Execute command */ + DestRemoteSimple, /* sent to frontend, w/no catalog access */ + DestSPI, /* results sent to SPI manager */ + DestTuplestore, /* results sent to Tuplestore */ + DestIntoRel, /* results sent to relation (SELECT INTO) */ + DestCopyOut, /* results sent to COPY TO code */ + DestSQLFunction, /* results sent to SQL-language func mgr */ + DestTransientRel, /* results sent to transient relation */ + DestTupleQueue /* results sent to tuple queue */ +} CommandDest; + +/* ---------------- + * DestReceiver is a base type for destination-specific local state. + * In the simplest cases, there is no state info, just the function + * pointers that the executor must call. + * + * Note: the receiveSlot routine must be passed a slot containing a TupleDesc + * identical to the one given to the rStartup routine. It returns bool where + * a "true" value means "continue processing" and a "false" value means + * "stop early, just as if we'd reached the end of the scan". + * ---------------- + */ +typedef struct _DestReceiver DestReceiver; + +struct _DestReceiver +{ + /* Called for each tuple to be output: */ + bool (*receiveSlot) (TupleTableSlot *slot, + DestReceiver *self); + /* Per-executor-run initialization and shutdown: */ + void (*rStartup) (DestReceiver *self, + int operation, + TupleDesc typeinfo); + void (*rShutdown) (DestReceiver *self); + /* Destroy the receiver object itself (if dynamically allocated) */ + void (*rDestroy) (DestReceiver *self); + /* CommandDest code for this receiver */ + CommandDest mydest; + /* Private fields might appear beyond this point... */ +}; + +extern PGDLLIMPORT DestReceiver *None_Receiver; /* permanent receiver for + * DestNone */ + +/* The primary destination management functions */ + +extern void BeginCommand(CommandTag commandTag, CommandDest dest); +extern DestReceiver *CreateDestReceiver(CommandDest dest); +extern void EndCommand(const QueryCompletion *qc, CommandDest dest, + bool force_undecorated_output); +extern void EndReplicationCommand(const char *commandTag); + +/* Additional functions that go with destination management, more or less. */ + +extern void NullCommand(CommandDest dest); +extern void ReadyForQuery(CommandDest dest); + +#endif /* DEST_H */ diff --git a/src/include/tcop/fastpath.h b/src/include/tcop/fastpath.h new file mode 100644 index 0000000..cb15a16 --- /dev/null +++ b/src/include/tcop/fastpath.h @@ -0,0 +1,20 @@ +/*------------------------------------------------------------------------- + * + * fastpath.h + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/fastpath.h + * + *------------------------------------------------------------------------- + */ +#ifndef FASTPATH_H +#define FASTPATH_H + +#include "lib/stringinfo.h" + +extern void HandleFunctionRequest(StringInfo msgBuf); + +#endif /* FASTPATH_H */ diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h new file mode 100644 index 0000000..f9a6882 --- /dev/null +++ b/src/include/tcop/pquery.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * pquery.h + * prototypes for pquery.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/pquery.h + * + *------------------------------------------------------------------------- + */ +#ifndef PQUERY_H +#define PQUERY_H + +#include "nodes/parsenodes.h" +#include "utils/portal.h" + +struct PlannedStmt; /* avoid including plannodes.h here */ + + +extern PGDLLIMPORT Portal ActivePortal; + + +extern PortalStrategy ChoosePortalStrategy(List *stmts); + +extern List *FetchPortalTargetList(Portal portal); + +extern List *FetchStatementTargetList(Node *stmt); + +extern void PortalStart(Portal portal, ParamListInfo params, + int eflags, Snapshot snapshot); + +extern void PortalSetResultFormat(Portal portal, int nFormats, + int16 *formats); + +extern bool PortalRun(Portal portal, long count, bool isTopLevel, + bool run_once, DestReceiver *dest, DestReceiver *altdest, + QueryCompletion *qc); + +extern uint64 PortalRunFetch(Portal portal, + FetchDirection fdirection, + long count, + DestReceiver *dest); + +extern bool PlannedStmtRequiresSnapshot(struct PlannedStmt *pstmt); + +extern void EnsurePortalSnapshotExists(void); + +#endif /* PQUERY_H */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h new file mode 100644 index 0000000..70d9dab --- /dev/null +++ b/src/include/tcop/tcopprot.h @@ -0,0 +1,97 @@ +/*------------------------------------------------------------------------- + * + * tcopprot.h + * prototypes for postgres.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/tcopprot.h + * + *------------------------------------------------------------------------- + */ +#ifndef TCOPPROT_H +#define TCOPPROT_H + +#include "nodes/params.h" +#include "nodes/parsenodes.h" +#include "nodes/plannodes.h" +#include "storage/procsignal.h" +#include "utils/guc.h" +#include "utils/queryenvironment.h" + + +/* Required daylight between max_stack_depth and the kernel limit, in bytes */ +#define STACK_DEPTH_SLOP (512 * 1024L) + +extern PGDLLIMPORT CommandDest whereToSendOutput; +extern PGDLLIMPORT const char *debug_query_string; +extern PGDLLIMPORT int max_stack_depth; +extern PGDLLIMPORT int PostAuthDelay; +extern PGDLLIMPORT int client_connection_check_interval; + +/* GUC-configurable parameters */ + +typedef enum +{ + LOGSTMT_NONE, /* log no statements */ + LOGSTMT_DDL, /* log data definition statements */ + LOGSTMT_MOD, /* log modification statements, plus DDL */ + LOGSTMT_ALL /* log all statements */ +} LogStmtLevel; + +extern PGDLLIMPORT int log_statement; + +extern List *pg_parse_query(const char *query_string); +extern List *pg_rewrite_query(Query *query); +extern List *pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, + const char *query_string, + const Oid *paramTypes, int numParams, + QueryEnvironment *queryEnv); +extern List *pg_analyze_and_rewrite_varparams(RawStmt *parsetree, + const char *query_string, + Oid **paramTypes, + int *numParams, + QueryEnvironment *queryEnv); +extern List *pg_analyze_and_rewrite_withcb(RawStmt *parsetree, + const char *query_string, + ParserSetupHook parserSetup, + void *parserSetupArg, + QueryEnvironment *queryEnv); +extern PlannedStmt *pg_plan_query(Query *querytree, const char *query_string, + int cursorOptions, + ParamListInfo boundParams); +extern List *pg_plan_queries(List *querytrees, const char *query_string, + int cursorOptions, + ParamListInfo boundParams); + +extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); +extern void assign_max_stack_depth(int newval, void *extra); + +extern void die(SIGNAL_ARGS); +extern void quickdie(SIGNAL_ARGS) pg_attribute_noreturn(); +extern void StatementCancelHandler(SIGNAL_ARGS); +extern void FloatExceptionHandler(SIGNAL_ARGS) pg_attribute_noreturn(); +extern void RecoveryConflictInterrupt(ProcSignalReason reason); /* called from SIGUSR1 + * handler */ +extern void ProcessClientReadInterrupt(bool blocked); +extern void ProcessClientWriteInterrupt(bool blocked); + +extern void process_postgres_switches(int argc, char *argv[], + GucContext ctx, const char **dbname); +extern void PostgresSingleUserMain(int argc, char *argv[], + const char *username) pg_attribute_noreturn(); +extern void PostgresMain(const char *dbname, + const char *username) pg_attribute_noreturn(); +extern long get_stack_depth_rlimit(void); +extern void ResetUsage(void); +extern void ShowUsage(const char *title); +extern int check_log_duration(char *msec_str, bool was_logged); +extern void set_debug_options(int debug_flag, + GucContext context, GucSource source); +extern bool set_plan_disabling_options(const char *arg, + GucContext context, GucSource source); +extern const char *get_stats_option_name(const char *arg); + +#endif /* TCOPPROT_H */ diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h new file mode 100644 index 0000000..f9daf5b --- /dev/null +++ b/src/include/tcop/utility.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * utility.h + * prototypes for utility.c. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/utility.h + * + *------------------------------------------------------------------------- + */ +#ifndef UTILITY_H +#define UTILITY_H + +#include "tcop/cmdtag.h" +#include "tcop/tcopprot.h" + +typedef enum +{ + PROCESS_UTILITY_TOPLEVEL, /* toplevel interactive command */ + PROCESS_UTILITY_QUERY, /* a complete query, but not toplevel */ + PROCESS_UTILITY_QUERY_NONATOMIC, /* a complete query, nonatomic + * execution context */ + PROCESS_UTILITY_SUBCOMMAND /* a portion of a query */ +} ProcessUtilityContext; + +/* Info needed when recursing from ALTER TABLE */ +typedef struct AlterTableUtilityContext +{ + PlannedStmt *pstmt; /* PlannedStmt for outer ALTER TABLE command */ + const char *queryString; /* its query string */ + Oid relid; /* OID of ALTER's target table */ + ParamListInfo params; /* any parameters available to ALTER TABLE */ + QueryEnvironment *queryEnv; /* execution environment for ALTER TABLE */ +} AlterTableUtilityContext; + +/* + * These constants are used to describe the extent to which a particular + * command is read-only. + * + * COMMAND_OK_IN_READ_ONLY_TXN means that the command is permissible even when + * XactReadOnly is set. This bit should be set for commands that don't change + * the state of the database (data or schema) in a way that would affect the + * output of pg_dump. + * + * COMMAND_OK_IN_PARALLEL_MODE means that the command is permissible even + * when in parallel mode. Writing tuples is forbidden, as is anything that + * might confuse cooperating processes. + * + * COMMAND_OK_IN_RECOVERY means that the command is permissible even when in + * recovery. It can't write WAL, nor can it do things that would imperil + * replay of future WAL received from the primary. + */ +#define COMMAND_OK_IN_READ_ONLY_TXN 0x0001 +#define COMMAND_OK_IN_PARALLEL_MODE 0x0002 +#define COMMAND_OK_IN_RECOVERY 0x0004 + +/* + * We say that a command is strictly read-only if it is sufficiently read-only + * for all purposes. For clarity, we also have a constant for commands that are + * in no way read-only. + */ +#define COMMAND_IS_STRICTLY_READ_ONLY \ + (COMMAND_OK_IN_READ_ONLY_TXN | COMMAND_OK_IN_RECOVERY | \ + COMMAND_OK_IN_PARALLEL_MODE) +#define COMMAND_IS_NOT_READ_ONLY 0 + +/* Hook for plugins to get control in ProcessUtility() */ +typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, QueryCompletion *qc); +extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook; + +extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, QueryCompletion *qc); +extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, QueryCompletion *qc); + +extern void ProcessUtilityForAlterTable(Node *stmt, + AlterTableUtilityContext *context); + +extern bool UtilityReturnsTuples(Node *parsetree); + +extern TupleDesc UtilityTupleDescriptor(Node *parsetree); + +extern Query *UtilityContainsQuery(Node *parsetree); + +extern CommandTag CreateCommandTag(Node *parsetree); + +static inline const char * +CreateCommandName(Node *parsetree) +{ + return GetCommandTagName(CreateCommandTag(parsetree)); +} + +extern LogStmtLevel GetCommandLogLevel(Node *parsetree); + +extern bool CommandIsReadOnly(PlannedStmt *pstmt); + +#endif /* UTILITY_H */ diff --git a/src/include/tsearch/dicts/regis.h b/src/include/tsearch/dicts/regis.h new file mode 100644 index 0000000..c7c3d9f --- /dev/null +++ b/src/include/tsearch/dicts/regis.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * regis.h + * + * Declarations for fast regex subset, used by ISpell + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/dicts/regis.h + * + *------------------------------------------------------------------------- + */ + +#ifndef __REGIS_H__ +#define __REGIS_H__ + +typedef struct RegisNode +{ + uint32 + type:2, + len:16, + unused:14; + struct RegisNode *next; + unsigned char data[FLEXIBLE_ARRAY_MEMBER]; +} RegisNode; + +#define RNHDRSZ (offsetof(RegisNode,data)) + +#define RSF_ONEOF 1 +#define RSF_NONEOF 2 + +typedef struct Regis +{ + RegisNode *node; + uint32 + issuffix:1, + nchar:16, + unused:15; +} Regis; + +extern bool RS_isRegis(const char *str); + +extern void RS_compile(Regis *r, bool issuffix, const char *str); +extern void RS_free(Regis *r); + +/*returns true if matches */ +extern bool RS_execute(Regis *r, char *str); + +#endif diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h new file mode 100644 index 0000000..978f43a --- /dev/null +++ b/src/include/tsearch/dicts/spell.h @@ -0,0 +1,247 @@ +/*------------------------------------------------------------------------- + * + * spell.h + * + * Declarations for ISpell dictionary + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/dicts/spell.h + * + *------------------------------------------------------------------------- + */ + +#ifndef __SPELL_H__ +#define __SPELL_H__ + +#include "regex/regex.h" +#include "tsearch/dicts/regis.h" +#include "tsearch/ts_public.h" + +/* + * SPNode and SPNodeData are used to represent prefix tree (Trie) to store + * a words list. + */ +struct SPNode; + +typedef struct +{ + uint32 val:8, + isword:1, + /* Stores compound flags listed below */ + compoundflag:4, + /* Reference to an entry of the AffixData field */ + affix:19; + struct SPNode *node; +} SPNodeData; + +/* + * Names of FF_ are correlated with Hunspell options in affix file + * http://hunspell.sourceforge.net/ + */ +#define FF_COMPOUNDONLY 0x01 +#define FF_COMPOUNDBEGIN 0x02 +#define FF_COMPOUNDMIDDLE 0x04 +#define FF_COMPOUNDLAST 0x08 +#define FF_COMPOUNDFLAG ( FF_COMPOUNDBEGIN | FF_COMPOUNDMIDDLE | \ + FF_COMPOUNDLAST ) +#define FF_COMPOUNDFLAGMASK 0x0f + +typedef struct SPNode +{ + uint32 length; + SPNodeData data[FLEXIBLE_ARRAY_MEMBER]; +} SPNode; + +#define SPNHDRSZ (offsetof(SPNode,data)) + +/* + * Represents an entry in a words list. + */ +typedef struct spell_struct +{ + union + { + /* + * flag is filled in by NIImportDictionary(). After + * NISortDictionary(), d is used instead of flag. + */ + char *flag; + /* d is used in mkSPNode() */ + struct + { + /* Reference to an entry of the AffixData field */ + int affix; + /* Length of the word */ + int len; + } d; + } p; + char word[FLEXIBLE_ARRAY_MEMBER]; +} SPELL; + +#define SPELLHDRSZ (offsetof(SPELL, word)) + +/* + * If an affix uses a regex, we have to store that separately in a struct + * that won't move around when arrays of affixes are enlarged or sorted. + * This is so that it can be found to be cleaned up at context destruction. + */ +typedef struct aff_regex_struct +{ + regex_t regex; + MemoryContextCallback mcallback; +} aff_regex_struct; + +/* + * Represents an entry in an affix list. + */ +typedef struct aff_struct +{ + char *flag; + /* FF_SUFFIX or FF_PREFIX */ + uint32 type:1, + flagflags:7, + issimple:1, + isregis:1, + replen:14; + char *find; + char *repl; + union + { + aff_regex_struct *pregex; + Regis regis; + } reg; +} AFFIX; + +/* + * affixes use dictionary flags too + */ +#define FF_COMPOUNDPERMITFLAG 0x10 +#define FF_COMPOUNDFORBIDFLAG 0x20 +#define FF_CROSSPRODUCT 0x40 + +/* + * Don't change the order of these. Initialization sorts by these, + * and expects prefixes to come first after sorting. + */ +#define FF_SUFFIX 1 +#define FF_PREFIX 0 + +/* + * AffixNode and AffixNodeData are used to represent prefix tree (Trie) to store + * an affix list. + */ +struct AffixNode; + +typedef struct +{ + uint32 val:8, + naff:24; + AFFIX **aff; + struct AffixNode *node; +} AffixNodeData; + +typedef struct AffixNode +{ + uint32 isvoid:1, + length:31; + AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]; +} AffixNode; + +#define ANHRDSZ (offsetof(AffixNode, data)) + +typedef struct +{ + char *affix; + int len; + bool issuffix; +} CMPDAffix; + +/* + * Type of encoding affix flags in Hunspell dictionaries + */ +typedef enum +{ + FM_CHAR, /* one character (like ispell) */ + FM_LONG, /* two characters */ + FM_NUM /* number, >= 0 and < 65536 */ +} FlagMode; + +/* + * Structure to store Hunspell options. Flag representation depends on flag + * type. These flags are about support of compound words. + */ +typedef struct CompoundAffixFlag +{ + union + { + /* Flag name if flagMode is FM_CHAR or FM_LONG */ + char *s; + /* Flag name if flagMode is FM_NUM */ + uint32 i; + } flag; + /* we don't have a bsearch_arg version, so, copy FlagMode */ + FlagMode flagMode; + uint32 value; +} CompoundAffixFlag; + +#define FLAGNUM_MAXSIZE (1 << 16) + +typedef struct +{ + int maffixes; + int naffixes; + AFFIX *Affix; + + AffixNode *Suffix; + AffixNode *Prefix; + + SPNode *Dictionary; + /* Array of sets of affixes */ + char **AffixData; + int lenAffixData; + int nAffixData; + bool useFlagAliases; + + CMPDAffix *CompoundAffix; + + bool usecompound; + FlagMode flagMode; + + /* + * All follow fields are actually needed only for initialization + */ + + /* Array of Hunspell options in affix file */ + CompoundAffixFlag *CompoundAffixFlags; + /* number of entries in CompoundAffixFlags array */ + int nCompoundAffixFlag; + /* allocated length of CompoundAffixFlags array */ + int mCompoundAffixFlag; + + /* + * Remaining fields are only used during dictionary construction; they are + * set up by NIStartBuild and cleared by NIFinishBuild. + */ + MemoryContext buildCxt; /* temp context for construction */ + + /* Temporary array of all words in the dict file */ + SPELL **Spell; + int nspell; /* number of valid entries in Spell array */ + int mspell; /* allocated length of Spell array */ + + /* These are used to allocate "compact" data without palloc overhead */ + char *firstfree; /* first free address (always maxaligned) */ + size_t avail; /* free space remaining at firstfree */ +} IspellDict; + +extern TSLexeme *NINormalizeWord(IspellDict *Conf, char *word); + +extern void NIStartBuild(IspellDict *Conf); +extern void NIImportAffixes(IspellDict *Conf, const char *filename); +extern void NIImportDictionary(IspellDict *Conf, const char *filename); +extern void NISortDictionary(IspellDict *Conf); +extern void NISortAffixes(IspellDict *Conf); +extern void NIFinishBuild(IspellDict *Conf); + +#endif diff --git a/src/include/tsearch/ts_cache.h b/src/include/tsearch/ts_cache.h new file mode 100644 index 0000000..5e4a49e --- /dev/null +++ b/src/include/tsearch/ts_cache.h @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------- + * + * ts_cache.h + * Tsearch related object caches. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tsearch/ts_cache.h + * + *------------------------------------------------------------------------- + */ +#ifndef TS_CACHE_H +#define TS_CACHE_H + +#include "utils/guc.h" + + +/* + * All TS*CacheEntry structs must share this common header + * (see InvalidateTSCacheCallBack) + */ +typedef struct TSAnyCacheEntry +{ + Oid objId; + bool isvalid; +} TSAnyCacheEntry; + + +typedef struct TSParserCacheEntry +{ + /* prsId is the hash lookup key and MUST BE FIRST */ + Oid prsId; /* OID of the parser */ + bool isvalid; + + Oid startOid; + Oid tokenOid; + Oid endOid; + Oid headlineOid; + Oid lextypeOid; + + /* + * Pre-set-up fmgr call of most needed parser's methods + */ + FmgrInfo prsstart; + FmgrInfo prstoken; + FmgrInfo prsend; + FmgrInfo prsheadline; +} TSParserCacheEntry; + +typedef struct TSDictionaryCacheEntry +{ + /* dictId is the hash lookup key and MUST BE FIRST */ + Oid dictId; + bool isvalid; + + /* most frequent fmgr call */ + Oid lexizeOid; + FmgrInfo lexize; + + MemoryContext dictCtx; /* memory context to store private data */ + void *dictData; +} TSDictionaryCacheEntry; + +typedef struct +{ + int len; + Oid *dictIds; +} ListDictionary; + +typedef struct +{ + /* cfgId is the hash lookup key and MUST BE FIRST */ + Oid cfgId; + bool isvalid; + + Oid prsId; + + int lenmap; + ListDictionary *map; +} TSConfigCacheEntry; + + +/* + * GUC variable for current configuration + */ +extern PGDLLIMPORT char *TSCurrentConfig; + + +extern TSParserCacheEntry *lookup_ts_parser_cache(Oid prsId); +extern TSDictionaryCacheEntry *lookup_ts_dictionary_cache(Oid dictId); +extern TSConfigCacheEntry *lookup_ts_config_cache(Oid cfgId); + +extern Oid getTSCurrentConfig(bool emitError); +extern bool check_TSCurrentConfig(char **newval, void **extra, GucSource source); +extern void assign_TSCurrentConfig(const char *newval, void *extra); + +#endif /* TS_CACHE_H */ diff --git a/src/include/tsearch/ts_locale.h b/src/include/tsearch/ts_locale.h new file mode 100644 index 0000000..7d7c4e1 --- /dev/null +++ b/src/include/tsearch/ts_locale.h @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * ts_locale.h + * locale compatibility layer for tsearch + * + * Copyright (c) 1998-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/ts_locale.h + * + *------------------------------------------------------------------------- + */ +#ifndef __TSLOCALE_H__ +#define __TSLOCALE_H__ + +#include <ctype.h> +#include <limits.h> + +#include "lib/stringinfo.h" +#include "mb/pg_wchar.h" +#include "utils/pg_locale.h" + +/* + * towlower() and friends should be in <wctype.h>, but some pre-C99 systems + * declare them in <wchar.h>, so include that too. + */ +#include <wchar.h> +#ifdef HAVE_WCTYPE_H +#include <wctype.h> +#endif + +/* working state for tsearch_readline (should be a local var in caller) */ +typedef struct +{ + FILE *fp; + const char *filename; + int lineno; + StringInfoData buf; /* current input line, in UTF-8 */ + char *curline; /* current input line, in DB's encoding */ + /* curline may be NULL, or equal to buf.data, or a palloc'd string */ + ErrorContextCallback cb; +} tsearch_readline_state; + +#define TOUCHAR(x) (*((const unsigned char *) (x))) + +/* The second argument of t_iseq() must be a plain ASCII character */ +#define t_iseq(x,c) (TOUCHAR(x) == (unsigned char) (c)) + +#define COPYCHAR(d,s) memcpy(d, s, pg_mblen(s)) + +extern int t_isdigit(const char *ptr); +extern int t_isspace(const char *ptr); +extern int t_isalpha(const char *ptr); +extern int t_isprint(const char *ptr); + +extern char *lowerstr(const char *str); +extern char *lowerstr_with_len(const char *str, int len); + +extern bool tsearch_readline_begin(tsearch_readline_state *stp, + const char *filename); +extern char *tsearch_readline(tsearch_readline_state *stp); +extern void tsearch_readline_end(tsearch_readline_state *stp); + +#endif /* __TSLOCALE_H__ */ diff --git a/src/include/tsearch/ts_public.h b/src/include/tsearch/ts_public.h new file mode 100644 index 0000000..fe2a167 --- /dev/null +++ b/src/include/tsearch/ts_public.h @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------- + * + * ts_public.h + * Public interface to various tsearch modules, such as + * parsers and dictionaries. + * + * Copyright (c) 1998-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/ts_public.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PG_TS_PUBLIC_H_ +#define _PG_TS_PUBLIC_H_ + +#include "tsearch/ts_type.h" + +/* + * Parser's framework + */ + +/* + * returning type for prslextype method of parser + */ +typedef struct +{ + int lexid; + char *alias; + char *descr; +} LexDescr; + +/* + * Interface to headline generator (tsparser's prsheadline function) + * + * HeadlineParsedText describes the text that is to be highlighted. + * Some fields are passed from the core code to the prsheadline function, + * while others are output from the prsheadline function. + * + * The principal data is words[], an array of HeadlineWordEntry, + * one entry per token, of length curwords. + * The fields of HeadlineWordEntry are: + * + * in, selected, replace, skip: these flags are initially zero + * and may be set by the prsheadline function. A consecutive group + * of tokens marked "in" form a "fragment" to be output. + * Such tokens may additionally be marked selected, replace, or skip + * to modify how they are shown. (If you set more than one of those + * bits, you get an unspecified one of those behaviors.) + * + * type, len, pos, word: filled by core code to describe the token. + * + * item: if the token matches any operand of the tsquery of interest, + * a pointer to such an operand. (If there are multiple matching + * operands, we generate extra copies of the HeadlineWordEntry to hold + * all the pointers. The extras are marked with repeated = 1 and should + * be ignored except for checking the item pointer.) + */ +typedef struct +{ + uint32 selected:1, /* token is to be highlighted */ + in:1, /* token is part of headline */ + replace:1, /* token is to be replaced with a space */ + repeated:1, /* duplicate entry to hold item pointer */ + skip:1, /* token is to be skipped (not output) */ + unused:3, /* available bits */ + type:8, /* parser's token category */ + len:16; /* length of token */ + WordEntryPos pos; /* position of token */ + char *word; /* text of token (not null-terminated) */ + QueryOperand *item; /* a matching query operand, or NULL if none */ +} HeadlineWordEntry; + +typedef struct +{ + /* Fields filled by core code before calling prsheadline function: */ + HeadlineWordEntry *words; + int32 lenwords; /* allocated length of words[] */ + int32 curwords; /* current number of valid entries */ + int32 vectorpos; /* used by ts_parse.c in filling pos fields */ + + /* The prsheadline function must fill these fields: */ + /* Strings for marking selected tokens and separating fragments: */ + char *startsel; /* palloc'd strings */ + char *stopsel; + char *fragdelim; + int16 startsellen; /* lengths of strings */ + int16 stopsellen; + int16 fragdelimlen; +} HeadlineParsedText; + +/* + * Common useful things for tsearch subsystem + */ +extern char *get_tsearch_config_filename(const char *basename, + const char *extension); + +/* + * Often useful stopword list management + */ +typedef struct +{ + int len; + char **stop; +} StopList; + +extern void readstoplist(const char *fname, StopList *s, + char *(*wordop) (const char *)); +extern bool searchstoplist(StopList *s, char *key); + +/* + * Interface with dictionaries + */ + +/* return struct for any lexize function */ +typedef struct +{ + /*---------- + * Number of current variant of split word. For example the Norwegian + * word 'fotballklubber' has two variants to split: ( fotball, klubb ) + * and ( fot, ball, klubb ). So, dictionary should return: + * + * nvariant lexeme + * 1 fotball + * 1 klubb + * 2 fot + * 2 ball + * 2 klubb + * + * In general, a TSLexeme will be considered to belong to the same split + * variant as the previous one if they have the same nvariant value. + * The exact values don't matter, only changes from one lexeme to next. + *---------- + */ + uint16 nvariant; + + uint16 flags; /* See flag bits below */ + + char *lexeme; /* C string */ +} TSLexeme; + +/* Flag bits that can appear in TSLexeme.flags */ +#define TSL_ADDPOS 0x01 +#define TSL_PREFIX 0x02 +#define TSL_FILTER 0x04 + +/* + * Struct for supporting complex dictionaries like thesaurus. + * 4th argument for dictlexize method is a pointer to this + */ +typedef struct +{ + bool isend; /* in: marks for lexize_info about text end is + * reached */ + bool getnext; /* out: dict wants next lexeme */ + void *private_state; /* internal dict state between calls with + * getnext == true */ +} DictSubState; + +#endif /* _PG_TS_PUBLIC_H_ */ diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h new file mode 100644 index 0000000..689b2d1 --- /dev/null +++ b/src/include/tsearch/ts_type.h @@ -0,0 +1,242 @@ +/*------------------------------------------------------------------------- + * + * ts_type.h + * Definitions for the tsvector and tsquery types + * + * Copyright (c) 1998-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/ts_type.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PG_TSTYPE_H_ +#define _PG_TSTYPE_H_ + +#include "fmgr.h" +#include "utils/memutils.h" + + +/* + * TSVector type. + * + * Structure of tsvector datatype: + * 1) standard varlena header + * 2) int32 size - number of lexemes (WordEntry array entries) + * 3) Array of WordEntry - one per lexeme; must be sorted according to + * tsCompareString() (ie, memcmp of lexeme strings). + * WordEntry->pos gives the number of bytes from end of WordEntry + * array to start of lexeme's string, which is of length len. + * 4) Per-lexeme data storage: + * lexeme string (not null-terminated) + * if haspos is true: + * padding byte if necessary to make the position data 2-byte aligned + * uint16 number of positions that follow + * WordEntryPos[] positions + * + * The positions for each lexeme must be sorted. + * + * Note, tsvectorsend/recv believe that sizeof(WordEntry) == 4 + */ + +typedef struct +{ + uint32 + haspos:1, + len:11, /* MAX 2Kb */ + pos:20; /* MAX 1Mb */ +} WordEntry; + +#define MAXSTRLEN ( (1<<11) - 1) +#define MAXSTRPOS ( (1<<20) - 1) + +extern int compareWordEntryPos(const void *a, const void *b); + +/* + * Equivalent to + * typedef struct { + * uint16 + * weight:2, + * pos:14; + * } + */ + +typedef uint16 WordEntryPos; + +typedef struct +{ + uint16 npos; + WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]; +} WordEntryPosVector; + +/* WordEntryPosVector with exactly 1 entry */ +typedef struct +{ + uint16 npos; + WordEntryPos pos[1]; +} WordEntryPosVector1; + + +#define WEP_GETWEIGHT(x) ( (x) >> 14 ) +#define WEP_GETPOS(x) ( (x) & 0x3fff ) + +#define WEP_SETWEIGHT(x,v) ( (x) = ( (v) << 14 ) | ( (x) & 0x3fff ) ) +#define WEP_SETPOS(x,v) ( (x) = ( (x) & 0xc000 ) | ( (v) & 0x3fff ) ) + +#define MAXENTRYPOS (1<<14) +#define MAXNUMPOS (256) +#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) ) + +/* This struct represents a complete tsvector datum */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 size; + WordEntry entries[FLEXIBLE_ARRAY_MEMBER]; + /* lexemes follow the entries[] array */ +} TSVectorData; + +typedef TSVectorData *TSVector; + +#define DATAHDRSIZE (offsetof(TSVectorData, entries)) +#define CALCDATASIZE(nentries, lenstr) (DATAHDRSIZE + (nentries) * sizeof(WordEntry) + (lenstr) ) + +/* pointer to start of a tsvector's WordEntry array */ +#define ARRPTR(x) ( (x)->entries ) + +/* pointer to start of a tsvector's lexeme storage */ +#define STRPTR(x) ( (char *) &(x)->entries[(x)->size] ) + +#define _POSVECPTR(x, e) ((WordEntryPosVector *)(STRPTR(x) + SHORTALIGN((e)->pos + (e)->len))) +#define POSDATALEN(x,e) ( ( (e)->haspos ) ? (_POSVECPTR(x,e)->npos) : 0 ) +#define POSDATAPTR(x,e) (_POSVECPTR(x,e)->pos) + +/* + * fmgr interface macros + */ + +#define DatumGetTSVector(X) ((TSVector) PG_DETOAST_DATUM(X)) +#define DatumGetTSVectorCopy(X) ((TSVector) PG_DETOAST_DATUM_COPY(X)) +#define TSVectorGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_TSVECTOR(n) DatumGetTSVector(PG_GETARG_DATUM(n)) +#define PG_GETARG_TSVECTOR_COPY(n) DatumGetTSVectorCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_TSVECTOR(x) return TSVectorGetDatum(x) + + +/* + * TSQuery + * + * + */ + +typedef int8 QueryItemType; + +/* Valid values for QueryItemType: */ +#define QI_VAL 1 +#define QI_OPR 2 +#define QI_VALSTOP 3 /* This is only used in an intermediate stack + * representation in parse_tsquery. It's not a + * legal type elsewhere. */ + +/* + * QueryItem is one node in tsquery - operator or operand. + */ +typedef struct +{ + QueryItemType type; /* operand or kind of operator (ts_tokentype) */ + uint8 weight; /* weights of operand to search. It's a + * bitmask of allowed weights. if it =0 then + * any weight are allowed. Weights and bit + * map: A: 1<<3 B: 1<<2 C: 1<<1 D: 1<<0 */ + bool prefix; /* true if it's a prefix search */ + int32 valcrc; /* XXX: pg_crc32 would be a more appropriate + * data type, but we use comparisons to signed + * integers in the code. They would need to be + * changed as well. */ + + /* pointer to text value of operand, must correlate with WordEntry */ + uint32 + length:12, + distance:20; +} QueryOperand; + + +/* + * Legal values for QueryOperator.operator. + */ +#define OP_NOT 1 +#define OP_AND 2 +#define OP_OR 3 +#define OP_PHRASE 4 /* highest code, tsquery_cleanup.c */ +#define OP_COUNT 4 + +extern PGDLLIMPORT const int tsearch_op_priority[OP_COUNT]; + +/* get operation priority by its code */ +#define OP_PRIORITY(x) ( tsearch_op_priority[(x) - 1] ) +/* get QueryOperator priority */ +#define QO_PRIORITY(x) OP_PRIORITY(((QueryOperator *) (x))->oper) + +typedef struct +{ + QueryItemType type; + int8 oper; /* see above */ + int16 distance; /* distance between agrs for OP_PHRASE */ + uint32 left; /* pointer to left operand. Right operand is + * item + 1, left operand is placed + * item+item->left */ +} QueryOperator; + +/* + * Note: TSQuery is 4-bytes aligned, so make sure there's no fields + * inside QueryItem requiring 8-byte alignment, like int64. + */ +typedef union +{ + QueryItemType type; + QueryOperator qoperator; + QueryOperand qoperand; +} QueryItem; + +/* + * Storage: + * (len)(size)(array of QueryItem)(operands as '\0'-terminated c-strings) + */ + +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 size; /* number of QueryItems */ + char data[FLEXIBLE_ARRAY_MEMBER]; /* data starts here */ +} TSQueryData; + +typedef TSQueryData *TSQuery; + +#define HDRSIZETQ ( VARHDRSZ + sizeof(int32) ) + +/* Computes the size of header and all QueryItems. size is the number of + * QueryItems, and lenofoperand is the total length of all operands + */ +#define COMPUTESIZE(size, lenofoperand) ( HDRSIZETQ + (size) * sizeof(QueryItem) + (lenofoperand) ) +#define TSQUERY_TOO_BIG(size, lenofoperand) \ + ((size) > (MaxAllocSize - HDRSIZETQ - (lenofoperand)) / sizeof(QueryItem)) + +/* Returns a pointer to the first QueryItem in a TSQuery */ +#define GETQUERY(x) ((QueryItem*)( (char*)(x)+HDRSIZETQ )) + +/* Returns a pointer to the beginning of operands in a TSQuery */ +#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((TSQuery)(x))->size * sizeof(QueryItem) ) + +/* + * fmgr interface macros + * Note, TSQuery type marked as plain storage, so it can't be toasted + * but PG_DETOAST_DATUM_COPY is used for simplicity + */ + +#define DatumGetTSQuery(X) ((TSQuery) DatumGetPointer(X)) +#define DatumGetTSQueryCopy(X) ((TSQuery) PG_DETOAST_DATUM_COPY(X)) +#define TSQueryGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_TSQUERY(n) DatumGetTSQuery(PG_GETARG_DATUM(n)) +#define PG_GETARG_TSQUERY_COPY(n) DatumGetTSQueryCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_TSQUERY(x) return TSQueryGetDatum(x) + +#endif /* _PG_TSTYPE_H_ */ diff --git a/src/include/tsearch/ts_utils.h b/src/include/tsearch/ts_utils.h new file mode 100644 index 0000000..c36c711 --- /dev/null +++ b/src/include/tsearch/ts_utils.h @@ -0,0 +1,266 @@ +/*------------------------------------------------------------------------- + * + * ts_utils.h + * helper utilities for tsearch + * + * Copyright (c) 1998-2022, PostgreSQL Global Development Group + * + * src/include/tsearch/ts_utils.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PG_TS_UTILS_H_ +#define _PG_TS_UTILS_H_ + +#include "nodes/pg_list.h" +#include "tsearch/ts_public.h" +#include "tsearch/ts_type.h" + +/* + * Common parse definitions for tsvector and tsquery + */ + +/* tsvector parser support. */ + +struct TSVectorParseStateData; /* opaque struct in tsvector_parser.c */ +typedef struct TSVectorParseStateData *TSVectorParseState; + +#define P_TSV_OPR_IS_DELIM (1 << 0) +#define P_TSV_IS_TSQUERY (1 << 1) +#define P_TSV_IS_WEB (1 << 2) + +extern TSVectorParseState init_tsvector_parser(char *input, int flags); +extern void reset_tsvector_parser(TSVectorParseState state, char *input); +extern bool gettoken_tsvector(TSVectorParseState state, + char **token, int *len, + WordEntryPos **pos, int *poslen, + char **endptr); +extern void close_tsvector_parser(TSVectorParseState state); + +/* phrase operator begins with '<' */ +#define ISOPERATOR(x) \ + ( pg_mblen(x) == 1 && ( *(x) == '!' || \ + *(x) == '&' || \ + *(x) == '|' || \ + *(x) == '(' || \ + *(x) == ')' || \ + *(x) == '<' \ + ) ) + +/* parse_tsquery */ + +struct TSQueryParserStateData; /* private in backend/utils/adt/tsquery.c */ +typedef struct TSQueryParserStateData *TSQueryParserState; + +typedef void (*PushFunction) (Datum opaque, TSQueryParserState state, + char *token, int tokenlen, + int16 tokenweights, /* bitmap as described in + * QueryOperand struct */ + bool prefix); + +#define P_TSQ_PLAIN (1 << 0) +#define P_TSQ_WEB (1 << 1) + +extern TSQuery parse_tsquery(char *buf, + PushFunction pushval, + Datum opaque, + int flags); + +/* Functions for use by PushFunction implementations */ +extern void pushValue(TSQueryParserState state, + char *strval, int lenval, int16 weight, bool prefix); +extern void pushStop(TSQueryParserState state); +extern void pushOperator(TSQueryParserState state, int8 oper, int16 distance); + +/* + * parse plain text and lexize words + */ +typedef struct +{ + uint16 len; + uint16 nvariant; + union + { + uint16 pos; + + /* + * When apos array is used, apos[0] is the number of elements in the + * array (excluding apos[0]), and alen is the allocated size of the + * array. + */ + uint16 *apos; + } pos; + uint16 flags; /* currently, only TSL_PREFIX */ + char *word; + uint32 alen; +} ParsedWord; + +typedef struct +{ + ParsedWord *words; + int32 lenwords; + int32 curwords; + int32 pos; +} ParsedText; + +extern void parsetext(Oid cfgId, ParsedText *prs, char *buf, int32 buflen); + +/* + * headline framework, flow in common to generate: + * 1 parse text with hlparsetext + * 2 parser-specific function to find part + * 3 generateHeadline to generate result text + */ + +extern void hlparsetext(Oid cfgId, HeadlineParsedText *prs, TSQuery query, + char *buf, int32 buflen); +extern text *generateHeadline(HeadlineParsedText *prs); + +/* + * TSQuery execution support + * + * TS_execute() executes a tsquery against data that can be represented in + * various forms. The TSExecuteCallback callback function is called to check + * whether a given primitive tsquery value is matched in the data. + */ + +/* TS_execute requires ternary logic to handle NOT with phrase matches */ +typedef enum +{ + TS_NO, /* definitely no match */ + TS_YES, /* definitely does match */ + TS_MAYBE /* can't verify match for lack of pos data */ +} TSTernaryValue; + +/* + * struct ExecPhraseData is passed to a TSExecuteCallback function if we need + * lexeme position data (because of a phrase-match operator in the tsquery). + * The callback should fill in position data when it returns TS_YES (success). + * If it cannot return position data, it should leave "data" unchanged and + * return TS_MAYBE. The caller of TS_execute() must then arrange for a later + * recheck with position data available. + * + * The reported lexeme positions must be sorted and unique. Callers must only + * consult the position bits of the pos array, ie, WEP_GETPOS(data->pos[i]). + * This allows the returned "pos" to point directly to the WordEntryPos + * portion of a tsvector value. If "allocated" is true then the pos array + * is palloc'd workspace and caller may free it when done. + * + * "negate" means that the pos array contains positions where the query does + * not match, rather than positions where it does. "width" is positive when + * the match is wider than one lexeme. Neither of these fields normally need + * to be touched by TSExecuteCallback functions; they are used for + * phrase-search processing within TS_execute. + * + * All fields of the ExecPhraseData struct are initially zeroed by caller. + */ +typedef struct ExecPhraseData +{ + int npos; /* number of positions reported */ + bool allocated; /* pos points to palloc'd data? */ + bool negate; /* positions are where query is NOT matched */ + WordEntryPos *pos; /* ordered, non-duplicate lexeme positions */ + int width; /* width of match in lexemes, less 1 */ +} ExecPhraseData; + +/* + * Signature for TSQuery lexeme check functions + * + * arg: opaque value passed through from caller of TS_execute + * val: lexeme to test for presence of + * data: to be filled with lexeme positions; NULL if position data not needed + * + * Return TS_YES if lexeme is present in data, TS_MAYBE if it might be + * present, TS_NO if it definitely is not present. If data is not NULL, + * it must be filled with lexeme positions if available. If position data + * is not available, leave *data as zeroes and return TS_MAYBE, never TS_YES. + */ +typedef TSTernaryValue (*TSExecuteCallback) (void *arg, QueryOperand *val, + ExecPhraseData *data); + +/* + * Flag bits for TS_execute + */ +#define TS_EXEC_EMPTY (0x00) +/* + * If TS_EXEC_SKIP_NOT is set, then NOT sub-expressions are automatically + * evaluated to be true. This was formerly the default behavior. It's now + * deprecated because it tends to give silly answers, but some applications + * might still have a use for it. + */ +#define TS_EXEC_SKIP_NOT (0x01) +/* + * If TS_EXEC_PHRASE_NO_POS is set, allow OP_PHRASE to be executed lossily + * in the absence of position information: a true result indicates that the + * phrase might be present. Without this flag, OP_PHRASE always returns + * false if lexeme position information is not available. + */ +#define TS_EXEC_PHRASE_NO_POS (0x02) + +extern bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, + TSExecuteCallback chkcond); +extern TSTernaryValue TS_execute_ternary(QueryItem *curitem, void *arg, + uint32 flags, + TSExecuteCallback chkcond); +extern bool tsquery_requires_match(QueryItem *curitem); + +/* + * to_ts* - text transformation to tsvector, tsquery + */ +extern TSVector make_tsvector(ParsedText *prs); +extern int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix); + +/* + * Possible strategy numbers for indexes + * TSearchStrategyNumber - (tsvector|text) @@ tsquery + * TSearchWithClassStrategyNumber - tsvector @@@ tsquery + */ +#define TSearchStrategyNumber 1 +#define TSearchWithClassStrategyNumber 2 + +/* + * TSQuery Utilities + */ +extern QueryItem *clean_NOT(QueryItem *ptr, int32 *len); +extern TSQuery cleanup_tsquery_stopwords(TSQuery in); + +typedef struct QTNode +{ + QueryItem *valnode; + uint32 flags; + int32 nchild; + char *word; + uint32 sign; + struct QTNode **child; +} QTNode; + +/* bits in QTNode.flags */ +#define QTN_NEEDFREE 0x01 +#define QTN_NOCHANGE 0x02 +#define QTN_WORDFREE 0x04 + +typedef uint64 TSQuerySign; + +#define TSQS_SIGLEN (sizeof(TSQuerySign)*BITS_PER_BYTE) + +#define TSQuerySignGetDatum(X) Int64GetDatum((int64) (X)) +#define DatumGetTSQuerySign(X) ((TSQuerySign) DatumGetInt64(X)) +#define PG_RETURN_TSQUERYSIGN(X) return TSQuerySignGetDatum(X) +#define PG_GETARG_TSQUERYSIGN(n) DatumGetTSQuerySign(PG_GETARG_DATUM(n)) + + +extern QTNode *QT2QTN(QueryItem *in, char *operand); +extern TSQuery QTN2QT(QTNode *in); +extern void QTNFree(QTNode *in); +extern void QTNSort(QTNode *in); +extern void QTNTernary(QTNode *in); +extern void QTNBinary(QTNode *in); +extern int QTNodeCompare(QTNode *an, QTNode *bn); +extern QTNode *QTNCopy(QTNode *in); +extern void QTNClearFlags(QTNode *in, uint32 flags); +extern bool QTNEq(QTNode *a, QTNode *b); +extern TSQuerySign makeTSQuerySign(TSQuery a); +extern QTNode *findsubquery(QTNode *root, QTNode *ex, QTNode *subs, + bool *isfind); + +#endif /* _PG_TS_UTILS_H_ */ diff --git a/src/include/utils/.gitignore b/src/include/utils/.gitignore new file mode 100644 index 0000000..05cfa7a --- /dev/null +++ b/src/include/utils/.gitignore @@ -0,0 +1,5 @@ +/fmgroids.h +/fmgrprotos.h +/probes.h +/errcodes.h +/header-stamp diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h new file mode 100644 index 0000000..48f7d72 --- /dev/null +++ b/src/include/utils/acl.h @@ -0,0 +1,333 @@ +/*------------------------------------------------------------------------- + * + * acl.h + * Definition of (and support for) access control list data structures. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/acl.h + * + * NOTES + * An ACL array is simply an array of AclItems, representing the union + * of the privileges represented by the individual items. A zero-length + * array represents "no privileges". + * + * The order of items in the array is important as client utilities (in + * particular, pg_dump, though possibly other clients) expect to be able + * to issue GRANTs in the ordering of the items in the array. The reason + * this matters is that GRANTs WITH GRANT OPTION must be before any GRANTs + * which depend on it. This happens naturally in the backend during + * operations as we update ACLs in-place, new items are appended, and + * existing entries are only removed if there's no dependency on them (no + * GRANT can been based on it, or, if there was, those GRANTs are also + * removed). + * + * For backward-compatibility purposes we have to allow null ACL entries + * in system catalogs. A null ACL will be treated as meaning "default + * protection" (i.e., whatever acldefault() returns). + *------------------------------------------------------------------------- + */ +#ifndef ACL_H +#define ACL_H + +#include "access/htup.h" +#include "nodes/parsenodes.h" +#include "parser/parse_node.h" +#include "utils/snapshot.h" + + +/* + * typedef AclMode is declared in parsenodes.h, also the individual privilege + * bit meanings are defined there + */ + +#define ACL_ID_PUBLIC 0 /* placeholder for id in a PUBLIC acl item */ + +/* + * AclItem + * + * Note: must be same size on all platforms, because the size is hardcoded + * in the pg_type.h entry for aclitem. + */ +typedef struct AclItem +{ + Oid ai_grantee; /* ID that this item grants privs to */ + Oid ai_grantor; /* grantor of privs */ + AclMode ai_privs; /* privilege bits */ +} AclItem; + +/* + * The upper 16 bits of the ai_privs field of an AclItem are the grant option + * bits, and the lower 16 bits are the actual privileges. We use "rights" + * to mean the combined grant option and privilege bits fields. + */ +#define ACLITEM_GET_PRIVS(item) ((item).ai_privs & 0xFFFF) +#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 16) & 0xFFFF) +#define ACLITEM_GET_RIGHTS(item) ((item).ai_privs) + +#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0xFFFF) << 16) +#define ACL_OPTION_TO_PRIVS(privs) (((AclMode) (privs) >> 16) & 0xFFFF) + +#define ACLITEM_SET_PRIVS(item,privs) \ + ((item).ai_privs = ((item).ai_privs & ~((AclMode) 0xFFFF)) | \ + ((AclMode) (privs) & 0xFFFF)) +#define ACLITEM_SET_GOPTIONS(item,goptions) \ + ((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0xFFFF) << 16)) | \ + (((AclMode) (goptions) & 0xFFFF) << 16)) +#define ACLITEM_SET_RIGHTS(item,rights) \ + ((item).ai_privs = (AclMode) (rights)) + +#define ACLITEM_SET_PRIVS_GOPTIONS(item,privs,goptions) \ + ((item).ai_privs = ((AclMode) (privs) & 0xFFFF) | \ + (((AclMode) (goptions) & 0xFFFF) << 16)) + + +#define ACLITEM_ALL_PRIV_BITS ((AclMode) 0xFFFF) +#define ACLITEM_ALL_GOPTION_BITS ((AclMode) 0xFFFF << 16) + +/* + * Definitions for convenient access to Acl (array of AclItem). + * These are standard PostgreSQL arrays, but are restricted to have one + * dimension and no nulls. We also ignore the lower bound when reading, + * and set it to one when writing. + * + * CAUTION: as of PostgreSQL 7.1, these arrays are toastable (just like all + * other array types). Therefore, be careful to detoast them with the + * macros provided, unless you know for certain that a particular array + * can't have been toasted. + */ + + +/* + * Acl a one-dimensional array of AclItem + */ +typedef struct ArrayType Acl; + +#define ACL_NUM(ACL) (ARR_DIMS(ACL)[0]) +#define ACL_DAT(ACL) ((AclItem *) ARR_DATA_PTR(ACL)) +#define ACL_N_SIZE(N) (ARR_OVERHEAD_NONULLS(1) + ((N) * sizeof(AclItem))) +#define ACL_SIZE(ACL) ARR_SIZE(ACL) + +/* + * fmgr macros for these types + */ +#define DatumGetAclItemP(X) ((AclItem *) DatumGetPointer(X)) +#define PG_GETARG_ACLITEM_P(n) DatumGetAclItemP(PG_GETARG_DATUM(n)) +#define PG_RETURN_ACLITEM_P(x) PG_RETURN_POINTER(x) + +#define DatumGetAclP(X) ((Acl *) PG_DETOAST_DATUM(X)) +#define DatumGetAclPCopy(X) ((Acl *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_ACL_P(n) DatumGetAclP(PG_GETARG_DATUM(n)) +#define PG_GETARG_ACL_P_COPY(n) DatumGetAclPCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_ACL_P(x) PG_RETURN_POINTER(x) + +/* + * ACL modification opcodes for aclupdate + */ +#define ACL_MODECHG_ADD 1 +#define ACL_MODECHG_DEL 2 +#define ACL_MODECHG_EQL 3 + +/* + * External representations of the privilege bits --- aclitemin/aclitemout + * represent each possible privilege bit with a distinct 1-character code + */ +#define ACL_INSERT_CHR 'a' /* formerly known as "append" */ +#define ACL_SELECT_CHR 'r' /* formerly known as "read" */ +#define ACL_UPDATE_CHR 'w' /* formerly known as "write" */ +#define ACL_DELETE_CHR 'd' +#define ACL_TRUNCATE_CHR 'D' /* super-delete, as it were */ +#define ACL_REFERENCES_CHR 'x' +#define ACL_TRIGGER_CHR 't' +#define ACL_EXECUTE_CHR 'X' +#define ACL_USAGE_CHR 'U' +#define ACL_CREATE_CHR 'C' +#define ACL_CREATE_TEMP_CHR 'T' +#define ACL_CONNECT_CHR 'c' +#define ACL_SET_CHR 's' +#define ACL_ALTER_SYSTEM_CHR 'A' + +/* string holding all privilege code chars, in order by bitmask position */ +#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTcsA" + +/* + * Bitmasks defining "all rights" for each supported object type + */ +#define ACL_ALL_RIGHTS_COLUMN (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_REFERENCES) +#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_TRUNCATE|ACL_REFERENCES|ACL_TRIGGER) +#define ACL_ALL_RIGHTS_SEQUENCE (ACL_USAGE|ACL_SELECT|ACL_UPDATE) +#define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT) +#define ACL_ALL_RIGHTS_FDW (ACL_USAGE) +#define ACL_ALL_RIGHTS_FOREIGN_SERVER (ACL_USAGE) +#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) +#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE) +#define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE) +#define ACL_ALL_RIGHTS_PARAMETER_ACL (ACL_SET|ACL_ALTER_SYSTEM) +#define ACL_ALL_RIGHTS_SCHEMA (ACL_USAGE|ACL_CREATE) +#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE) +#define ACL_ALL_RIGHTS_TYPE (ACL_USAGE) + +/* operation codes for pg_*_aclmask */ +typedef enum +{ + ACLMASK_ALL, /* normal case: compute all bits */ + ACLMASK_ANY /* return when result is known nonzero */ +} AclMaskHow; + +/* result codes for pg_*_aclcheck */ +typedef enum +{ + ACLCHECK_OK = 0, + ACLCHECK_NO_PRIV, + ACLCHECK_NOT_OWNER +} AclResult; + + +/* + * routines used internally + */ +extern Acl *acldefault(ObjectType objtype, Oid ownerId); +extern Acl *get_user_default_acl(ObjectType objtype, Oid ownerId, + Oid nsp_oid); +extern void recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId, + Oid ownerId, Acl *acl); + +extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip, + int modechg, Oid ownerId, DropBehavior behavior); +extern Acl *aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId); +extern Acl *make_empty_acl(void); +extern Acl *aclcopy(const Acl *orig_acl); +extern Acl *aclconcat(const Acl *left_acl, const Acl *right_acl); +extern Acl *aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId); +extern void aclitemsort(Acl *acl); +extern bool aclequal(const Acl *left_acl, const Acl *right_acl); + +extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, + AclMode mask, AclMaskHow how); +extern int aclmembers(const Acl *acl, Oid **roleids); + +extern bool has_privs_of_role(Oid member, Oid role); +extern bool is_member_of_role(Oid member, Oid role); +extern bool is_member_of_role_nosuper(Oid member, Oid role); +extern bool is_admin_of_role(Oid member, Oid role); +extern void check_is_member_of_role(Oid member, Oid role); +extern Oid get_role_oid(const char *rolename, bool missing_ok); +extern Oid get_role_oid_or_public(const char *rolename); +extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok); +extern void check_rolespec_name(const RoleSpec *role, const char *detail_msg); +extern HeapTuple get_rolespec_tuple(const RoleSpec *role); +extern char *get_rolespec_name(const RoleSpec *role); + +extern void select_best_grantor(Oid roleId, AclMode privileges, + const Acl *acl, Oid ownerId, + Oid *grantorId, AclMode *grantOptions); + +extern void initialize_acl(void); + +/* + * prototypes for functions in aclchk.c + */ +extern void ExecuteGrantStmt(GrantStmt *stmt); +extern void ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt); + +extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid); + +extern AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mask, AclMaskHow how); +extern AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mask, + AclMaskHow how, bool *is_missing); +extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing); +extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_parameter_aclmask(const char *name, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, + AclMode mask, AclMaskHow how, Snapshot snapshot); +extern AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, + AclMode mask, AclMaskHow how); +extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid, + AclMode mask, AclMaskHow how); + +extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mode); +extern AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mode, + bool *is_missing); +extern AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, + AclMode mode, AclMaskHow how); +extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode); +extern AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, + AclMode mode, bool *is_missing); +extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode); +extern AclResult pg_parameter_aclcheck(const char *name, Oid roleid, + AclMode mode); +extern AclResult pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid, + AclMode mode); +extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode); +extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode); +extern AclResult pg_largeobject_aclcheck_snapshot(Oid lang_oid, Oid roleid, + AclMode mode, Snapshot snapshot); +extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode); +extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); +extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode); +extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode); +extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode); + +extern void aclcheck_error(AclResult aclerr, ObjectType objtype, + const char *objectname); + +extern void aclcheck_error_col(AclResult aclerr, ObjectType objtype, + const char *objectname, const char *colname); + +extern void aclcheck_error_type(AclResult aclerr, Oid typeOid); + +extern void recordExtObjInitPriv(Oid objoid, Oid classoid); +extern void removeExtObjInitPriv(Oid objoid, Oid classoid); + + +/* ownercheck routines just return true (owner) or false (not) */ +extern bool pg_class_ownercheck(Oid class_oid, Oid roleid); +extern bool pg_type_ownercheck(Oid type_oid, Oid roleid); +extern bool pg_oper_ownercheck(Oid oper_oid, Oid roleid); +extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid); +extern bool pg_language_ownercheck(Oid lan_oid, Oid roleid); +extern bool pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid); +extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid); +extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid); +extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid); +extern bool pg_opfamily_ownercheck(Oid opf_oid, Oid roleid); +extern bool pg_database_ownercheck(Oid db_oid, Oid roleid); +extern bool pg_collation_ownercheck(Oid coll_oid, Oid roleid); +extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid); +extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid); +extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid); +extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid); +extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid); +extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid); +extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid); +extern bool pg_publication_ownercheck(Oid pub_oid, Oid roleid); +extern bool pg_subscription_ownercheck(Oid sub_oid, Oid roleid); +extern bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid); +extern bool has_createrole_privilege(Oid roleid); +extern bool has_bypassrls_privilege(Oid roleid); + +#endif /* ACL_H */ diff --git a/src/include/utils/aclchk_internal.h b/src/include/utils/aclchk_internal.h new file mode 100644 index 0000000..361284d --- /dev/null +++ b/src/include/utils/aclchk_internal.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * aclchk_internal.h + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/aclchk_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef ACLCHK_INTERNAL_H +#define ACLCHK_INTERNAL_H + +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" + +/* + * The information about one Grant/Revoke statement, in internal format: object + * and grantees names have been turned into Oids, the privilege list is an + * AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and + * all_privs is true, 'privileges' will be internally set to the right kind of + * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the + * InternalGrant struct!) + * + * Note: 'all_privs' and 'privileges' represent object-level privileges only. + * There might also be column-level privilege specifications, which are + * represented in col_privs (this is a list of untransformed AccessPriv nodes). + * Column privileges are only valid for objtype OBJECT_TABLE. + */ +typedef struct +{ + bool is_grant; + ObjectType objtype; + List *objects; + bool all_privs; + AclMode privileges; + List *col_privs; + List *grantees; + bool grant_option; + DropBehavior behavior; +} InternalGrant; + + +#endif /* ACLCHK_INTERNAL_H */ diff --git a/src/include/utils/array.h b/src/include/utils/array.h new file mode 100644 index 0000000..b4327b4 --- /dev/null +++ b/src/include/utils/array.h @@ -0,0 +1,471 @@ +/*------------------------------------------------------------------------- + * + * array.h + * Declarations for Postgres arrays. + * + * A standard varlena array has the following internal structure: + * <vl_len_> - standard varlena header word + * <ndim> - number of dimensions of the array + * <dataoffset> - offset to stored data, or 0 if no nulls bitmap + * <elemtype> - element type OID + * <dimensions> - length of each array axis (C array of int) + * <lower bnds> - lower boundary of each dimension (C array of int) + * <null bitmap> - bitmap showing locations of nulls (OPTIONAL) + * <actual data> - whatever is the stored data + * + * The <dimensions> and <lower bnds> arrays each have ndim elements. + * + * The <null bitmap> may be omitted if the array contains no NULL elements. + * If it is absent, the <dataoffset> field is zero and the offset to the + * stored data must be computed on-the-fly. If the bitmap is present, + * <dataoffset> is nonzero and is equal to the offset from the array start + * to the first data element (including any alignment padding). The bitmap + * follows the same conventions as tuple null bitmaps, ie, a 1 indicates + * a non-null entry and the LSB of each bitmap byte is used first. + * + * The actual data starts on a MAXALIGN boundary. Individual items in the + * array are aligned as specified by the array element type. They are + * stored in row-major order (last subscript varies most rapidly). + * + * NOTE: it is important that array elements of toastable datatypes NOT be + * toasted, since the tupletoaster won't know they are there. (We could + * support compressed toasted items; only out-of-line items are dangerous. + * However, it seems preferable to store such items uncompressed and allow + * the toaster to compress the whole array as one input.) + * + * + * The OIDVECTOR and INT2VECTOR datatypes are storage-compatible with + * generic arrays, but they support only one-dimensional arrays with no + * nulls (and no null bitmap). They don't support being toasted, either. + * + * There are also some "fixed-length array" datatypes, such as NAME and + * POINT. These are simply a sequence of a fixed number of items each + * of a fixed-length datatype, with no overhead; the item size must be + * a multiple of its alignment requirement, because we do no padding. + * We support subscripting on these types, but array_in() and array_out() + * only work with varlena arrays. + * + * In addition, arrays are a major user of the "expanded object" TOAST + * infrastructure. This allows a varlena array to be converted to a + * separate representation that may include "deconstructed" Datum/isnull + * arrays holding the elements. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/array.h + * + *------------------------------------------------------------------------- + */ +#ifndef ARRAY_H +#define ARRAY_H + +#include "fmgr.h" +#include "utils/expandeddatum.h" + +/* avoid including execnodes.h here */ +struct ExprState; +struct ExprContext; + + +/* + * Maximum number of array subscripts (arbitrary limit) + */ +#define MAXDIM 6 + +/* + * Maximum number of elements in an array. We limit this to at most about a + * quarter billion elements, so that it's not necessary to check for overflow + * in quite so many places --- for instance when palloc'ing Datum arrays. + */ +#define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum))) + +/* + * Arrays are varlena objects, so must meet the varlena convention that + * the first int32 of the object contains the total object size in bytes. + * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! + * + * CAUTION: if you change the header for ordinary arrays you will also + * need to change the headers for oidvector and int2vector! + */ +typedef struct ArrayType +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int ndim; /* # of dimensions */ + int32 dataoffset; /* offset to data, or 0 if no bitmap */ + Oid elemtype; /* element type OID */ +} ArrayType; + +/* + * An expanded array is contained within a private memory context (as + * all expanded objects must be) and has a control structure as below. + * + * The expanded array might contain a regular "flat" array if that was the + * original input and we've not modified it significantly. Otherwise, the + * contents are represented by Datum/isnull arrays plus dimensionality and + * type information. We could also have both forms, if we've deconstructed + * the original array for access purposes but not yet changed it. For pass- + * by-reference element types, the Datums would point into the flat array in + * this situation. Once we start modifying array elements, new pass-by-ref + * elements are separately palloc'd within the memory context. + */ +#define EA_MAGIC 689375833 /* ID for debugging crosschecks */ + +typedef struct ExpandedArrayHeader +{ + /* Standard header for expanded objects */ + ExpandedObjectHeader hdr; + + /* Magic value identifying an expanded array (for debugging only) */ + int ea_magic; + + /* Dimensionality info (always valid) */ + int ndims; /* # of dimensions */ + int *dims; /* array dimensions */ + int *lbound; /* index lower bounds for each dimension */ + + /* Element type info (always valid) */ + Oid element_type; /* element type OID */ + int16 typlen; /* needed info about element datatype */ + bool typbyval; + char typalign; + + /* + * If we have a Datum-array representation of the array, it's kept here; + * else dvalues/dnulls are NULL. The dvalues and dnulls arrays are always + * palloc'd within the object private context, but may change size from + * time to time. For pass-by-ref element types, dvalues entries might + * point either into the fstartptr..fendptr area, or to separately + * palloc'd chunks. Elements should always be fully detoasted, as they + * are in the standard flat representation. + * + * Even when dvalues is valid, dnulls can be NULL if there are no null + * elements. + */ + Datum *dvalues; /* array of Datums */ + bool *dnulls; /* array of is-null flags for Datums */ + int dvalueslen; /* allocated length of above arrays */ + int nelems; /* number of valid entries in above arrays */ + + /* + * flat_size is the current space requirement for the flat equivalent of + * the expanded array, if known; otherwise it's 0. We store this to make + * consecutive calls of get_flat_size cheap. + */ + Size flat_size; + + /* + * fvalue points to the flat representation if it is valid, else it is + * NULL. If we have or ever had a flat representation then + * fstartptr/fendptr point to the start and end+1 of its data area; this + * is so that we can tell which Datum pointers point into the flat + * representation rather than being pointers to separately palloc'd data. + */ + ArrayType *fvalue; /* must be a fully detoasted array */ + char *fstartptr; /* start of its data area */ + char *fendptr; /* end+1 of its data area */ +} ExpandedArrayHeader; + +/* + * Functions that can handle either a "flat" varlena array or an expanded + * array use this union to work with their input. Don't refer to "flt"; + * instead, cast to ArrayType. This struct nominally requires 8-byte + * alignment on 64-bit, but it's often used for an ArrayType having 4-byte + * alignment. UBSan complains about referencing "flt" in such cases. + */ +typedef union AnyArrayType +{ + ArrayType flt; + ExpandedArrayHeader xpn; +} AnyArrayType; + +/* + * working state for accumArrayResult() and friends + * note that the input must be scalars (legal array elements) + */ +typedef struct ArrayBuildState +{ + MemoryContext mcontext; /* where all the temp stuff is kept */ + Datum *dvalues; /* array of accumulated Datums */ + bool *dnulls; /* array of is-null flags for Datums */ + int alen; /* allocated length of above arrays */ + int nelems; /* number of valid entries in above arrays */ + Oid element_type; /* data type of the Datums */ + int16 typlen; /* needed info about datatype */ + bool typbyval; + char typalign; + bool private_cxt; /* use private memory context */ +} ArrayBuildState; + +/* + * working state for accumArrayResultArr() and friends + * note that the input must be arrays, and the same array type is returned + */ +typedef struct ArrayBuildStateArr +{ + MemoryContext mcontext; /* where all the temp stuff is kept */ + char *data; /* accumulated data */ + bits8 *nullbitmap; /* bitmap of is-null flags, or NULL if none */ + int abytes; /* allocated length of "data" */ + int nbytes; /* number of bytes used so far */ + int aitems; /* allocated length of bitmap (in elements) */ + int nitems; /* total number of elements in result */ + int ndims; /* current dimensions of result */ + int dims[MAXDIM]; + int lbs[MAXDIM]; + Oid array_type; /* data type of the arrays */ + Oid element_type; /* data type of the array elements */ + bool private_cxt; /* use private memory context */ +} ArrayBuildStateArr; + +/* + * working state for accumArrayResultAny() and friends + * these functions handle both cases + */ +typedef struct ArrayBuildStateAny +{ + /* Exactly one of these is not NULL: */ + ArrayBuildState *scalarstate; + ArrayBuildStateArr *arraystate; +} ArrayBuildStateAny; + +/* + * structure to cache type metadata needed for array manipulation + */ +typedef struct ArrayMetaState +{ + Oid element_type; + int16 typlen; + bool typbyval; + char typalign; + char typdelim; + Oid typioparam; + Oid typiofunc; + FmgrInfo proc; +} ArrayMetaState; + +/* + * private state needed by array_map (here because caller must provide it) + */ +typedef struct ArrayMapState +{ + ArrayMetaState inp_extra; + ArrayMetaState ret_extra; +} ArrayMapState; + +/* ArrayIteratorData is private in arrayfuncs.c */ +typedef struct ArrayIteratorData *ArrayIterator; + +/* fmgr macros for regular varlena array objects */ +#define DatumGetArrayTypeP(X) ((ArrayType *) PG_DETOAST_DATUM(X)) +#define DatumGetArrayTypePCopy(X) ((ArrayType *) PG_DETOAST_DATUM_COPY(X)) +#define PG_GETARG_ARRAYTYPE_P(n) DatumGetArrayTypeP(PG_GETARG_DATUM(n)) +#define PG_GETARG_ARRAYTYPE_P_COPY(n) DatumGetArrayTypePCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_ARRAYTYPE_P(x) PG_RETURN_POINTER(x) + +/* fmgr macros for expanded array objects */ +#define PG_GETARG_EXPANDED_ARRAY(n) DatumGetExpandedArray(PG_GETARG_DATUM(n)) +#define PG_GETARG_EXPANDED_ARRAYX(n, metacache) \ + DatumGetExpandedArrayX(PG_GETARG_DATUM(n), metacache) +#define PG_RETURN_EXPANDED_ARRAY(x) PG_RETURN_DATUM(EOHPGetRWDatum(&(x)->hdr)) + +/* fmgr macros for AnyArrayType (ie, get either varlena or expanded form) */ +#define PG_GETARG_ANY_ARRAY_P(n) DatumGetAnyArrayP(PG_GETARG_DATUM(n)) + +/* + * Access macros for varlena array header fields. + * + * ARR_DIMS returns a pointer to an array of array dimensions (number of + * elements along the various array axes). + * + * ARR_LBOUND returns a pointer to an array of array lower bounds. + * + * That is: if the third axis of an array has elements 5 through 8, then + * ARR_DIMS(a)[2] == 4 and ARR_LBOUND(a)[2] == 5. + * + * Unlike C, the default lower bound is 1. + */ +#define ARR_SIZE(a) VARSIZE(a) +#define ARR_NDIM(a) ((a)->ndim) +#define ARR_HASNULL(a) ((a)->dataoffset != 0) +#define ARR_ELEMTYPE(a) ((a)->elemtype) + +#define ARR_DIMS(a) \ + ((int *) (((char *) (a)) + sizeof(ArrayType))) +#define ARR_LBOUND(a) \ + ((int *) (((char *) (a)) + sizeof(ArrayType) + \ + sizeof(int) * ARR_NDIM(a))) + +#define ARR_NULLBITMAP(a) \ + (ARR_HASNULL(a) ? \ + (bits8 *) (((char *) (a)) + sizeof(ArrayType) + \ + 2 * sizeof(int) * ARR_NDIM(a)) \ + : (bits8 *) NULL) + +/* + * The total array header size (in bytes) for an array with the specified + * number of dimensions and total number of items. + */ +#define ARR_OVERHEAD_NONULLS(ndims) \ + MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims)) +#define ARR_OVERHEAD_WITHNULLS(ndims, nitems) \ + MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims) + \ + ((nitems) + 7) / 8) + +#define ARR_DATA_OFFSET(a) \ + (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a))) + +/* + * Returns a pointer to the actual array data. + */ +#define ARR_DATA_PTR(a) \ + (((char *) (a)) + ARR_DATA_OFFSET(a)) + +/* + * Macros for working with AnyArrayType inputs. Beware multiple references! + */ +#define AARR_NDIM(a) \ + (VARATT_IS_EXPANDED_HEADER(a) ? \ + (a)->xpn.ndims : ARR_NDIM((ArrayType *) (a))) +#define AARR_HASNULL(a) \ + (VARATT_IS_EXPANDED_HEADER(a) ? \ + ((a)->xpn.dvalues != NULL ? (a)->xpn.dnulls != NULL : ARR_HASNULL((a)->xpn.fvalue)) : \ + ARR_HASNULL((ArrayType *) (a))) +#define AARR_ELEMTYPE(a) \ + (VARATT_IS_EXPANDED_HEADER(a) ? \ + (a)->xpn.element_type : ARR_ELEMTYPE((ArrayType *) (a))) +#define AARR_DIMS(a) \ + (VARATT_IS_EXPANDED_HEADER(a) ? \ + (a)->xpn.dims : ARR_DIMS((ArrayType *) (a))) +#define AARR_LBOUND(a) \ + (VARATT_IS_EXPANDED_HEADER(a) ? \ + (a)->xpn.lbound : ARR_LBOUND((ArrayType *) (a))) + + +/* + * GUC parameter + */ +extern PGDLLIMPORT bool Array_nulls; + +/* + * prototypes for functions defined in arrayfuncs.c + */ +extern void CopyArrayEls(ArrayType *array, + Datum *values, + bool *nulls, + int nitems, + int typlen, + bool typbyval, + char typalign, + bool freedata); + +extern Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, + int arraytyplen, int elmlen, bool elmbyval, char elmalign, + bool *isNull); +extern Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, + Datum dataValue, bool isNull, + int arraytyplen, int elmlen, bool elmbyval, char elmalign); +extern Datum array_get_slice(Datum arraydatum, int nSubscripts, + int *upperIndx, int *lowerIndx, + bool *upperProvided, bool *lowerProvided, + int arraytyplen, int elmlen, bool elmbyval, char elmalign); +extern Datum array_set_slice(Datum arraydatum, int nSubscripts, + int *upperIndx, int *lowerIndx, + bool *upperProvided, bool *lowerProvided, + Datum srcArrayDatum, bool isNull, + int arraytyplen, int elmlen, bool elmbyval, char elmalign); + +extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, + int arraytyplen, int elmlen, bool elmbyval, char elmalign, + bool *isNull); +extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, + Datum dataValue, bool isNull, + int arraytyplen, int elmlen, bool elmbyval, char elmalign); + +extern Datum array_map(Datum arrayd, + struct ExprState *exprstate, struct ExprContext *econtext, + Oid retType, ArrayMapState *amstate); + +extern void array_bitmap_copy(bits8 *destbitmap, int destoffset, + const bits8 *srcbitmap, int srcoffset, + int nitems); + +extern ArrayType *construct_array(Datum *elems, int nelems, + Oid elmtype, + int elmlen, bool elmbyval, char elmalign); +extern ArrayType *construct_md_array(Datum *elems, + bool *nulls, + int ndims, + int *dims, + int *lbs, + Oid elmtype, int elmlen, bool elmbyval, char elmalign); +extern ArrayType *construct_empty_array(Oid elmtype); +extern ExpandedArrayHeader *construct_empty_expanded_array(Oid element_type, + MemoryContext parentcontext, + ArrayMetaState *metacache); +extern void deconstruct_array(ArrayType *array, + Oid elmtype, + int elmlen, bool elmbyval, char elmalign, + Datum **elemsp, bool **nullsp, int *nelemsp); +extern bool array_contains_nulls(ArrayType *array); + +extern ArrayBuildState *initArrayResult(Oid element_type, + MemoryContext rcontext, bool subcontext); +extern ArrayBuildState *accumArrayResult(ArrayBuildState *astate, + Datum dvalue, bool disnull, + Oid element_type, + MemoryContext rcontext); +extern Datum makeArrayResult(ArrayBuildState *astate, + MemoryContext rcontext); +extern Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, + int *dims, int *lbs, MemoryContext rcontext, bool release); + +extern ArrayBuildStateArr *initArrayResultArr(Oid array_type, Oid element_type, + MemoryContext rcontext, bool subcontext); +extern ArrayBuildStateArr *accumArrayResultArr(ArrayBuildStateArr *astate, + Datum dvalue, bool disnull, + Oid array_type, + MemoryContext rcontext); +extern Datum makeArrayResultArr(ArrayBuildStateArr *astate, + MemoryContext rcontext, bool release); + +extern ArrayBuildStateAny *initArrayResultAny(Oid input_type, + MemoryContext rcontext, bool subcontext); +extern ArrayBuildStateAny *accumArrayResultAny(ArrayBuildStateAny *astate, + Datum dvalue, bool disnull, + Oid input_type, + MemoryContext rcontext); +extern Datum makeArrayResultAny(ArrayBuildStateAny *astate, + MemoryContext rcontext, bool release); + +extern ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate); +extern bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull); +extern void array_free_iterator(ArrayIterator iterator); + +/* + * prototypes for functions defined in arrayutils.c + */ + +extern int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx); +extern int ArrayGetOffset0(int n, const int *tup, const int *scale); +extern int ArrayGetNItems(int ndim, const int *dims); +extern void ArrayCheckBounds(int ndim, const int *dims, const int *lb); +extern void mda_get_range(int n, int *span, const int *st, const int *endp); +extern void mda_get_prod(int n, const int *range, int *prod); +extern void mda_get_offset_values(int n, int *dist, const int *prod, const int *span); +extern int mda_next_tuple(int n, int *curr, const int *span); +extern int32 *ArrayGetIntegerTypmods(ArrayType *arr, int *n); + +/* + * prototypes for functions defined in array_expanded.c + */ +extern Datum expand_array(Datum arraydatum, MemoryContext parentcontext, + ArrayMetaState *metacache); +extern ExpandedArrayHeader *DatumGetExpandedArray(Datum d); +extern ExpandedArrayHeader *DatumGetExpandedArrayX(Datum d, + ArrayMetaState *metacache); +extern AnyArrayType *DatumGetAnyArrayP(Datum d); +extern void deconstruct_expanded_array(ExpandedArrayHeader *eah); + +#endif /* ARRAY_H */ diff --git a/src/include/utils/arrayaccess.h b/src/include/utils/arrayaccess.h new file mode 100644 index 0000000..7ad01d0 --- /dev/null +++ b/src/include/utils/arrayaccess.h @@ -0,0 +1,118 @@ +/*------------------------------------------------------------------------- + * + * arrayaccess.h + * Declarations for element-by-element access to Postgres arrays. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/arrayaccess.h + * + *------------------------------------------------------------------------- + */ +#ifndef ARRAYACCESS_H +#define ARRAYACCESS_H + +#include "access/tupmacs.h" +#include "utils/array.h" + + +/* + * Functions for iterating through elements of a flat or expanded array. + * These require a state struct "array_iter iter". + * + * Use "array_iter_setup(&iter, arrayptr);" to prepare to iterate, and + * "datumvar = array_iter_next(&iter, &isnullvar, index, ...);" to fetch + * the next element into datumvar/isnullvar. + * "index" must be the zero-origin element number; we make caller provide + * this since caller is generally counting the elements anyway. Despite + * that, these functions can only fetch elements sequentially. + */ + +typedef struct array_iter +{ + /* datumptr being NULL or not tells if we have flat or expanded array */ + + /* Fields used when we have an expanded array */ + Datum *datumptr; /* Pointer to Datum array */ + bool *isnullptr; /* Pointer to isnull array */ + + /* Fields used when we have a flat array */ + char *dataptr; /* Current spot in the data area */ + bits8 *bitmapptr; /* Current byte of the nulls bitmap, or NULL */ + int bitmask; /* mask for current bit in nulls bitmap */ +} array_iter; + + +static inline void +array_iter_setup(array_iter *it, AnyArrayType *a) +{ + if (VARATT_IS_EXPANDED_HEADER(a)) + { + if (a->xpn.dvalues) + { + it->datumptr = a->xpn.dvalues; + it->isnullptr = a->xpn.dnulls; + /* we must fill all fields to prevent compiler warnings */ + it->dataptr = NULL; + it->bitmapptr = NULL; + } + else + { + /* Work with flat array embedded in the expanded datum */ + it->datumptr = NULL; + it->isnullptr = NULL; + it->dataptr = ARR_DATA_PTR(a->xpn.fvalue); + it->bitmapptr = ARR_NULLBITMAP(a->xpn.fvalue); + } + } + else + { + it->datumptr = NULL; + it->isnullptr = NULL; + it->dataptr = ARR_DATA_PTR((ArrayType *) a); + it->bitmapptr = ARR_NULLBITMAP((ArrayType *) a); + } + it->bitmask = 1; +} + +static inline Datum +array_iter_next(array_iter *it, bool *isnull, int i, + int elmlen, bool elmbyval, char elmalign) +{ + Datum ret; + + if (it->datumptr) + { + ret = it->datumptr[i]; + *isnull = it->isnullptr ? it->isnullptr[i] : false; + } + else + { + if (it->bitmapptr && (*(it->bitmapptr) & it->bitmask) == 0) + { + *isnull = true; + ret = (Datum) 0; + } + else + { + *isnull = false; + ret = fetch_att(it->dataptr, elmbyval, elmlen); + it->dataptr = att_addlength_pointer(it->dataptr, elmlen, + it->dataptr); + it->dataptr = (char *) att_align_nominal(it->dataptr, elmalign); + } + it->bitmask <<= 1; + if (it->bitmask == 0x100) + { + if (it->bitmapptr) + it->bitmapptr++; + it->bitmask = 1; + } + } + + return ret; +} + +#endif /* ARRAYACCESS_H */ diff --git a/src/include/utils/ascii.h b/src/include/utils/ascii.h new file mode 100644 index 0000000..aed8019 --- /dev/null +++ b/src/include/utils/ascii.h @@ -0,0 +1,16 @@ +/*----------------------------------------------------------------------- + * ascii.h + * + * Portions Copyright (c) 1999-2022, PostgreSQL Global Development Group + * + * src/include/utils/ascii.h + * + *----------------------------------------------------------------------- + */ + +#ifndef _ASCII_H_ +#define _ASCII_H_ + +extern void ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz); + +#endif /* _ASCII_H_ */ diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h new file mode 100644 index 0000000..ee37af9 --- /dev/null +++ b/src/include/utils/attoptcache.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * attoptcache.h + * Attribute options cache. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/attoptcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef ATTOPTCACHE_H +#define ATTOPTCACHE_H + +/* + * Attribute options. + */ +typedef struct AttributeOpts +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + float8 n_distinct; + float8 n_distinct_inherited; +} AttributeOpts; + +extern AttributeOpts *get_attribute_options(Oid spcid, int attnum); + +#endif /* ATTOPTCACHE_H */ diff --git a/src/include/utils/backend_progress.h b/src/include/utils/backend_progress.h new file mode 100644 index 0000000..47bf802 --- /dev/null +++ b/src/include/utils/backend_progress.h @@ -0,0 +1,44 @@ +/* ---------- + * backend_progress.h + * Command progress reporting definition. + * + * Note that this file provides the infrastructure for storing a single + * backend's command progress counters, without ascribing meaning to the + * individual fields. See commands/progress.h and system_views.sql for that. + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/utils/backend_progress.h + * ---------- + */ +#ifndef BACKEND_PROGRESS_H +#define BACKEND_PROGRESS_H + + +/* ---------- + * Command type for progress reporting purposes + * ---------- + */ +typedef enum ProgressCommandType +{ + PROGRESS_COMMAND_INVALID, + PROGRESS_COMMAND_VACUUM, + PROGRESS_COMMAND_ANALYZE, + PROGRESS_COMMAND_CLUSTER, + PROGRESS_COMMAND_CREATE_INDEX, + PROGRESS_COMMAND_BASEBACKUP, + PROGRESS_COMMAND_COPY +} ProgressCommandType; + +#define PGSTAT_NUM_PROGRESS_PARAM 20 + + +extern void pgstat_progress_start_command(ProgressCommandType cmdtype, + Oid relid); +extern void pgstat_progress_update_param(int index, int64 val); +extern void pgstat_progress_update_multi_param(int nparam, const int *index, + const int64 *val); +extern void pgstat_progress_end_command(void); + + +#endif /* BACKEND_PROGRESS_H */ diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h new file mode 100644 index 0000000..7403bca --- /dev/null +++ b/src/include/utils/backend_status.h @@ -0,0 +1,321 @@ +/* ---------- + * backend_status.h + * Definitions related to backend status reporting + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/utils/backend_status.h + * ---------- + */ +#ifndef BACKEND_STATUS_H +#define BACKEND_STATUS_H + +#include "datatype/timestamp.h" +#include "libpq/pqcomm.h" +#include "miscadmin.h" /* for BackendType */ +#include "utils/backend_progress.h" + + +/* ---------- + * Backend states + * ---------- + */ +typedef enum BackendState +{ + STATE_UNDEFINED, + STATE_IDLE, + STATE_RUNNING, + STATE_IDLEINTRANSACTION, + STATE_FASTPATH, + STATE_IDLEINTRANSACTION_ABORTED, + STATE_DISABLED +} BackendState; + + +/* ---------- + * Shared-memory data structures + * ---------- + */ + +/* + * PgBackendSSLStatus + * + * For each backend, we keep the SSL status in a separate struct, that + * is only filled in if SSL is enabled. + * + * All char arrays must be null-terminated. + */ +typedef struct PgBackendSSLStatus +{ + /* Information about SSL connection */ + int ssl_bits; + char ssl_version[NAMEDATALEN]; + char ssl_cipher[NAMEDATALEN]; + char ssl_client_dn[NAMEDATALEN]; + + /* + * serial number is max "20 octets" per RFC 5280, so this size should be + * fine + */ + char ssl_client_serial[NAMEDATALEN]; + + char ssl_issuer_dn[NAMEDATALEN]; +} PgBackendSSLStatus; + +/* + * PgBackendGSSStatus + * + * For each backend, we keep the GSS status in a separate struct, that + * is only filled in if GSS is enabled. + * + * All char arrays must be null-terminated. + */ +typedef struct PgBackendGSSStatus +{ + /* Information about GSSAPI connection */ + char gss_princ[NAMEDATALEN]; /* GSSAPI Principal used to auth */ + bool gss_auth; /* If GSSAPI authentication was used */ + bool gss_enc; /* If encryption is being used */ + +} PgBackendGSSStatus; + + +/* ---------- + * PgBackendStatus + * + * Each live backend maintains a PgBackendStatus struct in shared memory + * showing its current activity. (The structs are allocated according to + * BackendId, but that is not critical.) Note that this is unrelated to the + * cumulative stats system (i.e. pgstat.c et al). + * + * Each auxiliary process also maintains a PgBackendStatus struct in shared + * memory. + * ---------- + */ +typedef struct PgBackendStatus +{ + /* + * To avoid locking overhead, we use the following protocol: a backend + * increments st_changecount before modifying its entry, and again after + * finishing a modification. A would-be reader should note the value of + * st_changecount, copy the entry into private memory, then check + * st_changecount again. If the value hasn't changed, and if it's even, + * the copy is valid; otherwise start over. This makes updates cheap + * while reads are potentially expensive, but that's the tradeoff we want. + * + * The above protocol needs memory barriers to ensure that the apparent + * order of execution is as it desires. Otherwise, for example, the CPU + * might rearrange the code so that st_changecount is incremented twice + * before the modification on a machine with weak memory ordering. Hence, + * use the macros defined below for manipulating st_changecount, rather + * than touching it directly. + */ + int st_changecount; + + /* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */ + int st_procpid; + + /* Type of backends */ + BackendType st_backendType; + + /* Times when current backend, transaction, and activity started */ + TimestampTz st_proc_start_timestamp; + TimestampTz st_xact_start_timestamp; + TimestampTz st_activity_start_timestamp; + TimestampTz st_state_start_timestamp; + + /* Database OID, owning user's OID, connection client address */ + Oid st_databaseid; + Oid st_userid; + SockAddr st_clientaddr; + char *st_clienthostname; /* MUST be null-terminated */ + + /* Information about SSL connection */ + bool st_ssl; + PgBackendSSLStatus *st_sslstatus; + + /* Information about GSSAPI connection */ + bool st_gss; + PgBackendGSSStatus *st_gssstatus; + + /* current state */ + BackendState st_state; + + /* application name; MUST be null-terminated */ + char *st_appname; + + /* + * Current command string; MUST be null-terminated. Note that this string + * possibly is truncated in the middle of a multi-byte character. As + * activity strings are stored more frequently than read, that allows to + * move the cost of correct truncation to the display side. Use + * pgstat_clip_activity() to truncate correctly. + */ + char *st_activity_raw; + + /* + * Command progress reporting. Any command which wishes can advertise + * that it is running by setting st_progress_command, + * st_progress_command_target, and st_progress_param[]. + * st_progress_command_target should be the OID of the relation which the + * command targets (we assume there's just one, as this is meant for + * utility commands), but the meaning of each element in the + * st_progress_param array is command-specific. + */ + ProgressCommandType st_progress_command; + Oid st_progress_command_target; + int64 st_progress_param[PGSTAT_NUM_PROGRESS_PARAM]; + + /* query identifier, optionally computed using post_parse_analyze_hook */ + uint64 st_query_id; +} PgBackendStatus; + + +/* + * Macros to load and store st_changecount with appropriate memory barriers. + * + * Use PGSTAT_BEGIN_WRITE_ACTIVITY() before, and PGSTAT_END_WRITE_ACTIVITY() + * after, modifying the current process's PgBackendStatus data. Note that, + * since there is no mechanism for cleaning up st_changecount after an error, + * THESE MACROS FORM A CRITICAL SECTION. Any error between them will be + * promoted to PANIC, causing a database restart to clean up shared memory! + * Hence, keep the critical section as short and straight-line as possible. + * Aside from being safer, that minimizes the window in which readers will + * have to loop. + * + * Reader logic should follow this sketch: + * + * for (;;) + * { + * int before_ct, after_ct; + * + * pgstat_begin_read_activity(beentry, before_ct); + * ... copy beentry data to local memory ... + * pgstat_end_read_activity(beentry, after_ct); + * if (pgstat_read_activity_complete(before_ct, after_ct)) + * break; + * CHECK_FOR_INTERRUPTS(); + * } + * + * For extra safety, we generally use volatile beentry pointers, although + * the memory barriers should theoretically be sufficient. + */ +#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry) \ + do { \ + START_CRIT_SECTION(); \ + (beentry)->st_changecount++; \ + pg_write_barrier(); \ + } while (0) + +#define PGSTAT_END_WRITE_ACTIVITY(beentry) \ + do { \ + pg_write_barrier(); \ + (beentry)->st_changecount++; \ + Assert(((beentry)->st_changecount & 1) == 0); \ + END_CRIT_SECTION(); \ + } while (0) + +#define pgstat_begin_read_activity(beentry, before_changecount) \ + do { \ + (before_changecount) = (beentry)->st_changecount; \ + pg_read_barrier(); \ + } while (0) + +#define pgstat_end_read_activity(beentry, after_changecount) \ + do { \ + pg_read_barrier(); \ + (after_changecount) = (beentry)->st_changecount; \ + } while (0) + +#define pgstat_read_activity_complete(before_changecount, after_changecount) \ + ((before_changecount) == (after_changecount) && \ + ((before_changecount) & 1) == 0) + + +/* ---------- + * LocalPgBackendStatus + * + * When we build the backend status array, we use LocalPgBackendStatus to be + * able to add new values to the struct when needed without adding new fields + * to the shared memory. It contains the backend status as a first member. + * ---------- + */ +typedef struct LocalPgBackendStatus +{ + /* + * Local version of the backend status entry. + */ + PgBackendStatus backendStatus; + + /* + * The xid of the current transaction if available, InvalidTransactionId + * if not. + */ + TransactionId backend_xid; + + /* + * The xmin of the current session if available, InvalidTransactionId if + * not. + */ + TransactionId backend_xmin; +} LocalPgBackendStatus; + + +/* ---------- + * GUC parameters + * ---------- + */ +extern PGDLLIMPORT bool pgstat_track_activities; +extern PGDLLIMPORT int pgstat_track_activity_query_size; + + +/* ---------- + * Other global variables + * ---------- + */ +extern PGDLLIMPORT PgBackendStatus *MyBEEntry; + + +/* ---------- + * Functions called from postmaster + * ---------- + */ +extern Size BackendStatusShmemSize(void); +extern void CreateSharedBackendStatus(void); + + +/* ---------- + * Functions called from backends + * ---------- + */ + +/* Initialization functions */ +extern void pgstat_beinit(void); +extern void pgstat_bestart(void); + +extern void pgstat_clear_backend_activity_snapshot(void); + +/* Activity reporting functions */ +extern void pgstat_report_activity(BackendState state, const char *cmd_str); +extern void pgstat_report_query_id(uint64 query_id, bool force); +extern void pgstat_report_tempfile(size_t filesize); +extern void pgstat_report_appname(const char *appname); +extern void pgstat_report_xact_timestamp(TimestampTz tstamp); +extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser); +extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer, + int buflen); +extern uint64 pgstat_get_my_query_id(void); + + +/* ---------- + * Support functions for the SQL-callable functions to + * generate the pgstat* views. + * ---------- + */ +extern int pgstat_fetch_stat_numbackends(void); +extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid); +extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid); +extern char *pgstat_clip_activity(const char *raw_activity); + + +#endif /* BACKEND_STATUS_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h new file mode 100644 index 0000000..221c3e6 --- /dev/null +++ b/src/include/utils/builtins.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------- + * + * builtins.h + * Declarations for operations on built-in types. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/builtins.h + * + *------------------------------------------------------------------------- + */ +#ifndef BUILTINS_H +#define BUILTINS_H + +#include "fmgr.h" +#include "nodes/nodes.h" +#include "utils/fmgrprotos.h" + +/* Sign + the most decimal digits an 8-byte number could have */ +#define MAXINT8LEN 20 + +/* bool.c */ +extern bool parse_bool(const char *value, bool *result); +extern bool parse_bool_with_len(const char *value, size_t len, bool *result); + +/* domains.c */ +extern void domain_check(Datum value, bool isnull, Oid domainType, + void **extra, MemoryContext mcxt); +extern int errdatatype(Oid datatypeOid); +extern int errdomainconstraint(Oid datatypeOid, const char *conname); + +/* encode.c */ +extern uint64 hex_encode(const char *src, size_t len, char *dst); +extern uint64 hex_decode(const char *src, size_t len, char *dst); + +/* int.c */ +extern int2vector *buildint2vector(const int16 *int2s, int n); + +/* name.c */ +extern void namestrcpy(Name name, const char *str); +extern int namestrcmp(Name name, const char *str); + +/* numutils.c */ +extern int16 pg_strtoint16(const char *s); +extern int32 pg_strtoint32(const char *s); +extern int64 pg_strtoint64(const char *s); +extern int pg_itoa(int16 i, char *a); +extern int pg_ultoa_n(uint32 l, char *a); +extern int pg_ulltoa_n(uint64 l, char *a); +extern int pg_ltoa(int32 l, char *a); +extern int pg_lltoa(int64 ll, char *a); +extern char *pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth); +extern char *pg_ultostr(char *str, uint32 value); + +/* oid.c */ +extern oidvector *buildoidvector(const Oid *oids, int n); +extern Oid oidparse(Node *node); +extern int oid_cmp(const void *p1, const void *p2); + +/* regexp.c */ +extern char *regexp_fixed_prefix(text *text_re, bool case_insensitive, + Oid collation, bool *exact); + +/* ruleutils.c */ +extern PGDLLIMPORT bool quote_all_identifiers; +extern const char *quote_identifier(const char *ident); +extern char *quote_qualified_identifier(const char *qualifier, + const char *ident); +extern void generate_operator_clause(fmStringInfo buf, + const char *leftop, Oid leftoptype, + Oid opoid, + const char *rightop, Oid rightoptype); + +/* varchar.c */ +extern int bpchartruelen(char *s, int len); + +/* popular functions from varlena.c */ +extern text *cstring_to_text(const char *s); +extern text *cstring_to_text_with_len(const char *s, int len); +extern char *text_to_cstring(const text *t); +extern void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len); + +#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s)) +#define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d)) + +/* xid.c */ +extern int xidComparator(const void *arg1, const void *arg2); +extern int xidLogicalComparator(const void *arg1, const void *arg2); + +/* inet_cidr_ntop.c */ +extern char *pg_inet_cidr_ntop(int af, const void *src, int bits, + char *dst, size_t size); + +/* inet_net_pton.c */ +extern int pg_inet_net_pton(int af, const char *src, + void *dst, size_t size); + +/* network.c */ +extern double convert_network_to_scalar(Datum value, Oid typid, bool *failure); +extern Datum network_scan_first(Datum in); +extern Datum network_scan_last(Datum in); +extern void clean_ipv6_addr(int addr_family, char *addr); + +/* numeric.c */ +extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); + +/* format_type.c */ + +/* Control flags for format_type_extended */ +#define FORMAT_TYPE_TYPEMOD_GIVEN 0x01 /* typemod defined by caller */ +#define FORMAT_TYPE_ALLOW_INVALID 0x02 /* allow invalid types */ +#define FORMAT_TYPE_FORCE_QUALIFY 0x04 /* force qualification of type */ +#define FORMAT_TYPE_INVALID_AS_NULL 0x08 /* NULL if undefined */ +extern char *format_type_extended(Oid type_oid, int32 typemod, bits16 flags); + +extern char *format_type_be(Oid type_oid); +extern char *format_type_be_qualified(Oid type_oid); +extern char *format_type_with_typemod(Oid type_oid, int32 typemod); + +extern int32 type_maximum_size(Oid type_oid, int32 typemod); + +/* quote.c */ +extern char *quote_literal_cstr(const char *rawstr); + +#endif /* BUILTINS_H */ diff --git a/src/include/utils/bytea.h b/src/include/utils/bytea.h new file mode 100644 index 0000000..c3c9e54 --- /dev/null +++ b/src/include/utils/bytea.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * bytea.h + * Declarations for BYTEA data type support. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/bytea.h + * + *------------------------------------------------------------------------- + */ +#ifndef BYTEA_H +#define BYTEA_H + + + +typedef enum +{ + BYTEA_OUTPUT_ESCAPE, + BYTEA_OUTPUT_HEX +} ByteaOutputType; + +extern PGDLLIMPORT int bytea_output; /* ByteaOutputType, but int for GUC + * enum */ + +#endif /* BYTEA_H */ diff --git a/src/include/utils/cash.h b/src/include/utils/cash.h new file mode 100644 index 0000000..2e332d8 --- /dev/null +++ b/src/include/utils/cash.h @@ -0,0 +1,25 @@ +/* + * src/include/utils/cash.h + * + * + * cash.h + * Written by D'Arcy J.M. Cain + * + * Functions to allow input and output of money normally but store + * and handle it as 64 bit integer. + */ + +#ifndef CASH_H +#define CASH_H + +#include "fmgr.h" + +typedef int64 Cash; + +/* Cash is pass-by-reference if and only if int64 is */ +#define DatumGetCash(X) ((Cash) DatumGetInt64(X)) +#define CashGetDatum(X) Int64GetDatum(X) +#define PG_GETARG_CASH(n) DatumGetCash(PG_GETARG_DATUM(n)) +#define PG_RETURN_CASH(x) return CashGetDatum(x) + +#endif /* CASH_H */ diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h new file mode 100644 index 0000000..d81e6fa --- /dev/null +++ b/src/include/utils/catcache.h @@ -0,0 +1,231 @@ +/*------------------------------------------------------------------------- + * + * catcache.h + * Low-level catalog cache definitions. + * + * NOTE: every catalog cache must have a corresponding unique index on + * the system table that it caches --- ie, the index must match the keys + * used to do lookups in this cache. All cache fetches are done with + * indexscans (under normal conditions). The index should be unique to + * guarantee that there can only be one matching row for a key combination. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/catcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef CATCACHE_H +#define CATCACHE_H + +#include "access/htup.h" +#include "access/skey.h" +#include "lib/ilist.h" +#include "utils/relcache.h" + +/* + * struct catctup: individual tuple in the cache. + * struct catclist: list of tuples matching a partial key. + * struct catcache: information for managing a cache. + * struct catcacheheader: information for managing all the caches. + */ + +#define CATCACHE_MAXKEYS 4 + + +/* function computing a datum's hash */ +typedef uint32 (*CCHashFN) (Datum datum); + +/* function computing equality of two datums */ +typedef bool (*CCFastEqualFN) (Datum a, Datum b); + +typedef struct catcache +{ + int id; /* cache identifier --- see syscache.h */ + int cc_nbuckets; /* # of hash buckets in this cache */ + TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */ + dlist_head *cc_bucket; /* hash buckets */ + CCHashFN cc_hashfunc[CATCACHE_MAXKEYS]; /* hash function for each key */ + CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS]; /* fast equal function for + * each key */ + int cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */ + dlist_head cc_lists; /* list of CatCList structs */ + int cc_ntup; /* # of tuples currently in this cache */ + int cc_nkeys; /* # of keys (1..CATCACHE_MAXKEYS) */ + const char *cc_relname; /* name of relation the tuples come from */ + Oid cc_reloid; /* OID of relation the tuples come from */ + Oid cc_indexoid; /* OID of index matching cache keys */ + bool cc_relisshared; /* is relation shared across databases? */ + slist_node cc_next; /* list link */ + ScanKeyData cc_skey[CATCACHE_MAXKEYS]; /* precomputed key info for heap + * scans */ + + /* + * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS + * doesn't break ABI for other modules + */ +#ifdef CATCACHE_STATS + long cc_searches; /* total # searches against this cache */ + long cc_hits; /* # of matches against existing entry */ + long cc_neg_hits; /* # of matches against negative entry */ + long cc_newloads; /* # of successful loads of new entry */ + + /* + * cc_searches - (cc_hits + cc_neg_hits + cc_newloads) is number of failed + * searches, each of which will result in loading a negative entry + */ + long cc_invals; /* # of entries invalidated from cache */ + long cc_lsearches; /* total # list-searches */ + long cc_lhits; /* # of matches against existing lists */ +#endif +} CatCache; + + +typedef struct catctup +{ + int ct_magic; /* for identifying CatCTup entries */ +#define CT_MAGIC 0x57261502 + + uint32 hash_value; /* hash value for this tuple's keys */ + + /* + * Lookup keys for the entry. By-reference datums point into the tuple for + * positive cache entries, and are separately allocated for negative ones. + */ + Datum keys[CATCACHE_MAXKEYS]; + + /* + * Each tuple in a cache is a member of a dlist that stores the elements + * of its hash bucket. We keep each dlist in LRU order to speed repeated + * lookups. + */ + dlist_node cache_elem; /* list member of per-bucket list */ + + /* + * A tuple marked "dead" must not be returned by subsequent searches. + * However, it won't be physically deleted from the cache until its + * refcount goes to zero. (If it's a member of a CatCList, the list's + * refcount must go to zero, too; also, remember to mark the list dead at + * the same time the tuple is marked.) + * + * A negative cache entry is an assertion that there is no tuple matching + * a particular key. This is just as useful as a normal entry so far as + * avoiding catalog searches is concerned. Management of positive and + * negative entries is identical. + */ + int refcount; /* number of active references */ + bool dead; /* dead but not yet removed? */ + bool negative; /* negative cache entry? */ + HeapTupleData tuple; /* tuple management header */ + + /* + * The tuple may also be a member of at most one CatCList. (If a single + * catcache is list-searched with varying numbers of keys, we may have to + * make multiple entries for the same tuple because of this restriction. + * Currently, that's not expected to be common, so we accept the potential + * inefficiency.) + */ + struct catclist *c_list; /* containing CatCList, or NULL if none */ + + CatCache *my_cache; /* link to owning catcache */ + /* properly aligned tuple data follows, unless a negative entry */ +} CatCTup; + + +/* + * A CatCList describes the result of a partial search, ie, a search using + * only the first K key columns of an N-key cache. We store the keys used + * into the keys attribute to represent the stored key set. The CatCList + * object contains links to cache entries for all the table rows satisfying + * the partial key. (Note: none of these will be negative cache entries.) + * + * A CatCList is only a member of a per-cache list; we do not currently + * divide them into hash buckets. + * + * A list marked "dead" must not be returned by subsequent searches. + * However, it won't be physically deleted from the cache until its + * refcount goes to zero. (A list should be marked dead if any of its + * member entries are dead.) + * + * If "ordered" is true then the member tuples appear in the order of the + * cache's underlying index. This will be true in normal operation, but + * might not be true during bootstrap or recovery operations. (namespace.c + * is able to save some cycles when it is true.) + */ +typedef struct catclist +{ + int cl_magic; /* for identifying CatCList entries */ +#define CL_MAGIC 0x52765103 + + uint32 hash_value; /* hash value for lookup keys */ + + dlist_node cache_elem; /* list member of per-catcache list */ + + /* + * Lookup keys for the entry, with the first nkeys elements being valid. + * All by-reference are separately allocated. + */ + Datum keys[CATCACHE_MAXKEYS]; + + int refcount; /* number of active references */ + bool dead; /* dead but not yet removed? */ + bool ordered; /* members listed in index order? */ + short nkeys; /* number of lookup keys specified */ + int n_members; /* number of member tuples */ + CatCache *my_cache; /* link to owning catcache */ + CatCTup *members[FLEXIBLE_ARRAY_MEMBER]; /* members */ +} CatCList; + + +typedef struct catcacheheader +{ + slist_head ch_caches; /* head of list of CatCache structs */ + int ch_ntup; /* # of tuples in all caches */ +} CatCacheHeader; + + +/* this extern duplicates utils/memutils.h... */ +extern PGDLLIMPORT MemoryContext CacheMemoryContext; + +extern void CreateCacheMemoryContext(void); + +extern CatCache *InitCatCache(int id, Oid reloid, Oid indexoid, + int nkeys, const int *key, + int nbuckets); +extern void InitCatCachePhase2(CatCache *cache, bool touch_index); + +extern HeapTuple SearchCatCache(CatCache *cache, + Datum v1, Datum v2, Datum v3, Datum v4); +extern HeapTuple SearchCatCache1(CatCache *cache, + Datum v1); +extern HeapTuple SearchCatCache2(CatCache *cache, + Datum v1, Datum v2); +extern HeapTuple SearchCatCache3(CatCache *cache, + Datum v1, Datum v2, Datum v3); +extern HeapTuple SearchCatCache4(CatCache *cache, + Datum v1, Datum v2, Datum v3, Datum v4); +extern void ReleaseCatCache(HeapTuple tuple); + +extern uint32 GetCatCacheHashValue(CatCache *cache, + Datum v1, Datum v2, + Datum v3, Datum v4); + +extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys, + Datum v1, Datum v2, + Datum v3); +extern void ReleaseCatCacheList(CatCList *list); + +extern void ResetCatalogCaches(void); +extern void CatalogCacheFlushCatalog(Oid catId); +extern void CatCacheInvalidate(CatCache *cache, uint32 hashValue); +extern void PrepareToInvalidateCacheTuple(Relation relation, + HeapTuple tuple, + HeapTuple newtuple, + void (*function) (int, uint32, Oid)); + +extern void PrintCatCacheLeakWarning(HeapTuple tuple); +extern void PrintCatCacheListLeakWarning(CatCList *list); + +#endif /* CATCACHE_H */ diff --git a/src/include/utils/combocid.h b/src/include/utils/combocid.h new file mode 100644 index 0000000..80fe6d2 --- /dev/null +++ b/src/include/utils/combocid.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * combocid.h + * Combo command ID support routines + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/combocid.h + * + *------------------------------------------------------------------------- + */ +#ifndef COMBOCID_H +#define COMBOCID_H + +/* + * HeapTupleHeaderGetCmin and HeapTupleHeaderGetCmax function prototypes + * are in access/htup.h, because that's where the macro definitions that + * those functions replaced used to be. + */ + +extern void AtEOXact_ComboCid(void); +extern void RestoreComboCIDState(char *comboCIDstate); +extern void SerializeComboCIDState(Size maxsize, char *start_address); +extern Size EstimateComboCIDStateSpace(void); + +#endif /* COMBOCID_H */ diff --git a/src/include/utils/date.h b/src/include/utils/date.h new file mode 100644 index 0000000..91ae242 --- /dev/null +++ b/src/include/utils/date.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * date.h + * Definitions for the SQL "date" and "time" types. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/date.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATE_H +#define DATE_H + +#include <math.h> + +#include "datatype/timestamp.h" +#include "fmgr.h" +#include "pgtime.h" + +typedef int32 DateADT; + +typedef int64 TimeADT; + +typedef struct +{ + TimeADT time; /* all time units other than months and years */ + int32 zone; /* numeric time zone, in seconds */ +} TimeTzADT; + +/* + * Infinity and minus infinity must be the max and min values of DateADT. + */ +#define DATEVAL_NOBEGIN ((DateADT) PG_INT32_MIN) +#define DATEVAL_NOEND ((DateADT) PG_INT32_MAX) + +#define DATE_NOBEGIN(j) ((j) = DATEVAL_NOBEGIN) +#define DATE_IS_NOBEGIN(j) ((j) == DATEVAL_NOBEGIN) +#define DATE_NOEND(j) ((j) = DATEVAL_NOEND) +#define DATE_IS_NOEND(j) ((j) == DATEVAL_NOEND) +#define DATE_NOT_FINITE(j) (DATE_IS_NOBEGIN(j) || DATE_IS_NOEND(j)) + +/* + * Macros for fmgr-callable functions. + * + * For TimeADT, we make use of the same support routines as for int64. + * Therefore TimeADT is pass-by-reference if and only if int64 is! + */ +#define MAX_TIME_PRECISION 6 + +#define DatumGetDateADT(X) ((DateADT) DatumGetInt32(X)) +#define DatumGetTimeADT(X) ((TimeADT) DatumGetInt64(X)) +#define DatumGetTimeTzADTP(X) ((TimeTzADT *) DatumGetPointer(X)) + +#define DateADTGetDatum(X) Int32GetDatum(X) +#define TimeADTGetDatum(X) Int64GetDatum(X) +#define TimeTzADTPGetDatum(X) PointerGetDatum(X) + +#define PG_GETARG_DATEADT(n) DatumGetDateADT(PG_GETARG_DATUM(n)) +#define PG_GETARG_TIMEADT(n) DatumGetTimeADT(PG_GETARG_DATUM(n)) +#define PG_GETARG_TIMETZADT_P(n) DatumGetTimeTzADTP(PG_GETARG_DATUM(n)) + +#define PG_RETURN_DATEADT(x) return DateADTGetDatum(x) +#define PG_RETURN_TIMEADT(x) return TimeADTGetDatum(x) +#define PG_RETURN_TIMETZADT_P(x) return TimeTzADTPGetDatum(x) + + +/* date.c */ +extern int32 anytime_typmod_check(bool istz, int32 typmod); +extern double date2timestamp_no_overflow(DateADT dateVal); +extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow); +extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow); +extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2); +extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2); + +extern void EncodeSpecialDate(DateADT dt, char *str); +extern DateADT GetSQLCurrentDate(void); +extern TimeTzADT *GetSQLCurrentTime(int32 typmod); +extern TimeADT GetSQLLocalTime(int32 typmod); +extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec); +extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result); +extern int tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result); +extern bool time_overflows(int hour, int min, int sec, fsec_t fsec); +extern bool float_time_overflows(int hour, int min, double sec); +extern void AdjustTimeForTypmod(TimeADT *time, int32 typmod); + +#endif /* DATE_H */ diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h new file mode 100644 index 0000000..4527e82 --- /dev/null +++ b/src/include/utils/datetime.h @@ -0,0 +1,344 @@ +/*------------------------------------------------------------------------- + * + * datetime.h + * Definitions for date/time support code. + * The support code is shared with other date data types, + * including date, and time. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/datetime.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATETIME_H +#define DATETIME_H + +#include "nodes/nodes.h" +#include "utils/timestamp.h" + +/* this struct is declared in utils/tzparser.h: */ +struct tzEntry; + + +/* ---------------------------------------------------------------- + * time types + support macros + * + * String definitions for standard time quantities. + * + * These strings are the defaults used to form output time strings. + * Other alternative forms are hardcoded into token tables in datetime.c. + * ---------------------------------------------------------------- + */ + +#define DAGO "ago" +#define DCURRENT "current" +#define EPOCH "epoch" +#define INVALID "invalid" +#define EARLY "-infinity" +#define LATE "infinity" +#define NOW "now" +#define TODAY "today" +#define TOMORROW "tomorrow" +#define YESTERDAY "yesterday" +#define ZULU "zulu" + +#define DMICROSEC "usecond" +#define DMILLISEC "msecond" +#define DSECOND "second" +#define DMINUTE "minute" +#define DHOUR "hour" +#define DDAY "day" +#define DWEEK "week" +#define DMONTH "month" +#define DQUARTER "quarter" +#define DYEAR "year" +#define DDECADE "decade" +#define DCENTURY "century" +#define DMILLENNIUM "millennium" +#define DA_D "ad" +#define DB_C "bc" +#define DTIMEZONE "timezone" + +/* + * Fundamental time field definitions for parsing. + * + * Meridian: am, pm, or 24-hour style. + * Millennium: ad, bc + */ + +#define AM 0 +#define PM 1 +#define HR24 2 + +#define AD 0 +#define BC 1 + +/* + * Field types for time decoding. + * + * Can't have more of these than there are bits in an unsigned int + * since these are turned into bit masks during parsing and decoding. + * + * Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND + * must be in the range 0..14 so that the associated bitmasks can fit + * into the left half of an INTERVAL's typmod value. Since those bits + * are stored in typmods, you can't change them without initdb! + */ + +#define RESERV 0 +#define MONTH 1 +#define YEAR 2 +#define DAY 3 +#define JULIAN 4 +#define TZ 5 /* fixed-offset timezone abbreviation */ +#define DTZ 6 /* fixed-offset timezone abbrev, DST */ +#define DYNTZ 7 /* dynamic timezone abbreviation */ +#define IGNORE_DTF 8 +#define AMPM 9 +#define HOUR 10 +#define MINUTE 11 +#define SECOND 12 +#define MILLISECOND 13 +#define MICROSECOND 14 +#define DOY 15 +#define DOW 16 +#define UNITS 17 +#define ADBC 18 +/* these are only for relative dates */ +#define AGO 19 +#define ABS_BEFORE 20 +#define ABS_AFTER 21 +/* generic fields to help with parsing */ +#define ISODATE 22 +#define ISOTIME 23 +/* these are only for parsing intervals */ +#define WEEK 24 +#define DECADE 25 +#define CENTURY 26 +#define MILLENNIUM 27 +/* hack for parsing two-word timezone specs "MET DST" etc */ +#define DTZMOD 28 /* "DST" as a separate word */ +/* reserved for unrecognized string values */ +#define UNKNOWN_FIELD 31 + +/* + * Token field definitions for time parsing and decoding. + * + * Some field type codes (see above) use these as the "value" in datetktbl[]. + * These are also used for bit masks in DecodeDateTime and friends + * so actually restrict them to within [0,31] for now. + * - thomas 97/06/19 + * Not all of these fields are used for masks in DecodeDateTime + * so allow some larger than 31. - thomas 1997-11-17 + * + * Caution: there are undocumented assumptions in the code that most of these + * values are not equal to IGNORE_DTF nor RESERV. Be very careful when + * renumbering values in either of these apparently-independent lists :-( + */ + +#define DTK_NUMBER 0 +#define DTK_STRING 1 + +#define DTK_DATE 2 +#define DTK_TIME 3 +#define DTK_TZ 4 +#define DTK_AGO 5 + +#define DTK_SPECIAL 6 +#define DTK_EARLY 9 +#define DTK_LATE 10 +#define DTK_EPOCH 11 +#define DTK_NOW 12 +#define DTK_YESTERDAY 13 +#define DTK_TODAY 14 +#define DTK_TOMORROW 15 +#define DTK_ZULU 16 + +#define DTK_DELTA 17 +#define DTK_SECOND 18 +#define DTK_MINUTE 19 +#define DTK_HOUR 20 +#define DTK_DAY 21 +#define DTK_WEEK 22 +#define DTK_MONTH 23 +#define DTK_QUARTER 24 +#define DTK_YEAR 25 +#define DTK_DECADE 26 +#define DTK_CENTURY 27 +#define DTK_MILLENNIUM 28 +#define DTK_MILLISEC 29 +#define DTK_MICROSEC 30 +#define DTK_JULIAN 31 + +#define DTK_DOW 32 +#define DTK_DOY 33 +#define DTK_TZ_HOUR 34 +#define DTK_TZ_MINUTE 35 +#define DTK_ISOYEAR 36 +#define DTK_ISODOW 37 + + +/* + * Bit mask definitions for time parsing. + */ + +#define DTK_M(t) (0x01 << (t)) + +/* Convenience: a second, plus any fractional component */ +#define DTK_ALL_SECS_M (DTK_M(SECOND) | DTK_M(MILLISECOND) | DTK_M(MICROSECOND)) +#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) +#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M) + +/* + * Working buffer size for input and output of interval, timestamp, etc. + * Inputs that need more working space will be rejected early. Longer outputs + * will overrun buffers, so this must suffice for all possible output. As of + * this writing, interval_out() needs the most space at ~90 bytes. + */ +#define MAXDATELEN 128 +/* maximum possible number of fields in a date string */ +#define MAXDATEFIELDS 25 +/* only this many chars are stored in datetktbl */ +#define TOKMAXLEN 10 + +/* keep this struct small; it gets used a lot */ +typedef struct +{ + char token[TOKMAXLEN + 1]; /* always NUL-terminated */ + char type; /* see field type codes above */ + int32 value; /* meaning depends on type */ +} datetkn; + +/* one of its uses is in tables of time zone abbreviations */ +typedef struct TimeZoneAbbrevTable +{ + Size tblsize; /* size in bytes of TimeZoneAbbrevTable */ + int numabbrevs; /* number of entries in abbrevs[] array */ + datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]; + /* DynamicZoneAbbrev(s) may follow the abbrevs[] array */ +} TimeZoneAbbrevTable; + +/* auxiliary data for a dynamic time zone abbreviation (non-fixed-offset) */ +typedef struct DynamicZoneAbbrev +{ + pg_tz *tz; /* NULL if not yet looked up */ + char zone[FLEXIBLE_ARRAY_MEMBER]; /* NUL-terminated zone name */ +} DynamicZoneAbbrev; + + +/* FMODULO() + * Macro to replace modf(), which is broken on some platforms. + * t = input and remainder + * q = integer part + * u = divisor + */ +#define FMODULO(t,q,u) \ +do { \ + (q) = (((t) < 0) ? ceil((t) / (u)) : floor((t) / (u))); \ + if ((q) != 0) (t) -= rint((q) * (u)); \ +} while(0) + +/* TMODULO() + * Like FMODULO(), but work on the timestamp datatype (now always int64). + * We assume that int64 follows the C99 semantics for division (negative + * quotients truncate towards zero). + */ +#define TMODULO(t,q,u) \ +do { \ + (q) = ((t) / (u)); \ + if ((q) != 0) (t) -= ((q) * (u)); \ +} while(0) + +/* + * Date/time validation + * Include check for leap year. + */ + +extern PGDLLIMPORT const char *const months[]; /* months (3-char + * abbreviations) */ +extern PGDLLIMPORT const char *const days[]; /* days (full names) */ +extern PGDLLIMPORT const int day_tab[2][13]; + +/* + * These are the rules for the Gregorian calendar, which was adopted in 1582. + * However, we use this calculation for all prior years as well because the + * SQL standard specifies use of the Gregorian calendar. This prevents the + * date 1500-02-29 from being stored, even though it is valid in the Julian + * calendar. + */ +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + + +/* + * Datetime input parsing routines (ParseDateTime, DecodeDateTime, etc) + * return zero or a positive value on success. On failure, they return + * one of these negative code values. DateTimeParseError may be used to + * produce a correct ereport. + */ +#define DTERR_BAD_FORMAT (-1) +#define DTERR_FIELD_OVERFLOW (-2) +#define DTERR_MD_FIELD_OVERFLOW (-3) /* triggers hint about DateStyle */ +#define DTERR_INTERVAL_OVERFLOW (-4) +#define DTERR_TZDISP_OVERFLOW (-5) + + +extern void GetCurrentDateTime(struct pg_tm *tm); +extern void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern void j2date(int jd, int *year, int *month, int *day); +extern int date2j(int year, int month, int day); + +extern int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, + char **field, int *ftype, + int maxfields, int *numfields); +extern int DecodeDateTime(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern int DecodeTimezone(char *str, int *tzp); +extern int DecodeTimeOnly(char **field, int *ftype, + int nf, int *dtype, + struct pg_tm *tm, fsec_t *fsec, int *tzp); +extern int DecodeInterval(char **field, int *ftype, int nf, int range, + int *dtype, struct pg_itm_in *itm_in); +extern int DecodeISO8601Interval(char *str, + int *dtype, struct pg_itm_in *itm_in); + +extern void DateTimeParseError(int dterr, const char *str, + const char *datatype) pg_attribute_noreturn(); + +extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp); +extern int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp); +extern int DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, + pg_tz *tzp, int *isdst); + +extern void EncodeDateOnly(struct pg_tm *tm, int style, char *str); +extern void EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, int style, char *str); +extern void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str); +extern void EncodeInterval(struct pg_itm *itm, int style, char *str); +extern void EncodeSpecialTimestamp(Timestamp dt, char *str); + +extern int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, + struct pg_tm *tm); + +extern int DecodeTimezoneAbbrev(int field, char *lowtoken, + int *offset, pg_tz **tz); +extern int DecodeSpecial(int field, char *lowtoken, int *val); +extern int DecodeUnits(int field, char *lowtoken, int *val); + +extern int j2day(int jd); + +extern Node *TemporalSimplify(int32 max_precis, Node *node); + +extern bool CheckDateTokenTables(void); + +extern TimeZoneAbbrevTable *ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, + int n); +extern void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl); + +extern void AdjustTimestampForTypmod(Timestamp *time, int32 typmod); +extern bool AdjustTimestampForTypmodError(Timestamp *time, int32 typmod, + bool *error); + +#endif /* DATETIME_H */ diff --git a/src/include/utils/datum.h b/src/include/utils/datum.h new file mode 100644 index 0000000..d7de961 --- /dev/null +++ b/src/include/utils/datum.h @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------- + * + * datum.h + * POSTGRES Datum (abstract data type) manipulation routines. + * + * These routines are driven by the 'typbyval' and 'typlen' information, + * which must previously have been obtained by the caller for the datatype + * of the Datum. (We do it this way because in most situations the caller + * can look up the info just once and use it for many per-datum operations.) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/datum.h + * + *------------------------------------------------------------------------- + */ +#ifndef DATUM_H +#define DATUM_H + +/* + * datumGetSize - find the "real" length of a datum + */ +extern Size datumGetSize(Datum value, bool typByVal, int typLen); + +/* + * datumCopy - make a copy of a non-NULL datum. + * + * If the datatype is pass-by-reference, memory is obtained with palloc(). + */ +extern Datum datumCopy(Datum value, bool typByVal, int typLen); + +/* + * datumTransfer - transfer a non-NULL datum into the current memory context. + * + * Differs from datumCopy() in its handling of read-write expanded objects. + */ +extern Datum datumTransfer(Datum value, bool typByVal, int typLen); + +/* + * datumIsEqual + * return true if two datums of the same type are equal, false otherwise. + * + * XXX : See comments in the code for restrictions! + */ +extern bool datumIsEqual(Datum value1, Datum value2, + bool typByVal, int typLen); + +/* + * datum_image_eq + * + * Compares two datums for identical contents, based on byte images. Return + * true if the two datums are equal, false otherwise. + */ +extern bool datum_image_eq(Datum value1, Datum value2, + bool typByVal, int typLen); + +/* + * datum_image_hash + * + * Generates hash value for 'value' based on its bits rather than logical + * value. + */ +extern uint32 datum_image_hash(Datum value, bool typByVal, int typLen); + +/* + * Serialize and restore datums so that we can transfer them to parallel + * workers. + */ +extern Size datumEstimateSpace(Datum value, bool isnull, bool typByVal, + int typLen); +extern void datumSerialize(Datum value, bool isnull, bool typByVal, + int typLen, char **start_address); +extern Datum datumRestore(char **start_address, bool *isnull); + +#endif /* DATUM_H */ diff --git a/src/include/utils/dsa.h b/src/include/utils/dsa.h new file mode 100644 index 0000000..405606f --- /dev/null +++ b/src/include/utils/dsa.h @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * + * dsa.h + * Dynamic shared memory areas. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/dsa.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSA_H +#define DSA_H + +#include "port/atomics.h" +#include "storage/dsm.h" + +/* The opaque type used for an area. */ +struct dsa_area; +typedef struct dsa_area dsa_area; + +/* + * If this system only uses a 32-bit value for size_t, then use the 32-bit + * implementation of DSA. This limits the amount of DSA that can be created + * to something significantly less than the entire 4GB address space because + * the DSA pointer must encode both a segment identifier and an offset, but + * that shouldn't be a significant limitation in practice. + * + * If this system doesn't support atomic operations on 64-bit values, then + * we fall back to 32-bit dsa_pointer for lack of other options. + * + * For testing purposes, USE_SMALL_DSA_POINTER can be defined to force the use + * of 32-bit dsa_pointer even on systems capable of supporting a 64-bit + * dsa_pointer. + */ +#if SIZEOF_SIZE_T == 4 || !defined(PG_HAVE_ATOMIC_U64_SUPPORT) || \ + defined(USE_SMALL_DSA_POINTER) +#define SIZEOF_DSA_POINTER 4 +#else +#define SIZEOF_DSA_POINTER 8 +#endif + +/* + * The type of 'relative pointers' to memory allocated by a dynamic shared + * area. dsa_pointer values can be shared with other processes, but must be + * converted to backend-local pointers before they can be dereferenced. See + * dsa_get_address. Also, an atomic version and appropriately sized atomic + * operations. + */ +#if SIZEOF_DSA_POINTER == 4 +typedef uint32 dsa_pointer; +typedef pg_atomic_uint32 dsa_pointer_atomic; +#define dsa_pointer_atomic_init pg_atomic_init_u32 +#define dsa_pointer_atomic_read pg_atomic_read_u32 +#define dsa_pointer_atomic_write pg_atomic_write_u32 +#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u32 +#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u32 +#define DSA_POINTER_FORMAT "%08x" +#else +typedef uint64 dsa_pointer; +typedef pg_atomic_uint64 dsa_pointer_atomic; +#define dsa_pointer_atomic_init pg_atomic_init_u64 +#define dsa_pointer_atomic_read pg_atomic_read_u64 +#define dsa_pointer_atomic_write pg_atomic_write_u64 +#define dsa_pointer_atomic_fetch_add pg_atomic_fetch_add_u64 +#define dsa_pointer_atomic_compare_exchange pg_atomic_compare_exchange_u64 +#define DSA_POINTER_FORMAT "%016" INT64_MODIFIER "x" +#endif + +/* Flags for dsa_allocate_extended. */ +#define DSA_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */ +#define DSA_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ +#define DSA_ALLOC_ZERO 0x04 /* zero allocated memory */ + +/* A sentinel value for dsa_pointer used to indicate failure to allocate. */ +#define InvalidDsaPointer ((dsa_pointer) 0) + +/* Check if a dsa_pointer value is valid. */ +#define DsaPointerIsValid(x) ((x) != InvalidDsaPointer) + +/* Allocate uninitialized memory with error on out-of-memory. */ +#define dsa_allocate(area, size) \ + dsa_allocate_extended(area, size, 0) + +/* Allocate zero-initialized memory with error on out-of-memory. */ +#define dsa_allocate0(area, size) \ + dsa_allocate_extended(area, size, DSA_ALLOC_ZERO) + +/* + * The type used for dsa_area handles. dsa_handle values can be shared with + * other processes, so that they can attach to them. This provides a way to + * share allocated storage with other processes. + * + * The handle for a dsa_area is currently implemented as the dsm_handle + * for the first DSM segment backing this dynamic storage area, but client + * code shouldn't assume that is true. + */ +typedef dsm_handle dsa_handle; + +extern dsa_area *dsa_create(int tranche_id); +extern dsa_area *dsa_create_in_place(void *place, size_t size, + int tranche_id, dsm_segment *segment); +extern dsa_area *dsa_attach(dsa_handle handle); +extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment); +extern void dsa_release_in_place(void *place); +extern void dsa_on_dsm_detach_release_in_place(dsm_segment *, Datum); +extern void dsa_on_shmem_exit_release_in_place(int, Datum); +extern void dsa_pin_mapping(dsa_area *area); +extern void dsa_detach(dsa_area *area); +extern void dsa_pin(dsa_area *area); +extern void dsa_unpin(dsa_area *area); +extern void dsa_set_size_limit(dsa_area *area, size_t limit); +extern size_t dsa_minimum_size(void); +extern dsa_handle dsa_get_handle(dsa_area *area); +extern dsa_pointer dsa_allocate_extended(dsa_area *area, size_t size, int flags); +extern void dsa_free(dsa_area *area, dsa_pointer dp); +extern void *dsa_get_address(dsa_area *area, dsa_pointer dp); +extern void dsa_trim(dsa_area *area); +extern void dsa_dump(dsa_area *area); + +#endif /* DSA_H */ diff --git a/src/include/utils/dynahash.h b/src/include/utils/dynahash.h new file mode 100644 index 0000000..4564fb2 --- /dev/null +++ b/src/include/utils/dynahash.h @@ -0,0 +1,20 @@ +/*------------------------------------------------------------------------- + * + * dynahash.h + * POSTGRES dynahash.h file definitions + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/dynahash.h + * + *------------------------------------------------------------------------- + */ +#ifndef DYNAHASH_H +#define DYNAHASH_H + +extern int my_log2(long num); + +#endif /* DYNAHASH_H */ diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h new file mode 100644 index 0000000..561c15e --- /dev/null +++ b/src/include/utils/elog.h @@ -0,0 +1,476 @@ +/*------------------------------------------------------------------------- + * + * elog.h + * POSTGRES error reporting/logging definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/elog.h + * + *------------------------------------------------------------------------- + */ +#ifndef ELOG_H +#define ELOG_H + +#include <setjmp.h> + +/* Error level codes */ +#define DEBUG5 10 /* Debugging messages, in categories of + * decreasing detail. */ +#define DEBUG4 11 +#define DEBUG3 12 +#define DEBUG2 13 +#define DEBUG1 14 /* used by GUC debug_* variables */ +#define LOG 15 /* Server operational messages; sent only to + * server log by default. */ +#define LOG_SERVER_ONLY 16 /* Same as LOG for server reporting, but never + * sent to client. */ +#define COMMERROR LOG_SERVER_ONLY /* Client communication problems; same as + * LOG for server reporting, but never + * sent to client. */ +#define INFO 17 /* Messages specifically requested by user (eg + * VACUUM VERBOSE output); always sent to + * client regardless of client_min_messages, + * but by default not sent to server log. */ +#define NOTICE 18 /* Helpful messages to users about query + * operation; sent to client and not to server + * log by default. */ +#define WARNING 19 /* Warnings. NOTICE is for expected messages + * like implicit sequence creation by SERIAL. + * WARNING is for unexpected messages. */ +#define PGWARNING 19 /* Must equal WARNING; see NOTE below. */ +#define WARNING_CLIENT_ONLY 20 /* Warnings to be sent to client as usual, but + * never to the server log. */ +#define ERROR 21 /* user error - abort transaction; return to + * known state */ +#define PGERROR 21 /* Must equal ERROR; see NOTE below. */ +#define FATAL 22 /* fatal error - abort process */ +#define PANIC 23 /* take down the other backends with me */ + +/* + * NOTE: the alternate names PGWARNING and PGERROR are useful for dealing + * with third-party headers that make other definitions of WARNING and/or + * ERROR. One can, for example, re-define ERROR as PGERROR after including + * such a header. + */ + + +/* macros for representing SQLSTATE strings compactly */ +#define PGSIXBIT(ch) (((ch) - '0') & 0x3F) +#define PGUNSIXBIT(val) (((val) & 0x3F) + '0') + +#define MAKE_SQLSTATE(ch1,ch2,ch3,ch4,ch5) \ + (PGSIXBIT(ch1) + (PGSIXBIT(ch2) << 6) + (PGSIXBIT(ch3) << 12) + \ + (PGSIXBIT(ch4) << 18) + (PGSIXBIT(ch5) << 24)) + +/* These macros depend on the fact that '0' becomes a zero in PGSIXBIT */ +#define ERRCODE_TO_CATEGORY(ec) ((ec) & ((1 << 12) - 1)) +#define ERRCODE_IS_CATEGORY(ec) (((ec) & ~((1 << 12) - 1)) == 0) + +/* SQLSTATE codes for errors are defined in a separate file */ +#include "utils/errcodes.h" + +/* + * Provide a way to prevent "errno" from being accidentally used inside an + * elog() or ereport() invocation. Since we know that some operating systems + * define errno as something involving a function call, we'll put a local + * variable of the same name as that function in the local scope to force a + * compile error. On platforms that don't define errno in that way, nothing + * happens, so we get no warning ... but we can live with that as long as it + * happens on some popular platforms. + */ +#if defined(errno) && defined(__linux__) +#define pg_prevent_errno_in_scope() int __errno_location pg_attribute_unused() +#elif defined(errno) && (defined(__darwin__) || defined(__freebsd__)) +#define pg_prevent_errno_in_scope() int __error pg_attribute_unused() +#else +#define pg_prevent_errno_in_scope() +#endif + + +/*---------- + * New-style error reporting API: to be used in this way: + * ereport(ERROR, + * errcode(ERRCODE_UNDEFINED_CURSOR), + * errmsg("portal \"%s\" not found", stmt->portalname), + * ... other errxxx() fields as needed ...); + * + * The error level is required, and so is a primary error message (errmsg + * or errmsg_internal). All else is optional. errcode() defaults to + * ERRCODE_INTERNAL_ERROR if elevel is ERROR or more, ERRCODE_WARNING + * if elevel is WARNING, or ERRCODE_SUCCESSFUL_COMPLETION if elevel is + * NOTICE or below. + * + * Before Postgres v12, extra parentheses were required around the + * list of auxiliary function calls; that's now optional. + * + * ereport_domain() allows a message domain to be specified, for modules that + * wish to use a different message catalog from the backend's. To avoid having + * one copy of the default text domain per .o file, we define it as NULL here + * and have errstart insert the default text domain. Modules can either use + * ereport_domain() directly, or preferably they can override the TEXTDOMAIN + * macro. + * + * When __builtin_constant_p is available and elevel >= ERROR we make a call + * to errstart_cold() instead of errstart(). This version of the function is + * marked with pg_attribute_cold which will coax supporting compilers into + * generating code which is more optimized towards non-ERROR cases. Because + * we use __builtin_constant_p() in the condition, when elevel is not a + * compile-time constant, or if it is, but it's < ERROR, the compiler has no + * need to generate any code for this branch. It can simply call errstart() + * unconditionally. + * + * If elevel >= ERROR, the call will not return; we try to inform the compiler + * of that via pg_unreachable(). However, no useful optimization effect is + * obtained unless the compiler sees elevel as a compile-time constant, else + * we're just adding code bloat. So, if __builtin_constant_p is available, + * use that to cause the second if() to vanish completely for non-constant + * cases. We avoid using a local variable because it's not necessary and + * prevents gcc from making the unreachability deduction at optlevel -O0. + *---------- + */ +#ifdef HAVE__BUILTIN_CONSTANT_P +#define ereport_domain(elevel, domain, ...) \ + do { \ + pg_prevent_errno_in_scope(); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \ + errstart_cold(elevel, domain) : \ + errstart(elevel, domain)) \ + __VA_ARGS__, errfinish(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ + if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ + pg_unreachable(); \ + } while(0) +#else /* !HAVE__BUILTIN_CONSTANT_P */ +#define ereport_domain(elevel, domain, ...) \ + do { \ + const int elevel_ = (elevel); \ + pg_prevent_errno_in_scope(); \ + if (errstart(elevel_, domain)) \ + __VA_ARGS__, errfinish(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ + if (elevel_ >= ERROR) \ + pg_unreachable(); \ + } while(0) +#endif /* HAVE__BUILTIN_CONSTANT_P */ + +#define ereport(elevel, ...) \ + ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__) + +#define TEXTDOMAIN NULL + +extern bool message_level_is_interesting(int elevel); + +extern bool errstart(int elevel, const char *domain); +extern pg_attribute_cold bool errstart_cold(int elevel, const char *domain); +extern void errfinish(const char *filename, int lineno, const char *funcname); + +extern int errcode(int sqlerrcode); + +extern int errcode_for_file_access(void); +extern int errcode_for_socket_access(void); + +extern int errmsg(const char *fmt,...) pg_attribute_printf(1, 2); +extern int errmsg_internal(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errmsg_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errdetail(const char *fmt,...) pg_attribute_printf(1, 2); +extern int errdetail_internal(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errdetail_log(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errdetail_log_plural(const char *fmt_singular, + const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errdetail_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errhint_plural(const char *fmt_singular, const char *fmt_plural, + unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4); + +/* + * errcontext() is typically called in error context callback functions, not + * within an ereport() invocation. The callback function can be in a different + * module than the ereport() call, so the message domain passed in errstart() + * is not usually the correct domain for translating the context message. + * set_errcontext_domain() first sets the domain to be used, and + * errcontext_msg() passes the actual message. + */ +#define errcontext set_errcontext_domain(TEXTDOMAIN), errcontext_msg + +extern int set_errcontext_domain(const char *domain); + +extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2); + +extern int errhidestmt(bool hide_stmt); +extern int errhidecontext(bool hide_ctx); + +extern int errbacktrace(void); + +extern int errposition(int cursorpos); + +extern int internalerrposition(int cursorpos); +extern int internalerrquery(const char *query); + +extern int err_generic_string(int field, const char *str); + +extern int geterrcode(void); +extern int geterrposition(void); +extern int getinternalerrposition(void); + + +/*---------- + * Old-style error reporting API: to be used in this way: + * elog(ERROR, "portal \"%s\" not found", stmt->portalname); + *---------- + */ +#define elog(elevel, ...) \ + ereport(elevel, errmsg_internal(__VA_ARGS__)) + + +/* Support for constructing error strings separately from ereport() calls */ + +extern void pre_format_elog_string(int errnumber, const char *domain); +extern char *format_elog_string(const char *fmt,...) pg_attribute_printf(1, 2); + + +/* Support for attaching context information to error reports */ + +typedef struct ErrorContextCallback +{ + struct ErrorContextCallback *previous; + void (*callback) (void *arg); + void *arg; +} ErrorContextCallback; + +extern PGDLLIMPORT ErrorContextCallback *error_context_stack; + + +/*---------- + * API for catching ereport(ERROR) exits. Use these macros like so: + * + * PG_TRY(); + * { + * ... code that might throw ereport(ERROR) ... + * } + * PG_CATCH(); + * { + * ... error recovery code ... + * } + * PG_END_TRY(); + * + * (The braces are not actually necessary, but are recommended so that + * pgindent will indent the construct nicely.) The error recovery code + * can either do PG_RE_THROW to propagate the error outwards, or do a + * (sub)transaction abort. Failure to do so may leave the system in an + * inconsistent state for further processing. + * + * For the common case that the error recovery code and the cleanup in the + * normal code path are identical, the following can be used instead: + * + * PG_TRY(); + * { + * ... code that might throw ereport(ERROR) ... + * } + * PG_FINALLY(); + * { + * ... cleanup code ... + * } + * PG_END_TRY(); + * + * The cleanup code will be run in either case, and any error will be rethrown + * afterwards. + * + * You cannot use both PG_CATCH() and PG_FINALLY() in the same + * PG_TRY()/PG_END_TRY() block. + * + * Note: while the system will correctly propagate any new ereport(ERROR) + * occurring in the recovery section, there is a small limit on the number + * of levels this will work for. It's best to keep the error recovery + * section simple enough that it can't generate any new errors, at least + * not before popping the error stack. + * + * Note: an ereport(FATAL) will not be caught by this construct; control will + * exit straight through proc_exit(). Therefore, do NOT put any cleanup + * of non-process-local resources into the error recovery section, at least + * not without taking thought for what will happen during ereport(FATAL). + * The PG_ENSURE_ERROR_CLEANUP macros provided by storage/ipc.h may be + * helpful in such cases. + * + * Note: if a local variable of the function containing PG_TRY is modified + * in the PG_TRY section and used in the PG_CATCH section, that variable + * must be declared "volatile" for POSIX compliance. This is not mere + * pedantry; we have seen bugs from compilers improperly optimizing code + * away when such a variable was not marked. Beware that gcc's -Wclobbered + * warnings are just about entirely useless for catching such oversights. + *---------- + */ +#define PG_TRY() \ + do { \ + sigjmp_buf *_save_exception_stack = PG_exception_stack; \ + ErrorContextCallback *_save_context_stack = error_context_stack; \ + sigjmp_buf _local_sigjmp_buf; \ + bool _do_rethrow = false; \ + if (sigsetjmp(_local_sigjmp_buf, 0) == 0) \ + { \ + PG_exception_stack = &_local_sigjmp_buf + +#define PG_CATCH() \ + } \ + else \ + { \ + PG_exception_stack = _save_exception_stack; \ + error_context_stack = _save_context_stack + +#define PG_FINALLY() \ + } \ + else \ + _do_rethrow = true; \ + { \ + PG_exception_stack = _save_exception_stack; \ + error_context_stack = _save_context_stack + +#define PG_END_TRY() \ + } \ + if (_do_rethrow) \ + PG_RE_THROW(); \ + PG_exception_stack = _save_exception_stack; \ + error_context_stack = _save_context_stack; \ + } while (0) + +/* + * Some compilers understand pg_attribute_noreturn(); for other compilers, + * insert pg_unreachable() so that the compiler gets the point. + */ +#ifdef HAVE_PG_ATTRIBUTE_NORETURN +#define PG_RE_THROW() \ + pg_re_throw() +#else +#define PG_RE_THROW() \ + (pg_re_throw(), pg_unreachable()) +#endif + +extern PGDLLIMPORT sigjmp_buf *PG_exception_stack; + + +/* Stuff that error handlers might want to use */ + +/* + * ErrorData holds the data accumulated during any one ereport() cycle. + * Any non-NULL pointers must point to palloc'd data. + * (The const pointers are an exception; we assume they point at non-freeable + * constant strings.) + */ +typedef struct ErrorData +{ + int elevel; /* error level */ + bool output_to_server; /* will report to server log? */ + bool output_to_client; /* will report to client? */ + bool hide_stmt; /* true to prevent STATEMENT: inclusion */ + bool hide_ctx; /* true to prevent CONTEXT: inclusion */ + const char *filename; /* __FILE__ of ereport() call */ + int lineno; /* __LINE__ of ereport() call */ + const char *funcname; /* __func__ of ereport() call */ + const char *domain; /* message domain */ + const char *context_domain; /* message domain for context message */ + int sqlerrcode; /* encoded ERRSTATE */ + char *message; /* primary error message (translated) */ + char *detail; /* detail error message */ + char *detail_log; /* detail error message for server log only */ + char *hint; /* hint message */ + char *context; /* context message */ + char *backtrace; /* backtrace */ + const char *message_id; /* primary message's id (original string) */ + char *schema_name; /* name of schema */ + char *table_name; /* name of table */ + char *column_name; /* name of column */ + char *datatype_name; /* name of datatype */ + char *constraint_name; /* name of constraint */ + int cursorpos; /* cursor index into query string */ + int internalpos; /* cursor index into internalquery */ + char *internalquery; /* text of internally-generated query */ + int saved_errno; /* errno at entry */ + + /* context containing associated non-constant strings */ + struct MemoryContextData *assoc_context; +} ErrorData; + +extern void EmitErrorReport(void); +extern ErrorData *CopyErrorData(void); +extern void FreeErrorData(ErrorData *edata); +extern void FlushErrorState(void); +extern void ReThrowError(ErrorData *edata) pg_attribute_noreturn(); +extern void ThrowErrorData(ErrorData *edata); +extern void pg_re_throw(void) pg_attribute_noreturn(); + +extern char *GetErrorContextStack(void); + +/* Hook for intercepting messages before they are sent to the server log */ +typedef void (*emit_log_hook_type) (ErrorData *edata); +extern PGDLLIMPORT emit_log_hook_type emit_log_hook; + + +/* GUC-configurable parameters */ + +typedef enum +{ + PGERROR_TERSE, /* single-line error messages */ + PGERROR_DEFAULT, /* recommended style */ + PGERROR_VERBOSE /* all the facts, ma'am */ +} PGErrorVerbosity; + +extern PGDLLIMPORT int Log_error_verbosity; +extern PGDLLIMPORT char *Log_line_prefix; +extern PGDLLIMPORT int Log_destination; +extern PGDLLIMPORT char *Log_destination_string; +extern PGDLLIMPORT bool syslog_sequence_numbers; +extern PGDLLIMPORT bool syslog_split_messages; + +/* Log destination bitmap */ +#define LOG_DESTINATION_STDERR 1 +#define LOG_DESTINATION_SYSLOG 2 +#define LOG_DESTINATION_EVENTLOG 4 +#define LOG_DESTINATION_CSVLOG 8 +#define LOG_DESTINATION_JSONLOG 16 + +/* Other exported functions */ +extern void DebugFileOpen(void); +extern char *unpack_sql_state(int sql_state); +extern bool in_error_recursion_trouble(void); + +/* Common functions shared across destinations */ +extern void reset_formatted_start_time(void); +extern char *get_formatted_start_time(void); +extern char *get_formatted_log_time(void); +extern const char *get_backend_type_for_log(void); +extern bool check_log_of_query(ErrorData *edata); +extern const char *error_severity(int elevel); +extern void write_pipe_chunks(char *data, int len, int dest); + +/* Destination-specific functions */ +extern void write_csvlog(ErrorData *edata); +extern void write_jsonlog(ErrorData *edata); + +#ifdef HAVE_SYSLOG +extern void set_syslog_parameters(const char *ident, int facility); +#endif + +/* + * Write errors to stderr (or by equal means when stderr is + * not available). Used before ereport/elog can be used + * safely (memory context, GUC load etc) + */ +extern void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2); + +/* + * Write a message to STDERR using only async-signal-safe functions. This can + * be used to safely emit a message from a signal handler. + */ +extern void write_stderr_signal_safe(const char *fmt); + +#endif /* ELOG_H */ diff --git a/src/include/utils/evtcache.h b/src/include/utils/evtcache.h new file mode 100644 index 0000000..ddb67a6 --- /dev/null +++ b/src/include/utils/evtcache.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * evtcache.h + * Special-purpose cache for event trigger data. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/evtcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef EVTCACHE_H +#define EVTCACHE_H + +#include "nodes/bitmapset.h" +#include "nodes/pg_list.h" + +typedef enum +{ + EVT_DDLCommandStart, + EVT_DDLCommandEnd, + EVT_SQLDrop, + EVT_TableRewrite +} EventTriggerEvent; + +typedef struct +{ + Oid fnoid; /* function to be called */ + char enabled; /* as SESSION_REPLICATION_ROLE_* */ + Bitmapset *tagset; /* command tags, or NULL if empty */ +} EventTriggerCacheItem; + +extern List *EventCacheLookup(EventTriggerEvent event); + +#endif /* EVTCACHE_H */ diff --git a/src/include/utils/expandeddatum.h b/src/include/utils/expandeddatum.h new file mode 100644 index 0000000..ffdb0c4 --- /dev/null +++ b/src/include/utils/expandeddatum.h @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------- + * + * expandeddatum.h + * Declarations for access to "expanded" value representations. + * + * Complex data types, particularly container types such as arrays and + * records, usually have on-disk representations that are compact but not + * especially convenient to modify. What's more, when we do modify them, + * having to recopy all the rest of the value can be extremely inefficient. + * Therefore, we provide a notion of an "expanded" representation that is used + * only in memory and is optimized more for computation than storage. + * The format appearing on disk is called the data type's "flattened" + * representation, since it is required to be a contiguous blob of bytes -- + * but the type can have an expanded representation that is not. Data types + * must provide means to translate an expanded representation back to + * flattened form. + * + * An expanded object is meant to survive across multiple operations, but + * not to be enormously long-lived; for example it might be a local variable + * in a PL/pgSQL procedure. So its extra bulk compared to the on-disk format + * is a worthwhile trade-off. + * + * References to expanded objects are a type of TOAST pointer. + * Because of longstanding conventions in Postgres, this means that the + * flattened form of such an object must always be a varlena object. + * Fortunately that's no restriction in practice. + * + * There are actually two kinds of TOAST pointers for expanded objects: + * read-only and read-write pointers. Possession of one of the latter + * authorizes a function to modify the value in-place rather than copying it + * as would normally be required. Functions should always return a read-write + * pointer to any new expanded object they create. Functions that modify an + * argument value in-place must take care that they do not corrupt the old + * value if they fail partway through. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/expandeddatum.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXPANDEDDATUM_H +#define EXPANDEDDATUM_H + +/* Size of an EXTERNAL datum that contains a pointer to an expanded object */ +#define EXPANDED_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_expanded)) + +/* + * "Methods" that must be provided for any expanded object. + * + * get_flat_size: compute space needed for flattened representation (total, + * including header). + * + * flatten_into: construct flattened representation in the caller-allocated + * space at *result, of size allocated_size (which will always be the result + * of a preceding get_flat_size call; it's passed for cross-checking). + * + * The flattened representation must be a valid in-line, non-compressed, + * 4-byte-header varlena object. + * + * Note: construction of a heap tuple from an expanded datum calls + * get_flat_size twice, so it's worthwhile to make sure that that doesn't + * incur too much overhead. + */ +typedef Size (*EOM_get_flat_size_method) (ExpandedObjectHeader *eohptr); +typedef void (*EOM_flatten_into_method) (ExpandedObjectHeader *eohptr, + void *result, Size allocated_size); + +/* Struct of function pointers for an expanded object's methods */ +typedef struct ExpandedObjectMethods +{ + EOM_get_flat_size_method get_flat_size; + EOM_flatten_into_method flatten_into; +} ExpandedObjectMethods; + +/* + * Every expanded object must contain this header; typically the header + * is embedded in some larger struct that adds type-specific fields. + * + * It is presumed that the header object and all subsidiary data are stored + * in eoh_context, so that the object can be freed by deleting that context, + * or its storage lifespan can be altered by reparenting the context. + * (In principle the object could own additional resources, such as malloc'd + * storage, and use a memory context reset callback to free them upon reset or + * deletion of eoh_context.) + * + * We set up two TOAST pointers within the standard header, one read-write + * and one read-only. This allows functions to return either kind of pointer + * without making an additional allocation, and in particular without worrying + * whether a separately palloc'd object would have sufficient lifespan. + * But note that these pointers are just a convenience; a pointer object + * appearing somewhere else would still be legal. + * + * The typedef declaration for this appears in postgres.h. + */ +struct ExpandedObjectHeader +{ + /* Phony varlena header */ + int32 vl_len_; /* always EOH_HEADER_MAGIC, see below */ + + /* Pointer to methods required for object type */ + const ExpandedObjectMethods *eoh_methods; + + /* Memory context containing this header and subsidiary data */ + MemoryContext eoh_context; + + /* Standard R/W TOAST pointer for this object is kept here */ + char eoh_rw_ptr[EXPANDED_POINTER_SIZE]; + + /* Standard R/O TOAST pointer for this object is kept here */ + char eoh_ro_ptr[EXPANDED_POINTER_SIZE]; +}; + +/* + * Particularly for read-only functions, it is handy to be able to work with + * either regular "flat" varlena inputs or expanded inputs of the same data + * type. To allow determining which case an argument-fetching function has + * returned, the first int32 of an ExpandedObjectHeader always contains -1 + * (EOH_HEADER_MAGIC to the code). This works since no 4-byte-header varlena + * could have that as its first 4 bytes. Caution: we could not reliably tell + * the difference between an ExpandedObjectHeader and a short-header object + * with this trick. However, it works fine if the argument fetching code + * always returns either a 4-byte-header flat object or an expanded object. + */ +#define EOH_HEADER_MAGIC (-1) +#define VARATT_IS_EXPANDED_HEADER(PTR) \ + (((varattrib_4b *) (PTR))->va_4byte.va_header == (uint32) EOH_HEADER_MAGIC) + +/* + * Generic support functions for expanded objects. + * (More of these might be worth inlining later.) + */ + +#define EOHPGetRWDatum(eohptr) PointerGetDatum((eohptr)->eoh_rw_ptr) +#define EOHPGetRODatum(eohptr) PointerGetDatum((eohptr)->eoh_ro_ptr) + +/* Does the Datum represent a writable expanded object? */ +#define DatumIsReadWriteExpandedObject(d, isnull, typlen) \ + (((isnull) || (typlen) != -1) ? false : \ + VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d))) + +#define MakeExpandedObjectReadOnly(d, isnull, typlen) \ + (((isnull) || (typlen) != -1) ? (d) : \ + MakeExpandedObjectReadOnlyInternal(d)) + +extern ExpandedObjectHeader *DatumGetEOHP(Datum d); +extern void EOH_init_header(ExpandedObjectHeader *eohptr, + const ExpandedObjectMethods *methods, + MemoryContext obj_context); +extern Size EOH_get_flat_size(ExpandedObjectHeader *eohptr); +extern void EOH_flatten_into(ExpandedObjectHeader *eohptr, + void *result, Size allocated_size); +extern Datum MakeExpandedObjectReadOnlyInternal(Datum d); +extern Datum TransferExpandedObject(Datum d, MemoryContext new_parent); +extern void DeleteExpandedObject(Datum d); + +#endif /* EXPANDEDDATUM_H */ diff --git a/src/include/utils/expandedrecord.h b/src/include/utils/expandedrecord.h new file mode 100644 index 0000000..be60e2c --- /dev/null +++ b/src/include/utils/expandedrecord.h @@ -0,0 +1,231 @@ +/*------------------------------------------------------------------------- + * + * expandedrecord.h + * Declarations for composite expanded objects. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/expandedrecord.h + * + *------------------------------------------------------------------------- + */ +#ifndef EXPANDEDRECORD_H +#define EXPANDEDRECORD_H + +#include "access/htup.h" +#include "access/tupdesc.h" +#include "fmgr.h" +#include "utils/expandeddatum.h" + + +/* + * An expanded record is contained within a private memory context (as + * all expanded objects must be) and has a control structure as below. + * + * The expanded record might contain a regular "flat" tuple if that was the + * original input and we've not modified it. Otherwise, the contents are + * represented by Datum/isnull arrays plus type information. We could also + * have both forms, if we've deconstructed the original tuple for access + * purposes but not yet changed it. For pass-by-reference field types, the + * Datums would point into the flat tuple in this situation. Once we start + * modifying tuple fields, new pass-by-ref fields are separately palloc'd + * within the memory context. + * + * It's possible to build an expanded record that references a "flat" tuple + * stored externally, if the caller can guarantee that that tuple will not + * change for the lifetime of the expanded record. (This frammish is mainly + * meant to avoid unnecessary data copying in trigger functions.) + */ +#define ER_MAGIC 1384727874 /* ID for debugging crosschecks */ + +typedef struct ExpandedRecordHeader +{ + /* Standard header for expanded objects */ + ExpandedObjectHeader hdr; + + /* Magic value identifying an expanded record (for debugging only) */ + int er_magic; + + /* Assorted flag bits */ + int flags; +#define ER_FLAG_FVALUE_VALID 0x0001 /* fvalue is up to date? */ +#define ER_FLAG_FVALUE_ALLOCED 0x0002 /* fvalue is local storage? */ +#define ER_FLAG_DVALUES_VALID 0x0004 /* dvalues/dnulls are up to date? */ +#define ER_FLAG_DVALUES_ALLOCED 0x0008 /* any field values local storage? */ +#define ER_FLAG_HAVE_EXTERNAL 0x0010 /* any field values are external? */ +#define ER_FLAG_TUPDESC_ALLOCED 0x0020 /* tupdesc is local storage? */ +#define ER_FLAG_IS_DOMAIN 0x0040 /* er_decltypeid is domain? */ +#define ER_FLAG_IS_DUMMY 0x0080 /* this header is dummy (see below) */ +/* flag bits that are not to be cleared when replacing tuple data: */ +#define ER_FLAGS_NON_DATA \ + (ER_FLAG_TUPDESC_ALLOCED | ER_FLAG_IS_DOMAIN | ER_FLAG_IS_DUMMY) + + /* Declared type of the record variable (could be a domain type) */ + Oid er_decltypeid; + + /* + * Actual composite type/typmod; never a domain (if ER_FLAG_IS_DOMAIN, + * these identify the composite base type). These will match + * er_tupdesc->tdtypeid/tdtypmod, as well as the header fields of + * composite datums made from or stored in this expanded record. + */ + Oid er_typeid; /* type OID of the composite type */ + int32 er_typmod; /* typmod of the composite type */ + + /* + * Tuple descriptor, if we have one, else NULL. This may point to a + * reference-counted tupdesc originally belonging to the typcache, in + * which case we use a memory context reset callback to release the + * refcount. It can also be locally allocated in this object's private + * context (in which case ER_FLAG_TUPDESC_ALLOCED is set). + */ + TupleDesc er_tupdesc; + + /* + * Unique-within-process identifier for the tupdesc (see typcache.h). This + * field will never be equal to INVALID_TUPLEDESC_IDENTIFIER. + */ + uint64 er_tupdesc_id; + + /* + * If we have a Datum-array representation of the record, it's kept here; + * else ER_FLAG_DVALUES_VALID is not set, and dvalues/dnulls may be NULL + * if they've not yet been allocated. If allocated, the dvalues and + * dnulls arrays are palloc'd within the object private context, and are + * of length matching er_tupdesc->natts. For pass-by-ref field types, + * dvalues entries might point either into the fstartptr..fendptr area, or + * to separately palloc'd chunks. + */ + Datum *dvalues; /* array of Datums */ + bool *dnulls; /* array of is-null flags for Datums */ + int nfields; /* length of above arrays */ + + /* + * flat_size is the current space requirement for the flat equivalent of + * the expanded record, if known; otherwise it's 0. We store this to make + * consecutive calls of get_flat_size cheap. If flat_size is not 0, the + * component values data_len, hoff, and hasnull must be valid too. + */ + Size flat_size; + + Size data_len; /* data len within flat_size */ + int hoff; /* header offset */ + bool hasnull; /* null bitmap needed? */ + + /* + * fvalue points to the flat representation if we have one, else it is + * NULL. If the flat representation is valid (up to date) then + * ER_FLAG_FVALUE_VALID is set. Even if we've outdated the flat + * representation due to changes of user fields, it can still be used to + * fetch system column values. If we have a flat representation then + * fstartptr/fendptr point to the start and end+1 of its data area; this + * is so that we can tell which Datum pointers point into the flat + * representation rather than being pointers to separately palloc'd data. + */ + HeapTuple fvalue; /* might or might not be private storage */ + char *fstartptr; /* start of its data area */ + char *fendptr; /* end+1 of its data area */ + + /* Some operations on the expanded record need a short-lived context */ + MemoryContext er_short_term_cxt; /* short-term memory context */ + + /* Working state for domain checking, used if ER_FLAG_IS_DOMAIN is set */ + struct ExpandedRecordHeader *er_dummy_header; /* dummy record header */ + void *er_domaininfo; /* cache space for domain_check() */ + + /* Callback info (it's active if er_mcb.arg is not NULL) */ + MemoryContextCallback er_mcb; +} ExpandedRecordHeader; + +/* fmgr macros for expanded record objects */ +#define PG_GETARG_EXPANDED_RECORD(n) DatumGetExpandedRecord(PG_GETARG_DATUM(n)) +#define ExpandedRecordGetDatum(erh) EOHPGetRWDatum(&(erh)->hdr) +#define ExpandedRecordGetRODatum(erh) EOHPGetRODatum(&(erh)->hdr) +#define PG_RETURN_EXPANDED_RECORD(x) PG_RETURN_DATUM(ExpandedRecordGetDatum(x)) + +/* assorted other macros */ +#define ExpandedRecordIsEmpty(erh) \ + (((erh)->flags & (ER_FLAG_DVALUES_VALID | ER_FLAG_FVALUE_VALID)) == 0) +#define ExpandedRecordIsDomain(erh) \ + (((erh)->flags & ER_FLAG_IS_DOMAIN) != 0) + +/* this can substitute for TransferExpandedObject() when we already have erh */ +#define TransferExpandedRecord(erh, cxt) \ + MemoryContextSetParent((erh)->hdr.eoh_context, cxt) + +/* information returned by expanded_record_lookup_field() */ +typedef struct ExpandedRecordFieldInfo +{ + int fnumber; /* field's attr number in record */ + Oid ftypeid; /* field's type/typmod info */ + int32 ftypmod; + Oid fcollation; /* field's collation if any */ +} ExpandedRecordFieldInfo; + +/* + * prototypes for functions defined in expandedrecord.c + */ +extern ExpandedRecordHeader *make_expanded_record_from_typeid(Oid type_id, int32 typmod, + MemoryContext parentcontext); +extern ExpandedRecordHeader *make_expanded_record_from_tupdesc(TupleDesc tupdesc, + MemoryContext parentcontext); +extern ExpandedRecordHeader *make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh, + MemoryContext parentcontext); +extern void expanded_record_set_tuple(ExpandedRecordHeader *erh, + HeapTuple tuple, bool copy, bool expand_external); +extern Datum make_expanded_record_from_datum(Datum recorddatum, + MemoryContext parentcontext); +extern TupleDesc expanded_record_fetch_tupdesc(ExpandedRecordHeader *erh); +extern HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh); +extern ExpandedRecordHeader *DatumGetExpandedRecord(Datum d); +extern void deconstruct_expanded_record(ExpandedRecordHeader *erh); +extern bool expanded_record_lookup_field(ExpandedRecordHeader *erh, + const char *fieldname, + ExpandedRecordFieldInfo *finfo); +extern Datum expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber, + bool *isnull); +extern void expanded_record_set_field_internal(ExpandedRecordHeader *erh, + int fnumber, + Datum newValue, bool isnull, + bool expand_external, + bool check_constraints); +extern void expanded_record_set_fields(ExpandedRecordHeader *erh, + const Datum *newValues, const bool *isnulls, + bool expand_external); + +/* outside code should never call expanded_record_set_field_internal as such */ +#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external) \ + expanded_record_set_field_internal(erh, fnumber, newValue, isnull, expand_external, true) + +/* + * Inline-able fast cases. The expanded_record_fetch_xxx functions above + * handle the general cases. + */ + +/* Get the tupdesc for the expanded record's actual type */ +static inline TupleDesc +expanded_record_get_tupdesc(ExpandedRecordHeader *erh) +{ + if (likely(erh->er_tupdesc != NULL)) + return erh->er_tupdesc; + else + return expanded_record_fetch_tupdesc(erh); +} + +/* Get value of record field */ +static inline Datum +expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, + bool *isnull) +{ + if ((erh->flags & ER_FLAG_DVALUES_VALID) && + likely(fnumber > 0 && fnumber <= erh->nfields)) + { + *isnull = erh->dnulls[fnumber - 1]; + return erh->dvalues[fnumber - 1]; + } + else + return expanded_record_fetch_field(erh, fnumber, isnull); +} + +#endif /* EXPANDEDRECORD_H */ diff --git a/src/include/utils/float.h b/src/include/utils/float.h new file mode 100644 index 0000000..4bf0e3a --- /dev/null +++ b/src/include/utils/float.h @@ -0,0 +1,356 @@ +/*------------------------------------------------------------------------- + * + * float.h + * Definitions for the built-in floating-point types + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/include/utils/float.h + * + *------------------------------------------------------------------------- + */ +#ifndef FLOAT_H +#define FLOAT_H + +#include <math.h> + +#ifndef M_PI +/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */ +#define M_PI 3.14159265358979323846 +#endif + +/* Radians per degree, a.k.a. PI / 180 */ +#define RADIANS_PER_DEGREE 0.0174532925199432957692 + +/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. */ +#if defined(WIN32) && !defined(NAN) +static const uint32 nan[2] = {0xffffffff, 0x7fffffff}; + +#define NAN (*(const float8 *) nan) +#endif + +extern PGDLLIMPORT int extra_float_digits; + +/* + * Utility functions in float.c + */ +extern void float_overflow_error(void) pg_attribute_noreturn(); +extern void float_underflow_error(void) pg_attribute_noreturn(); +extern void float_zero_divide_error(void) pg_attribute_noreturn(); +extern int is_infinite(float8 val); +extern float8 float8in_internal(char *num, char **endptr_p, + const char *type_name, const char *orig_string); +extern float8 float8in_internal_opt_error(char *num, char **endptr_p, + const char *type_name, const char *orig_string, + bool *have_error); +extern char *float8out_internal(float8 num); +extern int float4_cmp_internal(float4 a, float4 b); +extern int float8_cmp_internal(float8 a, float8 b); + +/* + * Routines to provide reasonably platform-independent handling of + * infinity and NaN + * + * We assume that isinf() and isnan() are available and work per spec. + * (On some platforms, we have to supply our own; see src/port.) However, + * generating an Infinity or NaN in the first place is less well standardized; + * pre-C99 systems tend not to have C99's INFINITY and NaN macros. We + * centralize our workarounds for this here. + */ + +/* + * The funny placements of the two #pragmas is necessary because of a + * long lived bug in the Microsoft compilers. + * See http://support.microsoft.com/kb/120968/en-us for details + */ +#ifdef _MSC_VER +#pragma warning(disable:4756) +#endif +static inline float4 +get_float4_infinity(void) +{ +#ifdef INFINITY + /* C99 standard way */ + return (float4) INFINITY; +#else +#ifdef _MSC_VER +#pragma warning(default:4756) +#endif + + /* + * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the + * largest normal float8. We assume forcing an overflow will get us a + * true infinity. + */ + return (float4) (HUGE_VAL * HUGE_VAL); +#endif +} + +static inline float8 +get_float8_infinity(void) +{ +#ifdef INFINITY + /* C99 standard way */ + return (float8) INFINITY; +#else + + /* + * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the + * largest normal float8. We assume forcing an overflow will get us a + * true infinity. + */ + return (float8) (HUGE_VAL * HUGE_VAL); +#endif +} + +static inline float4 +get_float4_nan(void) +{ +#ifdef NAN + /* C99 standard way */ + return (float4) NAN; +#else + /* Assume we can get a NAN via zero divide */ + return (float4) (0.0 / 0.0); +#endif +} + +static inline float8 +get_float8_nan(void) +{ + /* (float8) NAN doesn't work on some NetBSD/MIPS releases */ +#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__)) + /* C99 standard way */ + return (float8) NAN; +#else + /* Assume we can get a NaN via zero divide */ + return (float8) (0.0 / 0.0); +#endif +} + +/* + * Floating-point arithmetic with overflow/underflow reported as errors + * + * There isn't any way to check for underflow of addition/subtraction + * because numbers near the underflow value have already been rounded to + * the point where we can't detect that the two values were originally + * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 == + * 1.4013e-45. + */ + +static inline float4 +float4_pl(const float4 val1, const float4 val2) +{ + float4 result; + + result = val1 + val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + + return result; +} + +static inline float8 +float8_pl(const float8 val1, const float8 val2) +{ + float8 result; + + result = val1 + val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + + return result; +} + +static inline float4 +float4_mi(const float4 val1, const float4 val2) +{ + float4 result; + + result = val1 - val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + + return result; +} + +static inline float8 +float8_mi(const float8 val1, const float8 val2) +{ + float8 result; + + result = val1 - val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + + return result; +} + +static inline float4 +float4_mul(const float4 val1, const float4 val2) +{ + float4 result; + + result = val1 * val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f) + float_underflow_error(); + + return result; +} + +static inline float8 +float8_mul(const float8 val1, const float8 val2) +{ + float8 result; + + result = val1 * val2; + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0) + float_underflow_error(); + + return result; +} + +static inline float4 +float4_div(const float4 val1, const float4 val2) +{ + float4 result; + + if (unlikely(val2 == 0.0f) && !isnan(val1)) + float_zero_divide_error(); + result = val1 / val2; + if (unlikely(isinf(result)) && !isinf(val1)) + float_overflow_error(); + if (unlikely(result == 0.0f) && val1 != 0.0f && !isinf(val2)) + float_underflow_error(); + + return result; +} + +static inline float8 +float8_div(const float8 val1, const float8 val2) +{ + float8 result; + + if (unlikely(val2 == 0.0) && !isnan(val1)) + float_zero_divide_error(); + result = val1 / val2; + if (unlikely(isinf(result)) && !isinf(val1)) + float_overflow_error(); + if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2)) + float_underflow_error(); + + return result; +} + +/* + * Routines for NaN-aware comparisons + * + * We consider all NaNs to be equal and larger than any non-NaN. This is + * somewhat arbitrary; the important thing is to have a consistent sort + * order. + */ + +static inline bool +float4_eq(const float4 val1, const float4 val2) +{ + return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2; +} + +static inline bool +float8_eq(const float8 val1, const float8 val2) +{ + return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2; +} + +static inline bool +float4_ne(const float4 val1, const float4 val2) +{ + return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2; +} + +static inline bool +float8_ne(const float8 val1, const float8 val2) +{ + return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2; +} + +static inline bool +float4_lt(const float4 val1, const float4 val2) +{ + return !isnan(val1) && (isnan(val2) || val1 < val2); +} + +static inline bool +float8_lt(const float8 val1, const float8 val2) +{ + return !isnan(val1) && (isnan(val2) || val1 < val2); +} + +static inline bool +float4_le(const float4 val1, const float4 val2) +{ + return isnan(val2) || (!isnan(val1) && val1 <= val2); +} + +static inline bool +float8_le(const float8 val1, const float8 val2) +{ + return isnan(val2) || (!isnan(val1) && val1 <= val2); +} + +static inline bool +float4_gt(const float4 val1, const float4 val2) +{ + return !isnan(val2) && (isnan(val1) || val1 > val2); +} + +static inline bool +float8_gt(const float8 val1, const float8 val2) +{ + return !isnan(val2) && (isnan(val1) || val1 > val2); +} + +static inline bool +float4_ge(const float4 val1, const float4 val2) +{ + return isnan(val1) || (!isnan(val2) && val1 >= val2); +} + +static inline bool +float8_ge(const float8 val1, const float8 val2) +{ + return isnan(val1) || (!isnan(val2) && val1 >= val2); +} + +static inline float4 +float4_min(const float4 val1, const float4 val2) +{ + return float4_lt(val1, val2) ? val1 : val2; +} + +static inline float8 +float8_min(const float8 val1, const float8 val2) +{ + return float8_lt(val1, val2) ? val1 : val2; +} + +static inline float4 +float4_max(const float4 val1, const float4 val2) +{ + return float4_gt(val1, val2) ? val1 : val2; +} + +static inline float8 +float8_max(const float8 val1, const float8 val2) +{ + return float8_gt(val1, val2) ? val1 : val2; +} + +#endif /* FLOAT_H */ diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h new file mode 100644 index 0000000..0a59937 --- /dev/null +++ b/src/include/utils/fmgrtab.h @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * fmgrtab.h + * The function manager's table of internal functions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/fmgrtab.h + * + *------------------------------------------------------------------------- + */ +#ifndef FMGRTAB_H +#define FMGRTAB_H + +#include "access/transam.h" +#include "fmgr.h" + + +/* + * This table stores info about all the built-in functions (ie, functions + * that are compiled into the Postgres executable). + */ + +typedef struct +{ + Oid foid; /* OID of the function */ + short nargs; /* 0..FUNC_MAX_ARGS, or -1 if variable count */ + bool strict; /* T if function is "strict" */ + bool retset; /* T if function returns a set */ + const char *funcName; /* C name of the function */ + PGFunction func; /* pointer to compiled function */ +} FmgrBuiltin; + +extern PGDLLIMPORT const FmgrBuiltin fmgr_builtins[]; + +extern PGDLLIMPORT const int fmgr_nbuiltins; /* number of entries in table */ + +extern PGDLLIMPORT const Oid fmgr_last_builtin_oid; /* highest function OID in + * table */ + +/* + * Mapping from a builtin function's OID to its index in the fmgr_builtins + * array. This is indexed from 0 through fmgr_last_builtin_oid. + */ +#define InvalidOidBuiltinMapping PG_UINT16_MAX +extern PGDLLIMPORT const uint16 fmgr_builtin_oid_index[]; + +#endif /* FMGRTAB_H */ diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h new file mode 100644 index 0000000..851e787 --- /dev/null +++ b/src/include/utils/formatting.h @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------- + * formatting.h + * + * src/include/utils/formatting.h + * + * + * Portions Copyright (c) 1999-2022, PostgreSQL Global Development Group + * + * The PostgreSQL routines for a DateTime/int/float/numeric formatting, + * inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. + * + * Karel Zak + * + * ----------------------------------------------------------------------- + */ + +#ifndef _FORMATTING_H_ +#define _FORMATTING_H_ + + +extern char *str_tolower(const char *buff, size_t nbytes, Oid collid); +extern char *str_toupper(const char *buff, size_t nbytes, Oid collid); +extern char *str_initcap(const char *buff, size_t nbytes, Oid collid); + +extern char *asc_tolower(const char *buff, size_t nbytes); +extern char *asc_toupper(const char *buff, size_t nbytes); +extern char *asc_initcap(const char *buff, size_t nbytes); + +extern Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, + Oid *typid, int32 *typmod, int *tz, + bool *have_error); + +#endif diff --git a/src/include/utils/freepage.h b/src/include/utils/freepage.h new file mode 100644 index 0000000..e69b280 --- /dev/null +++ b/src/include/utils/freepage.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * freepage.h + * Management of page-organized free memory. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/freepage.h + * + *------------------------------------------------------------------------- + */ + +#ifndef FREEPAGE_H +#define FREEPAGE_H + +#include "storage/lwlock.h" +#include "utils/relptr.h" + +/* Forward declarations. */ +typedef struct FreePageSpanLeader FreePageSpanLeader; +typedef struct FreePageBtree FreePageBtree; +typedef struct FreePageManager FreePageManager; + +/* + * PostgreSQL normally uses 8kB pages for most things, but many common + * architecture/operating system pairings use a 4kB page size for memory + * allocation, so we do that here also. + */ +#define FPM_PAGE_SIZE 4096 + +/* + * Each freelist except for the last contains only spans of one particular + * size. Everything larger goes on the last one. In some sense this seems + * like a waste since most allocations are in a few common sizes, but it + * means that small allocations can simply pop the head of the relevant list + * without needing to worry about whether the object we find there is of + * precisely the correct size (because we know it must be). + */ +#define FPM_NUM_FREELISTS 129 + +/* Define relative pointer types. */ +relptr_declare(FreePageBtree, RelptrFreePageBtree); +relptr_declare(FreePageManager, RelptrFreePageManager); +relptr_declare(FreePageSpanLeader, RelptrFreePageSpanLeader); + +/* Everything we need in order to manage free pages (see freepage.c) */ +struct FreePageManager +{ + RelptrFreePageManager self; + RelptrFreePageBtree btree_root; + RelptrFreePageSpanLeader btree_recycle; + unsigned btree_depth; + unsigned btree_recycle_count; + Size singleton_first_page; + Size singleton_npages; + Size contiguous_pages; + bool contiguous_pages_dirty; + RelptrFreePageSpanLeader freelist[FPM_NUM_FREELISTS]; +#ifdef FPM_EXTRA_ASSERTS + /* For debugging only, pages put minus pages gotten. */ + Size free_pages; +#endif +}; + +/* Macros to convert between page numbers (expressed as Size) and pointers. */ +#define fpm_page_to_pointer(base, page) \ + (AssertVariableIsOfTypeMacro(page, Size), \ + (base) + FPM_PAGE_SIZE * (page)) +#define fpm_pointer_to_page(base, ptr) \ + (((Size) (((char *) (ptr)) - (base))) / FPM_PAGE_SIZE) + +/* Macro to convert an allocation size to a number of pages. */ +#define fpm_size_to_pages(sz) \ + (((sz) + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE) + +/* Macros to check alignment of absolute and relative pointers. */ +#define fpm_pointer_is_page_aligned(base, ptr) \ + (((Size) (((char *) (ptr)) - (base))) % FPM_PAGE_SIZE == 0) +#define fpm_relptr_is_page_aligned(base, relptr) \ + (relptr_offset(relptr) % FPM_PAGE_SIZE == 0) + +/* Macro to find base address of the segment containing a FreePageManager. */ +#define fpm_segment_base(fpm) \ + (((char *) fpm) - relptr_offset(fpm->self)) + +/* Macro to access a FreePageManager's largest consecutive run of pages. */ +#define fpm_largest(fpm) \ + (fpm->contiguous_pages) + +/* Functions to manipulate the free page map. */ +extern void FreePageManagerInitialize(FreePageManager *fpm, char *base); +extern bool FreePageManagerGet(FreePageManager *fpm, Size npages, + Size *first_page); +extern void FreePageManagerPut(FreePageManager *fpm, Size first_page, + Size npages); +extern char *FreePageManagerDump(FreePageManager *fpm); + +#endif /* FREEPAGE_H */ diff --git a/src/include/utils/geo_decls.h b/src/include/utils/geo_decls.h new file mode 100644 index 0000000..7190307 --- /dev/null +++ b/src/include/utils/geo_decls.h @@ -0,0 +1,221 @@ +/*------------------------------------------------------------------------- + * + * geo_decls.h - Declarations for various 2D constructs. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/geo_decls.h + * + * XXX These routines were not written by a numerical analyst. + * + * XXX I have made some attempt to flesh out the operators + * and data types. There are still some more to do. - tgl 97/04/19 + * + *------------------------------------------------------------------------- + */ +#ifndef GEO_DECLS_H +#define GEO_DECLS_H + +#include <math.h> + +#include "fmgr.h" + +/*-------------------------------------------------------------------- + * Useful floating point utilities and constants. + *-------------------------------------------------------------------- + * + * "Fuzzy" floating-point comparisons: values within EPSILON of each other + * are considered equal. Beware of normal reasoning about the behavior of + * these comparisons, since for example FPeq does not behave transitively. + * + * Note that these functions are not NaN-aware and will give FALSE for + * any case involving NaN inputs. + * + * Also note that these will give sane answers for infinite inputs, + * where it's important to avoid computing Inf minus Inf; we do so + * by eliminating equality cases before subtracting. + */ + +#define EPSILON 1.0E-06 + +#ifdef EPSILON +#define FPzero(A) (fabs(A) <= EPSILON) + +static inline bool +FPeq(double A, double B) +{ + return A == B || fabs(A - B) <= EPSILON; +} + +static inline bool +FPne(double A, double B) +{ + return A != B && fabs(A - B) > EPSILON; +} + +static inline bool +FPlt(double A, double B) +{ + return A + EPSILON < B; +} + +static inline bool +FPle(double A, double B) +{ + return A <= B + EPSILON; +} + +static inline bool +FPgt(double A, double B) +{ + return A > B + EPSILON; +} + +static inline bool +FPge(double A, double B) +{ + return A + EPSILON >= B; +} +#else +#define FPzero(A) ((A) == 0) +#define FPeq(A,B) ((A) == (B)) +#define FPne(A,B) ((A) != (B)) +#define FPlt(A,B) ((A) < (B)) +#define FPle(A,B) ((A) <= (B)) +#define FPgt(A,B) ((A) > (B)) +#define FPge(A,B) ((A) >= (B)) +#endif + +#define HYPOT(A, B) pg_hypot(A, B) + +/*--------------------------------------------------------------------- + * Point - (x,y) + *-------------------------------------------------------------------*/ +typedef struct +{ + float8 x, + y; +} Point; + + +/*--------------------------------------------------------------------- + * LSEG - A straight line, specified by endpoints. + *-------------------------------------------------------------------*/ +typedef struct +{ + Point p[2]; +} LSEG; + + +/*--------------------------------------------------------------------- + * PATH - Specified by vertex points. + *-------------------------------------------------------------------*/ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 npts; + int32 closed; /* is this a closed polygon? */ + int32 dummy; /* padding to make it double align */ + Point p[FLEXIBLE_ARRAY_MEMBER]; +} PATH; + + +/*--------------------------------------------------------------------- + * LINE - Specified by its general equation (Ax+By+C=0). + *-------------------------------------------------------------------*/ +typedef struct +{ + float8 A, + B, + C; +} LINE; + + +/*--------------------------------------------------------------------- + * BOX - Specified by two corner points, which are + * sorted to save calculation time later. + *-------------------------------------------------------------------*/ +typedef struct +{ + Point high, + low; /* corner POINTs */ +} BOX; + +/*--------------------------------------------------------------------- + * POLYGON - Specified by an array of doubles defining the points, + * keeping the number of points and the bounding box for + * speed purposes. + *-------------------------------------------------------------------*/ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 npts; + BOX boundbox; + Point p[FLEXIBLE_ARRAY_MEMBER]; +} POLYGON; + +/*--------------------------------------------------------------------- + * CIRCLE - Specified by a center point and radius. + *-------------------------------------------------------------------*/ +typedef struct +{ + Point center; + float8 radius; +} CIRCLE; + +/* + * fmgr interface macros + * + * Path and Polygon are toastable varlena types, the others are just + * fixed-size pass-by-reference types. + */ + +#define DatumGetPointP(X) ((Point *) DatumGetPointer(X)) +#define PointPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_POINT_P(n) DatumGetPointP(PG_GETARG_DATUM(n)) +#define PG_RETURN_POINT_P(x) return PointPGetDatum(x) + +#define DatumGetLsegP(X) ((LSEG *) DatumGetPointer(X)) +#define LsegPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_LSEG_P(n) DatumGetLsegP(PG_GETARG_DATUM(n)) +#define PG_RETURN_LSEG_P(x) return LsegPGetDatum(x) + +#define DatumGetPathP(X) ((PATH *) PG_DETOAST_DATUM(X)) +#define DatumGetPathPCopy(X) ((PATH *) PG_DETOAST_DATUM_COPY(X)) +#define PathPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_PATH_P(n) DatumGetPathP(PG_GETARG_DATUM(n)) +#define PG_GETARG_PATH_P_COPY(n) DatumGetPathPCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_PATH_P(x) return PathPGetDatum(x) + +#define DatumGetLineP(X) ((LINE *) DatumGetPointer(X)) +#define LinePGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_LINE_P(n) DatumGetLineP(PG_GETARG_DATUM(n)) +#define PG_RETURN_LINE_P(x) return LinePGetDatum(x) + +#define DatumGetBoxP(X) ((BOX *) DatumGetPointer(X)) +#define BoxPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_BOX_P(n) DatumGetBoxP(PG_GETARG_DATUM(n)) +#define PG_RETURN_BOX_P(x) return BoxPGetDatum(x) + +#define DatumGetPolygonP(X) ((POLYGON *) PG_DETOAST_DATUM(X)) +#define DatumGetPolygonPCopy(X) ((POLYGON *) PG_DETOAST_DATUM_COPY(X)) +#define PolygonPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_POLYGON_P(n) DatumGetPolygonP(PG_GETARG_DATUM(n)) +#define PG_GETARG_POLYGON_P_COPY(n) DatumGetPolygonPCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_POLYGON_P(x) return PolygonPGetDatum(x) + +#define DatumGetCircleP(X) ((CIRCLE *) DatumGetPointer(X)) +#define CirclePGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_CIRCLE_P(n) DatumGetCircleP(PG_GETARG_DATUM(n)) +#define PG_RETURN_CIRCLE_P(x) return CirclePGetDatum(x) + + +/* + * in geo_ops.c + */ + +extern float8 pg_hypot(float8 x, float8 y); + +#endif /* GEO_DECLS_H */ diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h new file mode 100644 index 0000000..65eafb4 --- /dev/null +++ b/src/include/utils/guc.h @@ -0,0 +1,469 @@ +/*-------------------------------------------------------------------- + * guc.h + * + * External declarations pertaining to backend/utils/misc/guc.c and + * backend/utils/misc/guc-file.l + * + * Copyright (c) 2000-2022, PostgreSQL Global Development Group + * Written by Peter Eisentraut <peter_e@gmx.net>. + * + * src/include/utils/guc.h + *-------------------------------------------------------------------- + */ +#ifndef GUC_H +#define GUC_H + +#include "nodes/parsenodes.h" +#include "tcop/dest.h" +#include "utils/array.h" + + +/* upper limit for GUC variables measured in kilobytes of memory */ +/* note that various places assume the byte size fits in a "long" variable */ +#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4 +#define MAX_KILOBYTES INT_MAX +#else +#define MAX_KILOBYTES (INT_MAX / 1024) +#endif + +/* + * Automatic configuration file name for ALTER SYSTEM. + * This file will be used to store values of configuration parameters + * set by ALTER SYSTEM command. + */ +#define PG_AUTOCONF_FILENAME "postgresql.auto.conf" + +/* + * Certain options can only be set at certain times. The rules are + * like this: + * + * INTERNAL options cannot be set by the user at all, but only through + * internal processes ("server_version" is an example). These are GUC + * variables only so they can be shown by SHOW, etc. + * + * POSTMASTER options can only be set when the postmaster starts, + * either from the configuration file or the command line. + * + * SIGHUP options can only be set at postmaster startup or by changing + * the configuration file and sending the HUP signal to the postmaster + * or a backend process. (Notice that the signal receipt will not be + * evaluated immediately. The postmaster and the backend check it at a + * certain point in their main loop. It's safer to wait than to read a + * file asynchronously.) + * + * BACKEND and SU_BACKEND options can only be set at postmaster startup, + * from the configuration file, or by client request in the connection + * startup packet (e.g., from libpq's PGOPTIONS variable). SU_BACKEND + * options can be set from the startup packet only when the user is a + * superuser. Furthermore, an already-started backend will ignore changes + * to such an option in the configuration file. The idea is that these + * options are fixed for a given backend once it's started, but they can + * vary across backends. + * + * SUSET options can be set at postmaster startup, with the SIGHUP + * mechanism, or from the startup packet or SQL if you're a superuser. + * + * USERSET options can be set by anyone any time. + */ +typedef enum +{ + PGC_INTERNAL, + PGC_POSTMASTER, + PGC_SIGHUP, + PGC_SU_BACKEND, + PGC_BACKEND, + PGC_SUSET, + PGC_USERSET +} GucContext; + +/* + * The following type records the source of the current setting. A + * new setting can only take effect if the previous setting had the + * same or lower level. (E.g, changing the config file doesn't + * override the postmaster command line.) Tracking the source allows us + * to process sources in any convenient order without affecting results. + * Sources <= PGC_S_OVERRIDE will set the default used by RESET, as well + * as the current value. + * + * PGC_S_INTERACTIVE isn't actually a source value, but is the + * dividing line between "interactive" and "non-interactive" sources for + * error reporting purposes. + * + * PGC_S_TEST is used when testing values to be used later. For example, + * ALTER DATABASE/ROLE tests proposed per-database or per-user defaults this + * way, and CREATE FUNCTION tests proposed function SET clauses this way. + * This is an interactive case, but it needs its own source value because + * some assign hooks need to make different validity checks in this case. + * In particular, references to nonexistent database objects generally + * shouldn't throw hard errors in this case, at most NOTICEs, since the + * objects might exist by the time the setting is used for real. + * + * When setting the value of a non-compile-time-constant PGC_INTERNAL option, + * source == PGC_S_DYNAMIC_DEFAULT should typically be used so that the value + * will show as "default" in pg_settings. If there is a specific reason not + * to want that, use source == PGC_S_OVERRIDE. + * + * NB: see GucSource_Names in guc.c if you change this. + */ +typedef enum +{ + PGC_S_DEFAULT, /* hard-wired default ("boot_val") */ + PGC_S_DYNAMIC_DEFAULT, /* default computed during initialization */ + PGC_S_ENV_VAR, /* postmaster environment variable */ + PGC_S_FILE, /* postgresql.conf */ + PGC_S_ARGV, /* postmaster command line */ + PGC_S_GLOBAL, /* global in-database setting */ + PGC_S_DATABASE, /* per-database setting */ + PGC_S_USER, /* per-user setting */ + PGC_S_DATABASE_USER, /* per-user-and-database setting */ + PGC_S_CLIENT, /* from client connection request */ + PGC_S_OVERRIDE, /* special case to forcibly set default */ + PGC_S_INTERACTIVE, /* dividing line for error reporting */ + PGC_S_TEST, /* test per-database or per-user setting */ + PGC_S_SESSION /* SET command */ +} GucSource; + +/* + * Parsing the configuration file(s) will return a list of name-value pairs + * with source location info. We also abuse this data structure to carry + * error reports about the config files. An entry reporting an error will + * have errmsg != NULL, and might have NULLs for name, value, and/or filename. + * + * If "ignore" is true, don't attempt to apply the item (it might be an error + * report, or an item we determined to be duplicate). "applied" is set true + * if we successfully applied, or could have applied, the setting. + */ +typedef struct ConfigVariable +{ + char *name; + char *value; + char *errmsg; + char *filename; + int sourceline; + bool ignore; + bool applied; + struct ConfigVariable *next; +} ConfigVariable; + +extern bool ParseConfigFile(const char *config_file, bool strict, + const char *calling_file, int calling_lineno, + int depth, int elevel, + ConfigVariable **head_p, ConfigVariable **tail_p); +extern bool ParseConfigFp(FILE *fp, const char *config_file, + int depth, int elevel, + ConfigVariable **head_p, ConfigVariable **tail_p); +extern bool ParseConfigDirectory(const char *includedir, + const char *calling_file, int calling_lineno, + int depth, int elevel, + ConfigVariable **head_p, + ConfigVariable **tail_p); +extern void FreeConfigVariables(ConfigVariable *list); +extern char *DeescapeQuotedString(const char *s); + +/* + * The possible values of an enum variable are specified by an array of + * name-value pairs. The "hidden" flag means the value is accepted but + * won't be displayed when guc.c is asked for a list of acceptable values. + */ +struct config_enum_entry +{ + const char *name; + int val; + bool hidden; +}; + +/* + * Signatures for per-variable check/assign/show hook functions + */ +typedef bool (*GucBoolCheckHook) (bool *newval, void **extra, GucSource source); +typedef bool (*GucIntCheckHook) (int *newval, void **extra, GucSource source); +typedef bool (*GucRealCheckHook) (double *newval, void **extra, GucSource source); +typedef bool (*GucStringCheckHook) (char **newval, void **extra, GucSource source); +typedef bool (*GucEnumCheckHook) (int *newval, void **extra, GucSource source); + +typedef void (*GucBoolAssignHook) (bool newval, void *extra); +typedef void (*GucIntAssignHook) (int newval, void *extra); +typedef void (*GucRealAssignHook) (double newval, void *extra); +typedef void (*GucStringAssignHook) (const char *newval, void *extra); +typedef void (*GucEnumAssignHook) (int newval, void *extra); + +typedef const char *(*GucShowHook) (void); + +/* + * Miscellaneous + */ +typedef enum +{ + /* Types of set_config_option actions */ + GUC_ACTION_SET, /* regular SET command */ + GUC_ACTION_LOCAL, /* SET LOCAL command */ + GUC_ACTION_SAVE /* function SET option, or temp assignment */ +} GucAction; + +#define GUC_QUALIFIER_SEPARATOR '.' + +/* + * bit values in "flags" of a GUC variable + */ +#define GUC_LIST_INPUT 0x0001 /* input can be list format */ +#define GUC_LIST_QUOTE 0x0002 /* double-quote list elements */ +#define GUC_NO_SHOW_ALL 0x0004 /* exclude from SHOW ALL */ +#define GUC_NO_RESET_ALL 0x0008 /* exclude from RESET ALL */ +#define GUC_REPORT 0x0010 /* auto-report changes to client */ +#define GUC_NOT_IN_SAMPLE 0x0020 /* not in postgresql.conf.sample */ +#define GUC_DISALLOW_IN_FILE 0x0040 /* can't set in postgresql.conf */ +#define GUC_CUSTOM_PLACEHOLDER 0x0080 /* placeholder for custom variable */ +#define GUC_SUPERUSER_ONLY 0x0100 /* show only to superusers */ +#define GUC_IS_NAME 0x0200 /* limit string to NAMEDATALEN-1 */ +#define GUC_NOT_WHILE_SEC_REST 0x0400 /* can't set if security restricted */ +#define GUC_DISALLOW_IN_AUTO_FILE 0x0800 /* can't set in + * PG_AUTOCONF_FILENAME */ + +#define GUC_UNIT_KB 0x1000 /* value is in kilobytes */ +#define GUC_UNIT_BLOCKS 0x2000 /* value is in blocks */ +#define GUC_UNIT_XBLOCKS 0x3000 /* value is in xlog blocks */ +#define GUC_UNIT_MB 0x4000 /* value is in megabytes */ +#define GUC_UNIT_BYTE 0x8000 /* value is in bytes */ +#define GUC_UNIT_MEMORY 0xF000 /* mask for size-related units */ + +#define GUC_UNIT_MS 0x10000 /* value is in milliseconds */ +#define GUC_UNIT_S 0x20000 /* value is in seconds */ +#define GUC_UNIT_MIN 0x30000 /* value is in minutes */ +#define GUC_UNIT_TIME 0xF0000 /* mask for time-related units */ + +#define GUC_EXPLAIN 0x100000 /* include in explain */ + +/* + * GUC_RUNTIME_COMPUTED is intended for runtime-computed GUCs that are only + * available via 'postgres -C' if the server is not running. + */ +#define GUC_RUNTIME_COMPUTED 0x200000 + +#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME) + + +/* GUC vars that are actually declared in guc.c, rather than elsewhere */ +extern PGDLLIMPORT bool Debug_print_plan; +extern PGDLLIMPORT bool Debug_print_parse; +extern PGDLLIMPORT bool Debug_print_rewritten; +extern PGDLLIMPORT bool Debug_pretty_print; + +extern PGDLLIMPORT bool log_parser_stats; +extern PGDLLIMPORT bool log_planner_stats; +extern PGDLLIMPORT bool log_executor_stats; +extern PGDLLIMPORT bool log_statement_stats; +extern PGDLLIMPORT bool log_btree_build_stats; + +extern PGDLLIMPORT bool check_function_bodies; +extern PGDLLIMPORT bool session_auth_is_superuser; + +extern PGDLLIMPORT bool log_duration; +extern PGDLLIMPORT int log_parameter_max_length; +extern PGDLLIMPORT int log_parameter_max_length_on_error; +extern PGDLLIMPORT int log_min_error_statement; +extern PGDLLIMPORT int log_min_messages; +extern PGDLLIMPORT int client_min_messages; +extern PGDLLIMPORT int log_min_duration_sample; +extern PGDLLIMPORT int log_min_duration_statement; +extern PGDLLIMPORT int log_temp_files; +extern PGDLLIMPORT double log_statement_sample_rate; +extern PGDLLIMPORT double log_xact_sample_rate; +extern PGDLLIMPORT char *backtrace_functions; +extern PGDLLIMPORT char *backtrace_symbol_list; + +extern PGDLLIMPORT int temp_file_limit; + +extern PGDLLIMPORT int num_temp_buffers; + +extern PGDLLIMPORT char *cluster_name; +extern PGDLLIMPORT char *ConfigFileName; +extern PGDLLIMPORT char *HbaFileName; +extern PGDLLIMPORT char *IdentFileName; +extern PGDLLIMPORT char *external_pid_file; + +extern PGDLLIMPORT char *application_name; + +extern PGDLLIMPORT int tcp_keepalives_idle; +extern PGDLLIMPORT int tcp_keepalives_interval; +extern PGDLLIMPORT int tcp_keepalives_count; +extern PGDLLIMPORT int tcp_user_timeout; + +#ifdef TRACE_SORT +extern PGDLLIMPORT bool trace_sort; +#endif + +/* + * Functions exported by guc.c + */ +extern void SetConfigOption(const char *name, const char *value, + GucContext context, GucSource source); + +extern void DefineCustomBoolVariable(const char *name, + const char *short_desc, + const char *long_desc, + bool *valueAddr, + bool bootValue, + GucContext context, + int flags, + GucBoolCheckHook check_hook, + GucBoolAssignHook assign_hook, + GucShowHook show_hook); + +extern void DefineCustomIntVariable(const char *name, + const char *short_desc, + const char *long_desc, + int *valueAddr, + int bootValue, + int minValue, + int maxValue, + GucContext context, + int flags, + GucIntCheckHook check_hook, + GucIntAssignHook assign_hook, + GucShowHook show_hook); + +extern void DefineCustomRealVariable(const char *name, + const char *short_desc, + const char *long_desc, + double *valueAddr, + double bootValue, + double minValue, + double maxValue, + GucContext context, + int flags, + GucRealCheckHook check_hook, + GucRealAssignHook assign_hook, + GucShowHook show_hook); + +extern void DefineCustomStringVariable(const char *name, + const char *short_desc, + const char *long_desc, + char **valueAddr, + const char *bootValue, + GucContext context, + int flags, + GucStringCheckHook check_hook, + GucStringAssignHook assign_hook, + GucShowHook show_hook); + +extern void DefineCustomEnumVariable(const char *name, + const char *short_desc, + const char *long_desc, + int *valueAddr, + int bootValue, + const struct config_enum_entry *options, + GucContext context, + int flags, + GucEnumCheckHook check_hook, + GucEnumAssignHook assign_hook, + GucShowHook show_hook); + +extern void MarkGUCPrefixReserved(const char *className); + +/* old name for MarkGUCPrefixReserved, for backwards compatibility: */ +#define EmitWarningsOnPlaceholders(className) MarkGUCPrefixReserved(className) + +extern const char *GetConfigOption(const char *name, bool missing_ok, + bool restrict_privileged); +extern const char *GetConfigOptionResetString(const char *name); +extern int GetConfigOptionFlags(const char *name, bool missing_ok); +extern void ProcessConfigFile(GucContext context); +extern char *convert_GUC_name_for_parameter_acl(const char *name); +extern bool check_GUC_name_for_parameter_acl(const char *name); +extern void InitializeGUCOptions(void); +extern void InitializeWalConsistencyChecking(void); +extern bool SelectConfigFiles(const char *userDoption, const char *progname); +extern void ResetAllOptions(void); +extern void AtStart_GUC(void); +extern int NewGUCNestLevel(void); +extern void AtEOXact_GUC(bool isCommit, int nestLevel); +extern void BeginReportingGUCOptions(void); +extern void ReportChangedGUCOptions(void); +extern void ParseLongOption(const char *string, char **name, char **value); +extern bool parse_int(const char *value, int *result, int flags, + const char **hintmsg); +extern bool parse_real(const char *value, double *result, int flags, + const char **hintmsg); +extern int set_config_option(const char *name, const char *value, + GucContext context, GucSource source, + GucAction action, bool changeVal, int elevel, + bool is_reload); +extern int set_config_option_ext(const char *name, const char *value, + GucContext context, GucSource source, + Oid srole, + GucAction action, bool changeVal, int elevel, + bool is_reload); +extern void AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt); +extern char *GetConfigOptionByName(const char *name, const char **varname, + bool missing_ok); +extern void GetConfigOptionByNum(int varnum, const char **values, bool *noshow); +extern int GetNumConfigOptions(void); + +extern void SetPGVariable(const char *name, List *args, bool is_local); +extern void GetPGVariable(const char *name, DestReceiver *dest); +extern TupleDesc GetPGVariableResultDesc(const char *name); + +extern void ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel); +extern char *ExtractSetVariableArgs(VariableSetStmt *stmt); + +extern void ProcessGUCArray(ArrayType *array, + GucContext context, GucSource source, GucAction action); +extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value); +extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name); +extern ArrayType *GUCArrayReset(ArrayType *array); + +#ifdef EXEC_BACKEND +extern void write_nondefault_variables(GucContext context); +extern void read_nondefault_variables(void); +#endif + +/* GUC serialization */ +extern Size EstimateGUCStateSpace(void); +extern void SerializeGUCState(Size maxsize, char *start_address); +extern void RestoreGUCState(void *gucstate); + +/* Support for messages reported from GUC check hooks */ + +extern PGDLLIMPORT char *GUC_check_errmsg_string; +extern PGDLLIMPORT char *GUC_check_errdetail_string; +extern PGDLLIMPORT char *GUC_check_errhint_string; + +extern void GUC_check_errcode(int sqlerrcode); + +#define GUC_check_errmsg \ + pre_format_elog_string(errno, TEXTDOMAIN), \ + GUC_check_errmsg_string = format_elog_string + +#define GUC_check_errdetail \ + pre_format_elog_string(errno, TEXTDOMAIN), \ + GUC_check_errdetail_string = format_elog_string + +#define GUC_check_errhint \ + pre_format_elog_string(errno, TEXTDOMAIN), \ + GUC_check_errhint_string = format_elog_string + + +/* + * The following functions are not in guc.c, but are declared here to avoid + * having to include guc.h in some widely used headers that it really doesn't + * belong in. + */ + +/* in commands/tablespace.c */ +extern bool check_default_tablespace(char **newval, void **extra, GucSource source); +extern bool check_temp_tablespaces(char **newval, void **extra, GucSource source); +extern void assign_temp_tablespaces(const char *newval, void *extra); + +/* in catalog/namespace.c */ +extern bool check_search_path(char **newval, void **extra, GucSource source); +extern void assign_search_path(const char *newval, void *extra); + +/* in access/transam/xlog.c */ +extern bool check_wal_buffers(int *newval, void **extra, GucSource source); +extern void assign_xlog_sync_method(int new_sync_method, void *extra); + +/* in access/transam/xlogprefetcher.c */ +extern bool check_recovery_prefetch(int *new_value, void **extra, GucSource source); +extern void assign_recovery_prefetch(int new_value, void *extra); + +#endif /* GUC_H */ diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h new file mode 100644 index 0000000..47e7819 --- /dev/null +++ b/src/include/utils/guc_tables.h @@ -0,0 +1,286 @@ +/*------------------------------------------------------------------------- + * + * guc_tables.h + * Declarations of tables used by GUC. + * + * See src/backend/utils/misc/README for design notes. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/utils/guc_tables.h + * + *------------------------------------------------------------------------- + */ +#ifndef GUC_TABLES_H +#define GUC_TABLES_H 1 + +#include "utils/guc.h" + +/* + * GUC supports these types of variables: + */ +enum config_type +{ + PGC_BOOL, + PGC_INT, + PGC_REAL, + PGC_STRING, + PGC_ENUM +}; + +union config_var_val +{ + bool boolval; + int intval; + double realval; + char *stringval; + int enumval; +}; + +/* + * The actual value of a GUC variable can include a malloc'd opaque struct + * "extra", which is created by its check_hook and used by its assign_hook. + */ +typedef struct config_var_value +{ + union config_var_val val; + void *extra; +} config_var_value; + +/* + * Groupings to help organize all the run-time options for display. + * Be sure this agrees with the way the options are categorized in config.sgml! + */ +enum config_group +{ + UNGROUPED, /* use for options not shown in pg_settings */ + FILE_LOCATIONS, + CONN_AUTH_SETTINGS, + CONN_AUTH_AUTH, + CONN_AUTH_SSL, + RESOURCES_MEM, + RESOURCES_DISK, + RESOURCES_KERNEL, + RESOURCES_VACUUM_DELAY, + RESOURCES_BGWRITER, + RESOURCES_ASYNCHRONOUS, + WAL_SETTINGS, + WAL_CHECKPOINTS, + WAL_ARCHIVING, + WAL_RECOVERY, + WAL_ARCHIVE_RECOVERY, + WAL_RECOVERY_TARGET, + REPLICATION_SENDING, + REPLICATION_PRIMARY, + REPLICATION_STANDBY, + REPLICATION_SUBSCRIBERS, + QUERY_TUNING_METHOD, + QUERY_TUNING_COST, + QUERY_TUNING_GEQO, + QUERY_TUNING_OTHER, + LOGGING_WHERE, + LOGGING_WHEN, + LOGGING_WHAT, + PROCESS_TITLE, + STATS_MONITORING, + STATS_CUMULATIVE, + AUTOVACUUM, + CLIENT_CONN_STATEMENT, + CLIENT_CONN_LOCALE, + CLIENT_CONN_PRELOAD, + CLIENT_CONN_OTHER, + LOCK_MANAGEMENT, + COMPAT_OPTIONS_PREVIOUS, + COMPAT_OPTIONS_CLIENT, + ERROR_HANDLING_OPTIONS, + PRESET_OPTIONS, + CUSTOM_OPTIONS, + DEVELOPER_OPTIONS +}; + +/* + * Stack entry for saving the state a variable had prior to an uncommitted + * transactional change + */ +typedef enum +{ + /* This is almost GucAction, but we need a fourth state for SET+LOCAL */ + GUC_SAVE, /* entry caused by function SET option */ + GUC_SET, /* entry caused by plain SET command */ + GUC_LOCAL, /* entry caused by SET LOCAL command */ + GUC_SET_LOCAL /* entry caused by SET then SET LOCAL */ +} GucStackState; + +typedef struct guc_stack +{ + struct guc_stack *prev; /* previous stack item, if any */ + int nest_level; /* nesting depth at which we made entry */ + GucStackState state; /* see enum above */ + GucSource source; /* source of the prior value */ + /* masked value's source must be PGC_S_SESSION, so no need to store it */ + GucContext scontext; /* context that set the prior value */ + GucContext masked_scontext; /* context that set the masked value */ + Oid srole; /* role that set the prior value */ + Oid masked_srole; /* role that set the masked value */ + config_var_value prior; /* previous value of variable */ + config_var_value masked; /* SET value in a GUC_SET_LOCAL entry */ +} GucStack; + +/* + * Generic fields applicable to all types of variables + * + * The short description should be less than 80 chars in length. Some + * applications may use the long description as well, and will append + * it to the short description. (separated by a newline or '. ') + * + * srole is the role that set the current value, or BOOTSTRAP_SUPERUSERID + * if the value came from an internal source or the config file. Similarly + * for reset_srole (which is usually BOOTSTRAP_SUPERUSERID, but not always). + * + * Note that sourcefile/sourceline are kept here, and not pushed into stacked + * values, although in principle they belong with some stacked value if the + * active value is session- or transaction-local. This is to avoid bloating + * stack entries. We know they are only relevant when source == PGC_S_FILE. + */ +struct config_generic +{ + /* constant fields, must be set correctly in initial value: */ + const char *name; /* name of variable - MUST BE FIRST */ + GucContext context; /* context required to set the variable */ + enum config_group group; /* to help organize variables by function */ + const char *short_desc; /* short desc. of this variable's purpose */ + const char *long_desc; /* long desc. of this variable's purpose */ + int flags; /* flag bits, see guc.h */ + /* variable fields, initialized at runtime: */ + enum config_type vartype; /* type of variable (set only at startup) */ + int status; /* status bits, see below */ + GucSource source; /* source of the current actual value */ + GucSource reset_source; /* source of the reset_value */ + GucContext scontext; /* context that set the current value */ + GucContext reset_scontext; /* context that set the reset value */ + Oid srole; /* role that set the current value */ + Oid reset_srole; /* role that set the reset value */ + GucStack *stack; /* stacked prior values */ + void *extra; /* "extra" pointer for current actual value */ + char *last_reported; /* if variable is GUC_REPORT, value last sent + * to client (NULL if not yet sent) */ + char *sourcefile; /* file current setting is from (NULL if not + * set in config file) */ + int sourceline; /* line in source file */ +}; + +/* bit values in status field */ +#define GUC_IS_IN_FILE 0x0001 /* found it in config file */ +/* + * Caution: the GUC_IS_IN_FILE bit is transient state for ProcessConfigFile. + * Do not assume that its value represents useful information elsewhere. + */ +#define GUC_PENDING_RESTART 0x0002 /* changed value cannot be applied yet */ +#define GUC_NEEDS_REPORT 0x0004 /* new value must be reported to client */ + + +/* GUC records for specific variable types */ + +struct config_bool +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + bool *variable; + bool boot_val; + GucBoolCheckHook check_hook; + GucBoolAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + bool reset_val; + void *reset_extra; +}; + +struct config_int +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + int *variable; + int boot_val; + int min; + int max; + GucIntCheckHook check_hook; + GucIntAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + int reset_val; + void *reset_extra; +}; + +struct config_real +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + double *variable; + double boot_val; + double min; + double max; + GucRealCheckHook check_hook; + GucRealAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + double reset_val; + void *reset_extra; +}; + +/* + * A note about string GUCs: the boot_val is allowed to be NULL, which leads + * to the reset_val and the actual variable value (*variable) also being NULL. + * However, there is no way to set a NULL value subsequently using + * set_config_option or any other GUC API. Also, GUC APIs such as SHOW will + * display a NULL value as an empty string. Callers that choose to use a NULL + * boot_val should overwrite the setting later in startup, or else be careful + * that NULL doesn't have semantics that are visibly different from an empty + * string. + */ +struct config_string +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + char **variable; + const char *boot_val; + GucStringCheckHook check_hook; + GucStringAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + char *reset_val; + void *reset_extra; +}; + +struct config_enum +{ + struct config_generic gen; + /* constant fields, must be set correctly in initial value: */ + int *variable; + int boot_val; + const struct config_enum_entry *options; + GucEnumCheckHook check_hook; + GucEnumAssignHook assign_hook; + GucShowHook show_hook; + /* variable fields, initialized at runtime: */ + int reset_val; + void *reset_extra; +}; + +/* constant tables corresponding to enums above and in guc.h */ +extern PGDLLIMPORT const char *const config_group_names[]; +extern PGDLLIMPORT const char *const config_type_names[]; +extern PGDLLIMPORT const char *const GucContext_Names[]; +extern PGDLLIMPORT const char *const GucSource_Names[]; + +/* get the current set of variables */ +extern struct config_generic **get_guc_variables(void); + +extern void build_guc_variables(void); + +/* search in enum options */ +extern const char *config_enum_lookup_by_value(struct config_enum *record, int val); +extern bool config_enum_lookup_by_name(struct config_enum *record, + const char *value, int *retval); +extern struct config_generic **get_explain_guc_options(int *num); + +#endif /* GUC_TABLES_H */ diff --git a/src/include/utils/help_config.h b/src/include/utils/help_config.h new file mode 100644 index 0000000..dc23ae2 --- /dev/null +++ b/src/include/utils/help_config.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + * + * help_config.h + * Interface to the --help-config option of main.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/utils/help_config.h + * + *------------------------------------------------------------------------- + */ +#ifndef HELP_CONFIG_H +#define HELP_CONFIG_H 1 + +extern void GucInfoMain(void) pg_attribute_noreturn(); + +#endif diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h new file mode 100644 index 0000000..854c331 --- /dev/null +++ b/src/include/utils/hsearch.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- + * + * hsearch.h + * exported definitions for utils/hash/dynahash.c; see notes therein + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/hsearch.h + * + *------------------------------------------------------------------------- + */ +#ifndef HSEARCH_H +#define HSEARCH_H + + +/* + * Hash functions must have this signature. + */ +typedef uint32 (*HashValueFunc) (const void *key, Size keysize); + +/* + * Key comparison functions must have this signature. Comparison functions + * return zero for match, nonzero for no match. (The comparison function + * definition is designed to allow memcmp() and strncmp() to be used directly + * as key comparison functions.) + */ +typedef int (*HashCompareFunc) (const void *key1, const void *key2, + Size keysize); + +/* + * Key copying functions must have this signature. The return value is not + * used. (The definition is set up to allow memcpy() and strlcpy() to be + * used directly.) + */ +typedef void *(*HashCopyFunc) (void *dest, const void *src, Size keysize); + +/* + * Space allocation function for a hashtable --- designed to match malloc(). + * Note: there is no free function API; can't destroy a hashtable unless you + * use the default allocator. + */ +typedef void *(*HashAllocFunc) (Size request); + +/* + * HASHELEMENT is the private part of a hashtable entry. The caller's data + * follows the HASHELEMENT structure (on a MAXALIGN'd boundary). The hash key + * is expected to be at the start of the caller's hash entry data structure. + */ +typedef struct HASHELEMENT +{ + struct HASHELEMENT *link; /* link to next entry in same bucket */ + uint32 hashvalue; /* hash function result for this entry */ +} HASHELEMENT; + +/* Hash table header struct is an opaque type known only within dynahash.c */ +typedef struct HASHHDR HASHHDR; + +/* Hash table control struct is an opaque type known only within dynahash.c */ +typedef struct HTAB HTAB; + +/* Parameter data structure for hash_create */ +/* Only those fields indicated by hash_flags need be set */ +typedef struct HASHCTL +{ + /* Used if HASH_PARTITION flag is set: */ + long num_partitions; /* # partitions (must be power of 2) */ + /* Used if HASH_SEGMENT flag is set: */ + long ssize; /* segment size */ + /* Used if HASH_DIRSIZE flag is set: */ + long dsize; /* (initial) directory size */ + long max_dsize; /* limit to dsize if dir size is limited */ + /* Used if HASH_ELEM flag is set (which is now required): */ + Size keysize; /* hash key length in bytes */ + Size entrysize; /* total user element size in bytes */ + /* Used if HASH_FUNCTION flag is set: */ + HashValueFunc hash; /* hash function */ + /* Used if HASH_COMPARE flag is set: */ + HashCompareFunc match; /* key comparison function */ + /* Used if HASH_KEYCOPY flag is set: */ + HashCopyFunc keycopy; /* key copying function */ + /* Used if HASH_ALLOC flag is set: */ + HashAllocFunc alloc; /* memory allocator */ + /* Used if HASH_CONTEXT flag is set: */ + MemoryContext hcxt; /* memory context to use for allocations */ + /* Used if HASH_SHARED_MEM flag is set: */ + HASHHDR *hctl; /* location of header in shared mem */ +} HASHCTL; + +/* Flag bits for hash_create; most indicate which parameters are supplied */ +#define HASH_PARTITION 0x0001 /* Hashtable is used w/partitioned locking */ +#define HASH_SEGMENT 0x0002 /* Set segment size */ +#define HASH_DIRSIZE 0x0004 /* Set directory size (initial and max) */ +#define HASH_ELEM 0x0008 /* Set keysize and entrysize (now required!) */ +#define HASH_STRINGS 0x0010 /* Select support functions for string keys */ +#define HASH_BLOBS 0x0020 /* Select support functions for binary keys */ +#define HASH_FUNCTION 0x0040 /* Set user defined hash function */ +#define HASH_COMPARE 0x0080 /* Set user defined comparison function */ +#define HASH_KEYCOPY 0x0100 /* Set user defined key-copying function */ +#define HASH_ALLOC 0x0200 /* Set memory allocator */ +#define HASH_CONTEXT 0x0400 /* Set memory allocation context */ +#define HASH_SHARED_MEM 0x0800 /* Hashtable is in shared memory */ +#define HASH_ATTACH 0x1000 /* Do not initialize hctl */ +#define HASH_FIXED_SIZE 0x2000 /* Initial size is a hard limit */ + +/* max_dsize value to indicate expansible directory */ +#define NO_MAX_DSIZE (-1) + +/* hash_search operations */ +typedef enum +{ + HASH_FIND, + HASH_ENTER, + HASH_REMOVE, + HASH_ENTER_NULL +} HASHACTION; + +/* hash_seq status (should be considered an opaque type by callers) */ +typedef struct +{ + HTAB *hashp; + uint32 curBucket; /* index of current bucket */ + HASHELEMENT *curEntry; /* current entry in bucket */ +} HASH_SEQ_STATUS; + +/* + * prototypes for functions in dynahash.c + */ +extern HTAB *hash_create(const char *tabname, long nelem, + const HASHCTL *info, int flags); +extern void hash_destroy(HTAB *hashp); +extern void hash_stats(const char *where, HTAB *hashp); +extern void *hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, + bool *foundPtr); +extern uint32 get_hash_value(HTAB *hashp, const void *keyPtr); +extern void *hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, + uint32 hashvalue, HASHACTION action, + bool *foundPtr); +extern bool hash_update_hash_key(HTAB *hashp, void *existingEntry, + const void *newKeyPtr); +extern long hash_get_num_entries(HTAB *hashp); +extern void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp); +extern void *hash_seq_search(HASH_SEQ_STATUS *status); +extern void hash_seq_term(HASH_SEQ_STATUS *status); +extern void hash_freeze(HTAB *hashp); +extern Size hash_estimate_size(long num_entries, Size entrysize); +extern long hash_select_dirsize(long num_entries); +extern Size hash_get_shared_size(HASHCTL *info, int flags); +extern void AtEOXact_HashTables(bool isCommit); +extern void AtEOSubXact_HashTables(bool isCommit, int nestDepth); + +#endif /* HSEARCH_H */ diff --git a/src/include/utils/index_selfuncs.h b/src/include/utils/index_selfuncs.h new file mode 100644 index 0000000..6483522 --- /dev/null +++ b/src/include/utils/index_selfuncs.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * index_selfuncs.h + * Index cost estimation functions for standard index access methods. + * + * + * Note: this is split out of selfuncs.h mainly to avoid importing all of the + * planner's data structures into the non-planner parts of the index AMs. + * If you make it depend on anything besides access/amapi.h, that's likely + * a mistake. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/index_selfuncs.h + * + *------------------------------------------------------------------------- + */ +#ifndef INDEX_SELFUNCS_H +#define INDEX_SELFUNCS_H + +#include "access/amapi.h" + +/* Functions in selfuncs.c */ +extern void brincostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); +extern void btcostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); +extern void hashcostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); +extern void gistcostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); +extern void spgcostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); +extern void gincostestimate(struct PlannerInfo *root, + struct IndexPath *path, + double loop_count, + Cost *indexStartupCost, + Cost *indexTotalCost, + Selectivity *indexSelectivity, + double *indexCorrelation, + double *indexPages); + +#endif /* INDEX_SELFUNCS_H */ diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h new file mode 100644 index 0000000..3073c03 --- /dev/null +++ b/src/include/utils/inet.h @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------- + * + * inet.h + * Declarations for operations on INET datatypes. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/inet.h + * + *------------------------------------------------------------------------- + */ +#ifndef INET_H +#define INET_H + +#include "fmgr.h" + +/* + * This is the internal storage format for IP addresses + * (both INET and CIDR datatypes): + */ +typedef struct +{ + unsigned char family; /* PGSQL_AF_INET or PGSQL_AF_INET6 */ + unsigned char bits; /* number of bits in netmask */ + unsigned char ipaddr[16]; /* up to 128 bits of address */ +} inet_struct; + +/* + * We use these values for the "family" field. + * + * Referencing all of the non-AF_INET types to AF_INET lets us work on + * machines which may not have the appropriate address family (like + * inet6 addresses when AF_INET6 isn't present) but doesn't cause a + * dump/reload requirement. Pre-7.4 databases used AF_INET for the family + * type on disk. + */ +#define PGSQL_AF_INET (AF_INET + 0) +#define PGSQL_AF_INET6 (AF_INET + 1) + +/* + * Both INET and CIDR addresses are represented within Postgres as varlena + * objects, ie, there is a varlena header in front of the struct type + * depicted above. This struct depicts what we actually have in memory + * in "uncompressed" cases. Note that since the maximum data size is only + * 18 bytes, INET/CIDR will invariably be stored into tuples using the + * 1-byte-header varlena format. However, we have to be prepared to cope + * with the 4-byte-header format too, because various code may helpfully + * try to "decompress" 1-byte-header datums. + */ +typedef struct +{ + char vl_len_[4]; /* Do not touch this field directly! */ + inet_struct inet_data; +} inet; + +/* + * Access macros. We use VARDATA_ANY so that we can process short-header + * varlena values without detoasting them. This requires a trick: + * VARDATA_ANY assumes the varlena header is already filled in, which is + * not the case when constructing a new value (until SET_INET_VARSIZE is + * called, which we typically can't do till the end). Therefore, we + * always initialize the newly-allocated value to zeroes (using palloc0). + * A zero length word will look like the not-1-byte case to VARDATA_ANY, + * and so we correctly construct an uncompressed value. + * + * Note that ip_addrsize(), ip_maxbits(), and SET_INET_VARSIZE() require + * the family field to be set correctly. + */ +#define ip_family(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->family) + +#define ip_bits(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->bits) + +#define ip_addr(inetptr) \ + (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr) + +#define ip_addrsize(inetptr) \ + (ip_family(inetptr) == PGSQL_AF_INET ? 4 : 16) + +#define ip_maxbits(inetptr) \ + (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) + +#define SET_INET_VARSIZE(dst) \ + SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ + ip_addrsize(dst)) + + +/* + * This is the internal storage format for MAC addresses: + */ +typedef struct macaddr +{ + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; +} macaddr; + +/* + * This is the internal storage format for MAC8 addresses: + */ +typedef struct macaddr8 +{ + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; + unsigned char g; + unsigned char h; +} macaddr8; + +/* + * fmgr interface macros + */ +#define DatumGetInetPP(X) ((inet *) PG_DETOAST_DATUM_PACKED(X)) +#define InetPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n)) +#define PG_RETURN_INET_P(x) return InetPGetDatum(x) +/* obsolescent variants */ +#define DatumGetInetP(X) ((inet *) PG_DETOAST_DATUM(X)) +#define PG_GETARG_INET_P(n) DatumGetInetP(PG_GETARG_DATUM(n)) + +/* macaddr is a fixed-length pass-by-reference datatype */ +#define DatumGetMacaddrP(X) ((macaddr *) DatumGetPointer(X)) +#define MacaddrPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n)) +#define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x) + +/* macaddr8 is a fixed-length pass-by-reference datatype */ +#define DatumGetMacaddr8P(X) ((macaddr8 *) DatumGetPointer(X)) +#define Macaddr8PGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_MACADDR8_P(n) DatumGetMacaddr8P(PG_GETARG_DATUM(n)) +#define PG_RETURN_MACADDR8_P(x) return Macaddr8PGetDatum(x) + +/* + * Support functions in network.c + */ +extern inet *cidr_set_masklen_internal(const inet *src, int bits); +extern int bitncmp(const unsigned char *l, const unsigned char *r, int n); +extern int bitncommon(const unsigned char *l, const unsigned char *r, int n); + +#endif /* INET_H */ diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h new file mode 100644 index 0000000..0e0323b --- /dev/null +++ b/src/include/utils/inval.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + * + * inval.h + * POSTGRES cache invalidation dispatcher definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/inval.h + * + *------------------------------------------------------------------------- + */ +#ifndef INVAL_H +#define INVAL_H + +#include "access/htup.h" +#include "storage/relfilenode.h" +#include "utils/relcache.h" + +extern PGDLLIMPORT int debug_discard_caches; + +typedef void (*SyscacheCallbackFunction) (Datum arg, int cacheid, uint32 hashvalue); +typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid); + + +extern void AcceptInvalidationMessages(void); + +extern void AtEOXact_Inval(bool isCommit); + +extern void AtEOSubXact_Inval(bool isCommit); + +extern void PostPrepare_Inval(void); + +extern void CommandEndInvalidationMessages(void); + +extern void CacheInvalidateHeapTuple(Relation relation, + HeapTuple tuple, + HeapTuple newtuple); + +extern void CacheInvalidateCatalog(Oid catalogId); + +extern void CacheInvalidateRelcache(Relation relation); + +extern void CacheInvalidateRelcacheAll(void); + +extern void CacheInvalidateRelcacheByTuple(HeapTuple classTuple); + +extern void CacheInvalidateRelcacheByRelid(Oid relid); + +extern void CacheInvalidateSmgr(RelFileNodeBackend rnode); + +extern void CacheInvalidateRelmap(Oid databaseId); + +extern void CacheRegisterSyscacheCallback(int cacheid, + SyscacheCallbackFunction func, + Datum arg); + +extern void CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, + Datum arg); + +extern void CallSyscacheCallbacks(int cacheid, uint32 hashvalue); + +extern void InvalidateSystemCaches(void); +extern void InvalidateSystemCachesExtended(bool debug_discard); + +extern void LogLogicalInvalidations(void); +#endif /* INVAL_H */ diff --git a/src/include/utils/json.h b/src/include/utils/json.h new file mode 100644 index 0000000..8a84a0c --- /dev/null +++ b/src/include/utils/json.h @@ -0,0 +1,24 @@ +/*------------------------------------------------------------------------- + * + * json.h + * Declarations for JSON data type support. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/json.h + * + *------------------------------------------------------------------------- + */ + +#ifndef JSON_H +#define JSON_H + +#include "lib/stringinfo.h" + +/* functions in json.c */ +extern void escape_json(StringInfo buf, const char *str); +extern char *JsonEncodeDateTime(char *buf, Datum value, Oid typid, + const int *tzp); + +#endif /* JSON_H */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h new file mode 100644 index 0000000..4cbe6ed --- /dev/null +++ b/src/include/utils/jsonb.h @@ -0,0 +1,415 @@ +/*------------------------------------------------------------------------- + * + * jsonb.h + * Declarations for jsonb data type support. + * + * Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/utils/jsonb.h + * + *------------------------------------------------------------------------- + */ +#ifndef __JSONB_H__ +#define __JSONB_H__ + +#include "lib/stringinfo.h" +#include "utils/array.h" +#include "utils/numeric.h" + +/* Tokens used when sequentially processing a jsonb value */ +typedef enum +{ + WJB_DONE, + WJB_KEY, + WJB_VALUE, + WJB_ELEM, + WJB_BEGIN_ARRAY, + WJB_END_ARRAY, + WJB_BEGIN_OBJECT, + WJB_END_OBJECT +} JsonbIteratorToken; + +/* Strategy numbers for GIN index opclasses */ +#define JsonbContainsStrategyNumber 7 +#define JsonbExistsStrategyNumber 9 +#define JsonbExistsAnyStrategyNumber 10 +#define JsonbExistsAllStrategyNumber 11 +#define JsonbJsonpathExistsStrategyNumber 15 +#define JsonbJsonpathPredicateStrategyNumber 16 + + +/* + * In the standard jsonb_ops GIN opclass for jsonb, we choose to index both + * keys and values. The storage format is text. The first byte of the text + * string distinguishes whether this is a key (always a string), null value, + * boolean value, numeric value, or string value. However, array elements + * that are strings are marked as though they were keys; this imprecision + * supports the definition of the "exists" operator, which treats array + * elements like keys. The remainder of the text string is empty for a null + * value, "t" or "f" for a boolean value, a normalized print representation of + * a numeric value, or the text of a string value. However, if the length of + * this text representation would exceed JGIN_MAXLENGTH bytes, we instead hash + * the text representation and store an 8-hex-digit representation of the + * uint32 hash value, marking the prefix byte with an additional bit to + * distinguish that this has happened. Hashing long strings saves space and + * ensures that we won't overrun the maximum entry length for a GIN index. + * (But JGIN_MAXLENGTH is quite a bit shorter than GIN's limit. It's chosen + * to ensure that the on-disk text datum will have a short varlena header.) + * Note that when any hashed item appears in a query, we must recheck index + * matches against the heap tuple; currently, this costs nothing because we + * must always recheck for other reasons. + */ +#define JGINFLAG_KEY 0x01 /* key (or string array element) */ +#define JGINFLAG_NULL 0x02 /* null value */ +#define JGINFLAG_BOOL 0x03 /* boolean value */ +#define JGINFLAG_NUM 0x04 /* numeric value */ +#define JGINFLAG_STR 0x05 /* string value (if not an array element) */ +#define JGINFLAG_HASHED 0x10 /* OR'd into flag if value was hashed */ +#define JGIN_MAXLENGTH 125 /* max length of text part before hashing */ + +/* Convenience macros */ +#define DatumGetJsonbP(d) ((Jsonb *) PG_DETOAST_DATUM(d)) +#define DatumGetJsonbPCopy(d) ((Jsonb *) PG_DETOAST_DATUM_COPY(d)) +#define JsonbPGetDatum(p) PointerGetDatum(p) +#define PG_GETARG_JSONB_P(x) DatumGetJsonbP(PG_GETARG_DATUM(x)) +#define PG_GETARG_JSONB_P_COPY(x) DatumGetJsonbPCopy(PG_GETARG_DATUM(x)) +#define PG_RETURN_JSONB_P(x) PG_RETURN_POINTER(x) + +typedef struct JsonbPair JsonbPair; +typedef struct JsonbValue JsonbValue; + +/* + * Jsonbs are varlena objects, so must meet the varlena convention that the + * first int32 of the object contains the total object size in bytes. Be sure + * to use VARSIZE() and SET_VARSIZE() to access it, though! + * + * Jsonb is the on-disk representation, in contrast to the in-memory JsonbValue + * representation. Often, JsonbValues are just shims through which a Jsonb + * buffer is accessed, but they can also be deep copied and passed around. + * + * Jsonb is a tree structure. Each node in the tree consists of a JEntry + * header and a variable-length content (possibly of zero size). The JEntry + * header indicates what kind of a node it is, e.g. a string or an array, + * and provides the length of its variable-length portion. + * + * The JEntry and the content of a node are not stored physically together. + * Instead, the container array or object has an array that holds the JEntrys + * of all the child nodes, followed by their variable-length portions. + * + * The root node is an exception; it has no parent array or object that could + * hold its JEntry. Hence, no JEntry header is stored for the root node. It + * is implicitly known that the root node must be an array or an object, + * so we can get away without the type indicator as long as we can distinguish + * the two. For that purpose, both an array and an object begin with a uint32 + * header field, which contains an JB_FOBJECT or JB_FARRAY flag. When a naked + * scalar value needs to be stored as a Jsonb value, what we actually store is + * an array with one element, with the flags in the array's header field set + * to JB_FSCALAR | JB_FARRAY. + * + * Overall, the Jsonb struct requires 4-bytes alignment. Within the struct, + * the variable-length portion of some node types is aligned to a 4-byte + * boundary, while others are not. When alignment is needed, the padding is + * in the beginning of the node that requires it. For example, if a numeric + * node is stored after a string node, so that the numeric node begins at + * offset 3, the variable-length portion of the numeric node will begin with + * one padding byte so that the actual numeric data is 4-byte aligned. + */ + +/* + * JEntry format. + * + * The least significant 28 bits store either the data length of the entry, + * or its end+1 offset from the start of the variable-length portion of the + * containing object. The next three bits store the type of the entry, and + * the high-order bit tells whether the least significant bits store a length + * or an offset. + * + * The reason for the offset-or-length complication is to compromise between + * access speed and data compressibility. In the initial design each JEntry + * always stored an offset, but this resulted in JEntry arrays with horrible + * compressibility properties, so that TOAST compression of a JSONB did not + * work well. Storing only lengths would greatly improve compressibility, + * but it makes random access into large arrays expensive (O(N) not O(1)). + * So what we do is store an offset in every JB_OFFSET_STRIDE'th JEntry and + * a length in the rest. This results in reasonably compressible data (as + * long as the stride isn't too small). We may have to examine as many as + * JB_OFFSET_STRIDE JEntrys in order to find out the offset or length of any + * given item, but that's still O(1) no matter how large the container is. + * + * We could avoid eating a flag bit for this purpose if we were to store + * the stride in the container header, or if we were willing to treat the + * stride as an unchangeable constant. Neither of those options is very + * attractive though. + */ +typedef uint32 JEntry; + +#define JENTRY_OFFLENMASK 0x0FFFFFFF +#define JENTRY_TYPEMASK 0x70000000 +#define JENTRY_HAS_OFF 0x80000000 + +/* values stored in the type bits */ +#define JENTRY_ISSTRING 0x00000000 +#define JENTRY_ISNUMERIC 0x10000000 +#define JENTRY_ISBOOL_FALSE 0x20000000 +#define JENTRY_ISBOOL_TRUE 0x30000000 +#define JENTRY_ISNULL 0x40000000 +#define JENTRY_ISCONTAINER 0x50000000 /* array or object */ + +/* Access macros. Note possible multiple evaluations */ +#define JBE_OFFLENFLD(je_) ((je_) & JENTRY_OFFLENMASK) +#define JBE_HAS_OFF(je_) (((je_) & JENTRY_HAS_OFF) != 0) +#define JBE_ISSTRING(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISSTRING) +#define JBE_ISNUMERIC(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISNUMERIC) +#define JBE_ISCONTAINER(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISCONTAINER) +#define JBE_ISNULL(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISNULL) +#define JBE_ISBOOL_TRUE(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISBOOL_TRUE) +#define JBE_ISBOOL_FALSE(je_) (((je_) & JENTRY_TYPEMASK) == JENTRY_ISBOOL_FALSE) +#define JBE_ISBOOL(je_) (JBE_ISBOOL_TRUE(je_) || JBE_ISBOOL_FALSE(je_)) + +/* Macro for advancing an offset variable to the next JEntry */ +#define JBE_ADVANCE_OFFSET(offset, je) \ + do { \ + JEntry je_ = (je); \ + if (JBE_HAS_OFF(je_)) \ + (offset) = JBE_OFFLENFLD(je_); \ + else \ + (offset) += JBE_OFFLENFLD(je_); \ + } while(0) + +/* + * We store an offset, not a length, every JB_OFFSET_STRIDE children. + * Caution: this macro should only be referenced when creating a JSONB + * value. When examining an existing value, pay attention to the HAS_OFF + * bits instead. This allows changes in the offset-placement heuristic + * without breaking on-disk compatibility. + */ +#define JB_OFFSET_STRIDE 32 + +/* + * A jsonb array or object node, within a Jsonb Datum. + * + * An array has one child for each element, stored in array order. + * + * An object has two children for each key/value pair. The keys all appear + * first, in key sort order; then the values appear, in an order matching the + * key order. This arrangement keeps the keys compact in memory, making a + * search for a particular key more cache-friendly. + */ +typedef struct JsonbContainer +{ + uint32 header; /* number of elements or key/value pairs, and + * flags */ + JEntry children[FLEXIBLE_ARRAY_MEMBER]; + + /* the data for each child node follows. */ +} JsonbContainer; + +/* flags for the header-field in JsonbContainer */ +#define JB_CMASK 0x0FFFFFFF /* mask for count field */ +#define JB_FSCALAR 0x10000000 /* flag bits */ +#define JB_FOBJECT 0x20000000 +#define JB_FARRAY 0x40000000 + +/* convenience macros for accessing a JsonbContainer struct */ +#define JsonContainerSize(jc) ((jc)->header & JB_CMASK) +#define JsonContainerIsScalar(jc) (((jc)->header & JB_FSCALAR) != 0) +#define JsonContainerIsObject(jc) (((jc)->header & JB_FOBJECT) != 0) +#define JsonContainerIsArray(jc) (((jc)->header & JB_FARRAY) != 0) + +/* The top-level on-disk format for a jsonb datum. */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + JsonbContainer root; +} Jsonb; + +/* convenience macros for accessing the root container in a Jsonb datum */ +#define JB_ROOT_COUNT(jbp_) (*(uint32 *) VARDATA(jbp_) & JB_CMASK) +#define JB_ROOT_IS_SCALAR(jbp_) ((*(uint32 *) VARDATA(jbp_) & JB_FSCALAR) != 0) +#define JB_ROOT_IS_OBJECT(jbp_) ((*(uint32 *) VARDATA(jbp_) & JB_FOBJECT) != 0) +#define JB_ROOT_IS_ARRAY(jbp_) ((*(uint32 *) VARDATA(jbp_) & JB_FARRAY) != 0) + + +enum jbvType +{ + /* Scalar types */ + jbvNull = 0x0, + jbvString, + jbvNumeric, + jbvBool, + /* Composite types */ + jbvArray = 0x10, + jbvObject, + /* Binary (i.e. struct Jsonb) jbvArray/jbvObject */ + jbvBinary, + + /* + * Virtual types. + * + * These types are used only for in-memory JSON processing and serialized + * into JSON strings when outputted to json/jsonb. + */ + jbvDatetime = 0x20, +}; + +/* + * JsonbValue: In-memory representation of Jsonb. This is a convenient + * deserialized representation, that can easily support using the "val" + * union across underlying types during manipulation. The Jsonb on-disk + * representation has various alignment considerations. + */ +struct JsonbValue +{ + enum jbvType type; /* Influences sort order */ + + union + { + Numeric numeric; + bool boolean; + struct + { + int len; + char *val; /* Not necessarily null-terminated */ + } string; /* String primitive type */ + + struct + { + int nElems; + JsonbValue *elems; + bool rawScalar; /* Top-level "raw scalar" array? */ + } array; /* Array container type */ + + struct + { + int nPairs; /* 1 pair, 2 elements */ + JsonbPair *pairs; + } object; /* Associative container type */ + + struct + { + int len; + JsonbContainer *data; + } binary; /* Array or object, in on-disk format */ + + struct + { + Datum value; + Oid typid; + int32 typmod; + int tz; /* Numeric time zone, in seconds, for + * TimestampTz data type */ + } datetime; + } val; +}; + +#define IsAJsonbScalar(jsonbval) (((jsonbval)->type >= jbvNull && \ + (jsonbval)->type <= jbvBool) || \ + (jsonbval)->type == jbvDatetime) + +/* + * Key/value pair within an Object. + * + * This struct type is only used briefly while constructing a Jsonb; it is + * *not* the on-disk representation. + * + * Pairs with duplicate keys are de-duplicated. We store the originally + * observed pair ordering for the purpose of removing duplicates in a + * well-defined way (which is "last observed wins"). + */ +struct JsonbPair +{ + JsonbValue key; /* Must be a jbvString */ + JsonbValue value; /* May be of any type */ + uint32 order; /* Pair's index in original sequence */ +}; + +/* Conversion state used when parsing Jsonb from text, or for type coercion */ +typedef struct JsonbParseState +{ + JsonbValue contVal; + Size size; + struct JsonbParseState *next; +} JsonbParseState; + +/* + * JsonbIterator holds details of the type for each iteration. It also stores a + * Jsonb varlena buffer, which can be directly accessed in some contexts. + */ +typedef enum +{ + JBI_ARRAY_START, + JBI_ARRAY_ELEM, + JBI_OBJECT_START, + JBI_OBJECT_KEY, + JBI_OBJECT_VALUE +} JsonbIterState; + +typedef struct JsonbIterator +{ + /* Container being iterated */ + JsonbContainer *container; + uint32 nElems; /* Number of elements in children array (will + * be nPairs for objects) */ + bool isScalar; /* Pseudo-array scalar value? */ + JEntry *children; /* JEntrys for child nodes */ + /* Data proper. This points to the beginning of the variable-length data */ + char *dataProper; + + /* Current item in buffer (up to nElems) */ + int curIndex; + + /* Data offset corresponding to current item */ + uint32 curDataOffset; + + /* + * If the container is an object, we want to return keys and values + * alternately; so curDataOffset points to the current key, and + * curValueOffset points to the current value. + */ + uint32 curValueOffset; + + /* Private state */ + JsonbIterState state; + + struct JsonbIterator *parent; +} JsonbIterator; + + +/* Support functions */ +extern uint32 getJsonbOffset(const JsonbContainer *jc, int index); +extern uint32 getJsonbLength(const JsonbContainer *jc, int index); +extern int compareJsonbContainers(JsonbContainer *a, JsonbContainer *b); +extern JsonbValue *findJsonbValueFromContainer(JsonbContainer *sheader, + uint32 flags, + JsonbValue *key); +extern JsonbValue *getKeyJsonValueFromContainer(JsonbContainer *container, + const char *keyVal, int keyLen, + JsonbValue *res); +extern JsonbValue *getIthJsonbValueFromContainer(JsonbContainer *sheader, + uint32 i); +extern JsonbValue *pushJsonbValue(JsonbParseState **pstate, + JsonbIteratorToken seq, JsonbValue *jbval); +extern JsonbIterator *JsonbIteratorInit(JsonbContainer *container); +extern JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, + bool skipNested); +extern void JsonbToJsonbValue(Jsonb *jsonb, JsonbValue *val); +extern Jsonb *JsonbValueToJsonb(JsonbValue *val); +extern bool JsonbDeepContains(JsonbIterator **val, + JsonbIterator **mContained); +extern void JsonbHashScalarValue(const JsonbValue *scalarVal, uint32 *hash); +extern void JsonbHashScalarValueExtended(const JsonbValue *scalarVal, + uint64 *hash, uint64 seed); + +/* jsonb.c support functions */ +extern char *JsonbToCString(StringInfo out, JsonbContainer *in, + int estimated_len); +extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in, + int estimated_len); +extern bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res); +extern const char *JsonbTypeName(JsonbValue *jb); + +extern Datum jsonb_set_element(Jsonb *jb, Datum *path, int path_len, + JsonbValue *newval); +extern Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath, + bool *isnull, bool as_text); +#endif /* __JSONB_H__ */ diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h new file mode 100644 index 0000000..865b2ff --- /dev/null +++ b/src/include/utils/jsonfuncs.h @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * jsonfuncs.h + * Functions to process JSON data types. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/jsonfuncs.h + * + *------------------------------------------------------------------------- + */ + +#ifndef JSONFUNCS_H +#define JSONFUNCS_H + +#include "common/jsonapi.h" +#include "utils/jsonb.h" + +/* + * Flag types for iterate_json(b)_values to specify what elements from a + * json(b) document we want to iterate. + */ +typedef enum JsonToIndex +{ + jtiKey = 0x01, + jtiString = 0x02, + jtiNumeric = 0x04, + jtiBool = 0x08, + jtiAll = jtiKey | jtiString | jtiNumeric | jtiBool +} JsonToIndex; + +/* an action that will be applied to each value in iterate_json(b)_values functions */ +typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, int elem_len); + +/* an action that will be applied to each value in transform_json(b)_values functions */ +typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len); + +/* build a JsonLexContext from a text datum */ +extern JsonLexContext *makeJsonLexContext(text *json, bool need_escapes); + +/* try to parse json, and ereport(ERROR) on failure */ +extern void pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem); + +/* report an error during json lexing or parsing */ +extern void json_ereport_error(JsonParseErrorType error, JsonLexContext *lex); + +extern uint32 parse_jsonb_index_flags(Jsonb *jb); +extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, + JsonIterateStringValuesAction action); +extern void iterate_json_values(text *json, uint32 flags, void *action_state, + JsonIterateStringValuesAction action); +extern Jsonb *transform_jsonb_string_values(Jsonb *jsonb, void *action_state, + JsonTransformStringValuesAction transform_action); +extern text *transform_json_string_values(text *json, void *action_state, + JsonTransformStringValuesAction transform_action); + +#endif diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h new file mode 100644 index 0000000..cd0b5d5 --- /dev/null +++ b/src/include/utils/jsonpath.h @@ -0,0 +1,251 @@ +/*------------------------------------------------------------------------- + * + * jsonpath.h + * Definitions for jsonpath datatype + * + * Copyright (c) 2019-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/include/utils/jsonpath.h + * + *------------------------------------------------------------------------- + */ + +#ifndef JSONPATH_H +#define JSONPATH_H + +#include "fmgr.h" +#include "nodes/pg_list.h" +#include "utils/jsonb.h" + +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint32 header; /* version and flags (see below) */ + char data[FLEXIBLE_ARRAY_MEMBER]; +} JsonPath; + +#define JSONPATH_VERSION (0x01) +#define JSONPATH_LAX (0x80000000) +#define JSONPATH_HDRSZ (offsetof(JsonPath, data)) + +#define DatumGetJsonPathP(d) ((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM(d))) +#define DatumGetJsonPathPCopy(d) ((JsonPath *) DatumGetPointer(PG_DETOAST_DATUM_COPY(d))) +#define PG_GETARG_JSONPATH_P(x) DatumGetJsonPathP(PG_GETARG_DATUM(x)) +#define PG_GETARG_JSONPATH_P_COPY(x) DatumGetJsonPathPCopy(PG_GETARG_DATUM(x)) +#define PG_RETURN_JSONPATH_P(p) PG_RETURN_POINTER(p) + +#define jspIsScalar(type) ((type) >= jpiNull && (type) <= jpiBool) + +/* + * All node's type of jsonpath expression + */ +typedef enum JsonPathItemType +{ + jpiNull = jbvNull, /* NULL literal */ + jpiString = jbvString, /* string literal */ + jpiNumeric = jbvNumeric, /* numeric literal */ + jpiBool = jbvBool, /* boolean literal: TRUE or FALSE */ + jpiAnd, /* predicate && predicate */ + jpiOr, /* predicate || predicate */ + jpiNot, /* ! predicate */ + jpiIsUnknown, /* (predicate) IS UNKNOWN */ + jpiEqual, /* expr == expr */ + jpiNotEqual, /* expr != expr */ + jpiLess, /* expr < expr */ + jpiGreater, /* expr > expr */ + jpiLessOrEqual, /* expr <= expr */ + jpiGreaterOrEqual, /* expr >= expr */ + jpiAdd, /* expr + expr */ + jpiSub, /* expr - expr */ + jpiMul, /* expr * expr */ + jpiDiv, /* expr / expr */ + jpiMod, /* expr % expr */ + jpiPlus, /* + expr */ + jpiMinus, /* - expr */ + jpiAnyArray, /* [*] */ + jpiAnyKey, /* .* */ + jpiIndexArray, /* [subscript, ...] */ + jpiAny, /* .** */ + jpiKey, /* .key */ + jpiCurrent, /* @ */ + jpiRoot, /* $ */ + jpiVariable, /* $variable */ + jpiFilter, /* ? (predicate) */ + jpiExists, /* EXISTS (expr) predicate */ + jpiType, /* .type() item method */ + jpiSize, /* .size() item method */ + jpiAbs, /* .abs() item method */ + jpiFloor, /* .floor() item method */ + jpiCeiling, /* .ceiling() item method */ + jpiDouble, /* .double() item method */ + jpiDatetime, /* .datetime() item method */ + jpiKeyValue, /* .keyvalue() item method */ + jpiSubscript, /* array subscript: 'expr' or 'expr TO expr' */ + jpiLast, /* LAST array subscript */ + jpiStartsWith, /* STARTS WITH predicate */ + jpiLikeRegex, /* LIKE_REGEX predicate */ +} JsonPathItemType; + +/* XQuery regex mode flags for LIKE_REGEX predicate */ +#define JSP_REGEX_ICASE 0x01 /* i flag, case insensitive */ +#define JSP_REGEX_DOTALL 0x02 /* s flag, dot matches newline */ +#define JSP_REGEX_MLINE 0x04 /* m flag, ^/$ match at newlines */ +#define JSP_REGEX_WSPACE 0x08 /* x flag, ignore whitespace in pattern */ +#define JSP_REGEX_QUOTE 0x10 /* q flag, no special characters */ + +/* + * Support functions to parse/construct binary value. + * Unlike many other representation of expression the first/main + * node is not an operation but left operand of expression. That + * allows to implement cheap follow-path descending in jsonb + * structure and then execute operator with right operand + */ + +typedef struct JsonPathItem +{ + JsonPathItemType type; + + /* position form base to next node */ + int32 nextPos; + + /* + * pointer into JsonPath value to current node, all positions of current + * are relative to this base + */ + char *base; + + union + { + /* classic operator with two operands: and, or etc */ + struct + { + int32 left; + int32 right; + } args; + + /* any unary operation */ + int32 arg; + + /* storage for jpiIndexArray: indexes of array */ + struct + { + int32 nelems; + struct + { + int32 from; + int32 to; + } *elems; + } array; + + /* jpiAny: levels */ + struct + { + uint32 first; + uint32 last; + } anybounds; + + struct + { + char *data; /* for bool, numeric and string/key */ + int32 datalen; /* filled only for string/key */ + } value; + + struct + { + int32 expr; + char *pattern; + int32 patternlen; + uint32 flags; + } like_regex; + } content; +} JsonPathItem; + +#define jspHasNext(jsp) ((jsp)->nextPos > 0) + +extern void jspInit(JsonPathItem *v, JsonPath *js); +extern void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos); +extern bool jspGetNext(JsonPathItem *v, JsonPathItem *a); +extern void jspGetArg(JsonPathItem *v, JsonPathItem *a); +extern void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a); +extern void jspGetRightArg(JsonPathItem *v, JsonPathItem *a); +extern Numeric jspGetNumeric(JsonPathItem *v); +extern bool jspGetBool(JsonPathItem *v); +extern char *jspGetString(JsonPathItem *v, int32 *len); +extern bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, + JsonPathItem *to, int i); + +extern const char *jspOperationName(JsonPathItemType type); + +/* + * Parsing support data structures. + */ + +typedef struct JsonPathParseItem JsonPathParseItem; + +struct JsonPathParseItem +{ + JsonPathItemType type; + JsonPathParseItem *next; /* next in path */ + + union + { + + /* classic operator with two operands: and, or etc */ + struct + { + JsonPathParseItem *left; + JsonPathParseItem *right; + } args; + + /* any unary operation */ + JsonPathParseItem *arg; + + /* storage for jpiIndexArray: indexes of array */ + struct + { + int nelems; + struct + { + JsonPathParseItem *from; + JsonPathParseItem *to; + } *elems; + } array; + + /* jpiAny: levels */ + struct + { + uint32 first; + uint32 last; + } anybounds; + + struct + { + JsonPathParseItem *expr; + char *pattern; /* could not be not null-terminated */ + uint32 patternlen; + uint32 flags; + } like_regex; + + /* scalars */ + Numeric numeric; + bool boolean; + struct + { + uint32 len; + char *val; /* could not be not null-terminated */ + } string; + } value; +}; + +typedef struct JsonPathParseResult +{ + JsonPathParseItem *expr; + bool lax; +} JsonPathParseResult; + +extern JsonPathParseResult *parsejsonpath(const char *str, int len); + +extern int jspConvertRegexFlags(uint32 xflags); + +#endif diff --git a/src/include/utils/logtape.h b/src/include/utils/logtape.h new file mode 100644 index 0000000..8c742ac --- /dev/null +++ b/src/include/utils/logtape.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * logtape.h + * Management of "logical tapes" within temporary files. + * + * See logtape.c for explanations. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/logtape.h + * + *------------------------------------------------------------------------- + */ + +#ifndef LOGTAPE_H +#define LOGTAPE_H + +#include "storage/sharedfileset.h" + +/* + * LogicalTapeSet and LogicalTape are opaque types whose details are not + * known outside logtape.c. + */ +typedef struct LogicalTapeSet LogicalTapeSet; +typedef struct LogicalTape LogicalTape; + + +/* + * The approach tuplesort.c takes to parallel external sorts is that workers, + * whose state is almost the same as independent serial sorts, are made to + * produce a final materialized tape of sorted output in all cases. This is + * frozen, just like any case requiring a final materialized tape. However, + * there is one difference, which is that freezing will also export an + * underlying shared fileset BufFile for sharing. Freezing produces TapeShare + * metadata for the worker when this happens, which is passed along through + * shared memory to leader. + * + * The leader process can then pass an array of TapeShare metadata (one per + * worker participant) to LogicalTapeSetCreate(), alongside a handle to a + * shared fileset, which is sufficient to construct a new logical tapeset that + * consists of each of the tapes materialized by workers. + * + * Note that while logtape.c does create an empty leader tape at the end of the + * tapeset in the leader case, it can never be written to due to a restriction + * in the shared buffile infrastructure. + */ +typedef struct TapeShare +{ + /* + * Currently, all the leader process needs is the location of the + * materialized tape's first block. + */ + long firstblocknumber; +} TapeShare; + +/* + * prototypes for functions in logtape.c + */ + +extern LogicalTapeSet *LogicalTapeSetCreate(bool preallocate, + SharedFileSet *fileset, int worker); +extern void LogicalTapeClose(LogicalTape *lt); +extern void LogicalTapeSetClose(LogicalTapeSet *lts); +extern LogicalTape *LogicalTapeCreate(LogicalTapeSet *lts); +extern LogicalTape *LogicalTapeImport(LogicalTapeSet *lts, int worker, TapeShare *shared); +extern void LogicalTapeSetForgetFreeSpace(LogicalTapeSet *lts); +extern size_t LogicalTapeRead(LogicalTape *lt, void *ptr, size_t size); +extern void LogicalTapeWrite(LogicalTape *lt, void *ptr, size_t size); +extern void LogicalTapeRewindForRead(LogicalTape *lt, size_t buffer_size); +extern void LogicalTapeFreeze(LogicalTape *lt, TapeShare *share); +extern size_t LogicalTapeBackspace(LogicalTape *lt, size_t size); +extern void LogicalTapeSeek(LogicalTape *lt, long blocknum, int offset); +extern void LogicalTapeTell(LogicalTape *lt, long *blocknum, int *offset); +extern long LogicalTapeSetBlocks(LogicalTapeSet *lts); + +#endif /* LOGTAPE_H */ diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h new file mode 100644 index 0000000..b8dd27d --- /dev/null +++ b/src/include/utils/lsyscache.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- + * + * lsyscache.h + * Convenience routines for common queries in the system catalog cache. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/lsyscache.h + * + *------------------------------------------------------------------------- + */ +#ifndef LSYSCACHE_H +#define LSYSCACHE_H + +#include "access/attnum.h" +#include "access/htup.h" +#include "nodes/pg_list.h" + +/* avoid including subscripting.h here */ +struct SubscriptRoutines; + +/* Result list element for get_op_btree_interpretation */ +typedef struct OpBtreeInterpretation +{ + Oid opfamily_id; /* btree opfamily containing operator */ + int strategy; /* its strategy number */ + Oid oplefttype; /* declared left input datatype */ + Oid oprighttype; /* declared right input datatype */ +} OpBtreeInterpretation; + +/* I/O function selector for get_type_io_data */ +typedef enum IOFuncSelector +{ + IOFunc_input, + IOFunc_output, + IOFunc_receive, + IOFunc_send +} IOFuncSelector; + +/* Flag bits for get_attstatsslot */ +#define ATTSTATSSLOT_VALUES 0x01 +#define ATTSTATSSLOT_NUMBERS 0x02 + +/* Result struct for get_attstatsslot */ +typedef struct AttStatsSlot +{ + /* Always filled: */ + Oid staop; /* Actual staop for the found slot */ + Oid stacoll; /* Actual collation for the found slot */ + /* Filled if ATTSTATSSLOT_VALUES is specified: */ + Oid valuetype; /* Actual datatype of the values */ + Datum *values; /* slot's "values" array, or NULL if none */ + int nvalues; /* length of values[], or 0 */ + /* Filled if ATTSTATSSLOT_NUMBERS is specified: */ + float4 *numbers; /* slot's "numbers" array, or NULL if none */ + int nnumbers; /* length of numbers[], or 0 */ + + /* Remaining fields are private to get_attstatsslot/free_attstatsslot */ + void *values_arr; /* palloc'd values array, if any */ + void *numbers_arr; /* palloc'd numbers array, if any */ +} AttStatsSlot; + +/* Hook for plugins to get control in get_attavgwidth() */ +typedef int32 (*get_attavgwidth_hook_type) (Oid relid, AttrNumber attnum); +extern PGDLLIMPORT get_attavgwidth_hook_type get_attavgwidth_hook; + +extern bool op_in_opfamily(Oid opno, Oid opfamily); +extern int get_op_opfamily_strategy(Oid opno, Oid opfamily); +extern Oid get_op_opfamily_sortfamily(Oid opno, Oid opfamily); +extern void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, + int *strategy, + Oid *lefttype, + Oid *righttype); +extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, + int16 strategy); +extern bool get_ordering_op_properties(Oid opno, + Oid *opfamily, Oid *opcintype, int16 *strategy); +extern Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse); +extern Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type); +extern List *get_mergejoin_opfamilies(Oid opno); +extern bool get_compatible_hash_operators(Oid opno, + Oid *lhs_opno, Oid *rhs_opno); +extern bool get_op_hash_functions(Oid opno, + RegProcedure *lhs_procno, RegProcedure *rhs_procno); +extern List *get_op_btree_interpretation(Oid opno); +extern bool equality_ops_are_compatible(Oid opno1, Oid opno2); +extern bool comparison_ops_are_compatible(Oid opno1, Oid opno2); +extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, + int16 procnum); +extern char *get_attname(Oid relid, AttrNumber attnum, bool missing_ok); +extern AttrNumber get_attnum(Oid relid, const char *attname); +extern int get_attstattarget(Oid relid, AttrNumber attnum); +extern char get_attgenerated(Oid relid, AttrNumber attnum); +extern Oid get_atttype(Oid relid, AttrNumber attnum); +extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod, Oid *collid); +extern Datum get_attoptions(Oid relid, int16 attnum); +extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok); +extern char *get_collation_name(Oid colloid); +extern bool get_collation_isdeterministic(Oid colloid); +extern char *get_constraint_name(Oid conoid); +extern Oid get_constraint_index(Oid conoid); +extern char *get_language_name(Oid langoid, bool missing_ok); +extern Oid get_opclass_family(Oid opclass); +extern Oid get_opclass_input_type(Oid opclass); +extern bool get_opclass_opfamily_and_input_type(Oid opclass, + Oid *opfamily, Oid *opcintype); +extern RegProcedure get_opcode(Oid opno); +extern char *get_opname(Oid opno); +extern Oid get_op_rettype(Oid opno); +extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype); +extern bool op_mergejoinable(Oid opno, Oid inputtype); +extern bool op_hashjoinable(Oid opno, Oid inputtype); +extern bool op_strict(Oid opno); +extern char op_volatile(Oid opno); +extern Oid get_commutator(Oid opno); +extern Oid get_negator(Oid opno); +extern RegProcedure get_oprrest(Oid opno); +extern RegProcedure get_oprjoin(Oid opno); +extern char *get_func_name(Oid funcid); +extern Oid get_func_namespace(Oid funcid); +extern Oid get_func_rettype(Oid funcid); +extern int get_func_nargs(Oid funcid); +extern Oid get_func_signature(Oid funcid, Oid **argtypes, int *nargs); +extern Oid get_func_variadictype(Oid funcid); +extern bool get_func_retset(Oid funcid); +extern bool func_strict(Oid funcid); +extern char func_volatile(Oid funcid); +extern char func_parallel(Oid funcid); +extern char get_func_prokind(Oid funcid); +extern bool get_func_leakproof(Oid funcid); +extern RegProcedure get_func_support(Oid funcid); +extern Oid get_relname_relid(const char *relname, Oid relnamespace); +extern char *get_rel_name(Oid relid); +extern Oid get_rel_namespace(Oid relid); +extern Oid get_rel_type_id(Oid relid); +extern char get_rel_relkind(Oid relid); +extern bool get_rel_relispartition(Oid relid); +extern Oid get_rel_tablespace(Oid relid); +extern char get_rel_persistence(Oid relid); +extern Oid get_transform_fromsql(Oid typid, Oid langid, List *trftypes); +extern Oid get_transform_tosql(Oid typid, Oid langid, List *trftypes); +extern bool get_typisdefined(Oid typid); +extern int16 get_typlen(Oid typid); +extern bool get_typbyval(Oid typid); +extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval); +extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, + char *typalign); +extern Oid getTypeIOParam(HeapTuple typeTuple); +extern void get_type_io_data(Oid typid, + IOFuncSelector which_func, + int16 *typlen, + bool *typbyval, + char *typalign, + char *typdelim, + Oid *typioparam, + Oid *func); +extern char get_typstorage(Oid typid); +extern Node *get_typdefault(Oid typid); +extern char get_typtype(Oid typid); +extern bool type_is_rowtype(Oid typid); +extern bool type_is_enum(Oid typid); +extern bool type_is_range(Oid typid); +extern bool type_is_multirange(Oid typid); +extern void get_type_category_preferred(Oid typid, + char *typcategory, + bool *typispreferred); +extern Oid get_typ_typrelid(Oid typid); +extern Oid get_element_type(Oid typid); +extern Oid get_array_type(Oid typid); +extern Oid get_promoted_array_type(Oid typid); +extern Oid get_base_element_type(Oid typid); +extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam); +extern void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena); +extern void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam); +extern void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena); +extern Oid get_typmodin(Oid typid); +extern Oid get_typcollation(Oid typid); +extern bool type_is_collatable(Oid typid); +extern RegProcedure get_typsubscript(Oid typid, Oid *typelemp); +extern const struct SubscriptRoutines *getSubscriptingRoutines(Oid typid, + Oid *typelemp); +extern Oid getBaseType(Oid typid); +extern Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod); +extern int32 get_typavgwidth(Oid typid, int32 typmod); +extern int32 get_attavgwidth(Oid relid, AttrNumber attnum); +extern bool get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple, + int reqkind, Oid reqop, int flags); +extern void free_attstatsslot(AttStatsSlot *sslot); +extern char *get_namespace_name(Oid nspid); +extern char *get_namespace_name_or_temp(Oid nspid); +extern Oid get_range_subtype(Oid rangeOid); +extern Oid get_range_collation(Oid rangeOid); +extern Oid get_range_multirange(Oid rangeOid); +extern Oid get_multirange_range(Oid multirangeOid); +extern Oid get_index_column_opclass(Oid index_oid, int attno); +extern bool get_index_isreplident(Oid index_oid); +extern bool get_index_isvalid(Oid index_oid); +extern bool get_index_isclustered(Oid index_oid); + +#define type_is_array(typid) (get_element_type(typid) != InvalidOid) +/* type_is_array_domain accepts both plain arrays and domains over arrays */ +#define type_is_array_domain(typid) (get_base_element_type(typid) != InvalidOid) + +#define TypeIsToastable(typid) (get_typstorage(typid) != TYPSTORAGE_PLAIN) + +#endif /* LSYSCACHE_H */ diff --git a/src/include/utils/memdebug.h b/src/include/utils/memdebug.h new file mode 100644 index 0000000..6876e0a --- /dev/null +++ b/src/include/utils/memdebug.h @@ -0,0 +1,82 @@ +/*------------------------------------------------------------------------- + * + * memdebug.h + * Memory debugging support. + * + * Currently, this file either wraps <valgrind/memcheck.h> or substitutes + * empty definitions for Valgrind client request macros we use. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/memdebug.h + * + *------------------------------------------------------------------------- + */ +#ifndef MEMDEBUG_H +#define MEMDEBUG_H + +#ifdef USE_VALGRIND +#include <valgrind/memcheck.h> +#else +#define VALGRIND_CHECK_MEM_IS_DEFINED(addr, size) do {} while (0) +#define VALGRIND_CREATE_MEMPOOL(context, redzones, zeroed) do {} while (0) +#define VALGRIND_DESTROY_MEMPOOL(context) do {} while (0) +#define VALGRIND_MAKE_MEM_DEFINED(addr, size) do {} while (0) +#define VALGRIND_MAKE_MEM_NOACCESS(addr, size) do {} while (0) +#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size) do {} while (0) +#define VALGRIND_MEMPOOL_ALLOC(context, addr, size) do {} while (0) +#define VALGRIND_MEMPOOL_FREE(context, addr) do {} while (0) +#define VALGRIND_MEMPOOL_CHANGE(context, optr, nptr, size) do {} while (0) +#endif + + +#ifdef CLOBBER_FREED_MEMORY + +/* Wipe freed memory for debugging purposes */ +static inline void +wipe_mem(void *ptr, size_t size) +{ + VALGRIND_MAKE_MEM_UNDEFINED(ptr, size); + memset(ptr, 0x7F, size); + VALGRIND_MAKE_MEM_NOACCESS(ptr, size); +} + +#endif /* CLOBBER_FREED_MEMORY */ + +#ifdef MEMORY_CONTEXT_CHECKING + +static inline void +set_sentinel(void *base, Size offset) +{ + char *ptr = (char *) base + offset; + + VALGRIND_MAKE_MEM_UNDEFINED(ptr, 1); + *ptr = 0x7E; + VALGRIND_MAKE_MEM_NOACCESS(ptr, 1); +} + +static inline bool +sentinel_ok(const void *base, Size offset) +{ + const char *ptr = (const char *) base + offset; + bool ret; + + VALGRIND_MAKE_MEM_DEFINED(ptr, 1); + ret = *ptr == 0x7E; + VALGRIND_MAKE_MEM_NOACCESS(ptr, 1); + + return ret; +} + +#endif /* MEMORY_CONTEXT_CHECKING */ + +#ifdef RANDOMIZE_ALLOCATED_MEMORY + +void randomize_mem(char *ptr, size_t size); + +#endif /* RANDOMIZE_ALLOCATED_MEMORY */ + + +#endif /* MEMDEBUG_H */ diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h new file mode 100644 index 0000000..495d1af --- /dev/null +++ b/src/include/utils/memutils.h @@ -0,0 +1,229 @@ +/*------------------------------------------------------------------------- + * + * memutils.h + * This file contains declarations for memory allocation utility + * functions. These are functions that are not quite widely used + * enough to justify going in utils/palloc.h, but are still part + * of the API of the memory management subsystem. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/memutils.h + * + *------------------------------------------------------------------------- + */ +#ifndef MEMUTILS_H +#define MEMUTILS_H + +#include "nodes/memnodes.h" + + +/* + * MaxAllocSize, MaxAllocHugeSize + * Quasi-arbitrary limits on size of allocations. + * + * Note: + * There is no guarantee that smaller allocations will succeed, but + * larger requests will be summarily denied. + * + * palloc() enforces MaxAllocSize, chosen to correspond to the limiting size + * of varlena objects under TOAST. See VARSIZE_4B() and related macros in + * postgres.h. Many datatypes assume that any allocatable size can be + * represented in a varlena header. This limit also permits a caller to use + * an "int" variable for an index into or length of an allocation. Callers + * careful to avoid these hazards can access the higher limit with + * MemoryContextAllocHuge(). Both limits permit code to assume that it may + * compute twice an allocation's size without overflow. + */ +#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */ + +#define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize) + +#define MaxAllocHugeSize (SIZE_MAX / 2) + +#define AllocHugeSizeIsValid(size) ((Size) (size) <= MaxAllocHugeSize) + + +/* + * Standard top-level memory contexts. + * + * Only TopMemoryContext and ErrorContext are initialized by + * MemoryContextInit() itself. + */ +extern PGDLLIMPORT MemoryContext TopMemoryContext; +extern PGDLLIMPORT MemoryContext ErrorContext; +extern PGDLLIMPORT MemoryContext PostmasterContext; +extern PGDLLIMPORT MemoryContext CacheMemoryContext; +extern PGDLLIMPORT MemoryContext MessageContext; +extern PGDLLIMPORT MemoryContext TopTransactionContext; +extern PGDLLIMPORT MemoryContext CurTransactionContext; + +/* This is a transient link to the active portal's memory context: */ +extern PGDLLIMPORT MemoryContext PortalContext; + +/* Backwards compatibility macro */ +#define MemoryContextResetAndDeleteChildren(ctx) MemoryContextReset(ctx) + + +/* + * Memory-context-type-independent functions in mcxt.c + */ +extern void MemoryContextInit(void); +extern void MemoryContextReset(MemoryContext context); +extern void MemoryContextDelete(MemoryContext context); +extern void MemoryContextResetOnly(MemoryContext context); +extern void MemoryContextResetChildren(MemoryContext context); +extern void MemoryContextDeleteChildren(MemoryContext context); +extern void MemoryContextSetIdentifier(MemoryContext context, const char *id); +extern void MemoryContextSetParent(MemoryContext context, + MemoryContext new_parent); +extern Size GetMemoryChunkSpace(void *pointer); +extern MemoryContext MemoryContextGetParent(MemoryContext context); +extern bool MemoryContextIsEmpty(MemoryContext context); +extern Size MemoryContextMemAllocated(MemoryContext context, bool recurse); +extern void MemoryContextStats(MemoryContext context); +extern void MemoryContextStatsDetail(MemoryContext context, int max_children, + bool print_to_stderr); +extern void MemoryContextAllowInCriticalSection(MemoryContext context, + bool allow); + +#ifdef MEMORY_CONTEXT_CHECKING +extern void MemoryContextCheck(MemoryContext context); +#endif +extern bool MemoryContextContains(MemoryContext context, void *pointer); + +/* Handy macro for copying and assigning context ID ... but note double eval */ +#define MemoryContextCopyAndSetIdentifier(cxt, id) \ + MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id)) + +/* + * GetMemoryChunkContext + * Given a currently-allocated chunk, determine the context + * it belongs to. + * + * All chunks allocated by any memory context manager are required to be + * preceded by the corresponding MemoryContext stored, without padding, in the + * preceding sizeof(void*) bytes. A currently-allocated chunk must contain a + * backpointer to its owning context. The backpointer is used by pfree() and + * repalloc() to find the context to call. + */ +#ifndef FRONTEND +static inline MemoryContext +GetMemoryChunkContext(void *pointer) +{ + MemoryContext context; + + /* + * Try to detect bogus pointers handed to us, poorly though we can. + * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an + * allocated chunk. + */ + Assert(pointer != NULL); + Assert(pointer == (void *) MAXALIGN(pointer)); + + /* + * OK, it's probably safe to look at the context. + */ + context = *(MemoryContext *) (((char *) pointer) - sizeof(void *)); + + AssertArg(MemoryContextIsValid(context)); + + return context; +} +#endif + +/* + * This routine handles the context-type-independent part of memory + * context creation. It's intended to be called from context-type- + * specific creation routines, and noplace else. + */ +extern void MemoryContextCreate(MemoryContext node, + NodeTag tag, + const MemoryContextMethods *methods, + MemoryContext parent, + const char *name); + +extern void HandleLogMemoryContextInterrupt(void); +extern void ProcessLogMemoryContextInterrupt(void); + +/* + * Memory-context-type-specific functions + */ + +/* aset.c */ +extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent, + const char *name, + Size minContextSize, + Size initBlockSize, + Size maxBlockSize); + +/* + * This wrapper macro exists to check for non-constant strings used as context + * names; that's no longer supported. (Use MemoryContextSetIdentifier if you + * want to provide a variable identifier.) + */ +#ifdef HAVE__BUILTIN_CONSTANT_P +#define AllocSetContextCreate(parent, name, ...) \ + (StaticAssertExpr(__builtin_constant_p(name), \ + "memory context names must be constant strings"), \ + AllocSetContextCreateInternal(parent, name, __VA_ARGS__)) +#else +#define AllocSetContextCreate \ + AllocSetContextCreateInternal +#endif + +/* slab.c */ +extern MemoryContext SlabContextCreate(MemoryContext parent, + const char *name, + Size blockSize, + Size chunkSize); + +/* generation.c */ +extern MemoryContext GenerationContextCreate(MemoryContext parent, + const char *name, + Size minContextSize, + Size initBlockSize, + Size maxBlockSize); + +/* + * Recommended default alloc parameters, suitable for "ordinary" contexts + * that might hold quite a lot of data. + */ +#define ALLOCSET_DEFAULT_MINSIZE 0 +#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024) +#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024) +#define ALLOCSET_DEFAULT_SIZES \ + ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE + +/* + * Recommended alloc parameters for "small" contexts that are never expected + * to contain much data (for example, a context to contain a query plan). + */ +#define ALLOCSET_SMALL_MINSIZE 0 +#define ALLOCSET_SMALL_INITSIZE (1 * 1024) +#define ALLOCSET_SMALL_MAXSIZE (8 * 1024) +#define ALLOCSET_SMALL_SIZES \ + ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE + +/* + * Recommended alloc parameters for contexts that should start out small, + * but might sometimes grow big. + */ +#define ALLOCSET_START_SMALL_SIZES \ + ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE + + +/* + * Threshold above which a request in an AllocSet context is certain to be + * allocated separately (and thereby have constant allocation overhead). + * Few callers should be interested in this, but tuplesort/tuplestore need + * to know it. + */ +#define ALLOCSET_SEPARATE_THRESHOLD 8192 + +#define SLAB_DEFAULT_BLOCK_SIZE (8 * 1024) +#define SLAB_LARGE_BLOCK_SIZE (8 * 1024 * 1024) + +#endif /* MEMUTILS_H */ diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h new file mode 100644 index 0000000..915330f --- /dev/null +++ b/src/include/utils/multirangetypes.h @@ -0,0 +1,135 @@ +/*------------------------------------------------------------------------- + * + * multirangetypes.h + * Declarations for Postgres multirange types. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/multirangetypes.h + * + *------------------------------------------------------------------------- + */ +#ifndef MULTIRANGETYPES_H +#define MULTIRANGETYPES_H + +#include "utils/rangetypes.h" +#include "utils/typcache.h" + + +/* + * Multiranges are varlena objects, so must meet the varlena convention that + * the first int32 of the object contains the total object size in bytes. + * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + Oid multirangetypid; /* multirange type's own OID */ + uint32 rangeCount; /* the number of ranges */ + + /* + * Following the count are the range objects themselves, as ShortRangeType + * structs. Note that ranges are varlena too, depending on whether they + * have lower/upper bounds and because even their base types can be + * varlena. So we can't really index into this list. + */ +} MultirangeType; + +/* Use these macros in preference to accessing these fields directly */ +#define MultirangeTypeGetOid(mr) ((mr)->multirangetypid) +#define MultirangeIsEmpty(mr) ((mr)->rangeCount == 0) + +/* + * fmgr macros for multirange type objects + */ +#define DatumGetMultirangeTypeP(X) ((MultirangeType *) PG_DETOAST_DATUM(X)) +#define DatumGetMultirangeTypePCopy(X) ((MultirangeType *) PG_DETOAST_DATUM_COPY(X)) +#define MultirangeTypePGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_MULTIRANGE_P(n) DatumGetMultirangeTypeP(PG_GETARG_DATUM(n)) +#define PG_GETARG_MULTIRANGE_P_COPY(n) DatumGetMultirangeTypePCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_MULTIRANGE_P(x) return MultirangeTypePGetDatum(x) + +/* + * prototypes for functions defined in multirangetypes.c + */ + +/* internal versions of the above */ +extern bool multirange_eq_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool multirange_ne_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool multirange_contains_elem_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, + Datum elem); +extern bool multirange_contains_range_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr, + const RangeType *r); +extern bool range_contains_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_contains_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool range_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_overlaps_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern bool range_overleft_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_overright_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_before_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_after_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool range_adjacent_multirange_internal(TypeCacheEntry *rangetyp, + const RangeType *r, + const MultirangeType *mr); +extern bool multirange_before_multirange_internal(TypeCacheEntry *rangetyp, + const MultirangeType *mr1, + const MultirangeType *mr2); +extern MultirangeType *multirange_minus_internal(Oid mltrngtypoid, + TypeCacheEntry *rangetyp, + int32 range_count1, + RangeType **ranges1, + int32 range_count2, + RangeType **ranges2); +extern MultirangeType *multirange_intersect_internal(Oid mltrngtypoid, + TypeCacheEntry *rangetyp, + int32 range_count1, + RangeType **ranges1, + int32 range_count2, + RangeType **ranges2); + +/* assorted support functions */ +extern TypeCacheEntry *multirange_get_typcache(FunctionCallInfo fcinfo, + Oid mltrngtypid); +extern void multirange_deserialize(TypeCacheEntry *rangetyp, + const MultirangeType *range, + int32 *range_count, + RangeType ***ranges); +extern MultirangeType *make_multirange(Oid mltrngtypoid, + TypeCacheEntry *typcache, + int32 range_count, RangeType **ranges); +extern MultirangeType *make_empty_multirange(Oid mltrngtypoid, + TypeCacheEntry *rangetyp); +extern void multirange_get_bounds(TypeCacheEntry *rangetyp, + const MultirangeType *multirange, + uint32 i, + RangeBound *lower, RangeBound *upper); +extern RangeType *multirange_get_range(TypeCacheEntry *rangetyp, + const MultirangeType *multirange, int i); +extern RangeType *multirange_get_union_range(TypeCacheEntry *rangetyp, + const MultirangeType *mr); + +#endif /* MULTIRANGETYPES_H */ diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h new file mode 100644 index 0000000..3caa74d --- /dev/null +++ b/src/include/utils/numeric.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * numeric.h + * Definitions for the exact numeric data type of Postgres + * + * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. + * + * Copyright (c) 1998-2022, PostgreSQL Global Development Group + * + * src/include/utils/numeric.h + * + *------------------------------------------------------------------------- + */ +#ifndef _PG_NUMERIC_H_ +#define _PG_NUMERIC_H_ + +#include "fmgr.h" + +/* + * Limits on the precision and scale specifiable in a NUMERIC typmod. The + * precision is strictly positive, but the scale may be positive or negative. + * A negative scale implies rounding before the decimal point. + * + * Note that the minimum display scale defined below is zero --- we always + * display all digits before the decimal point, even when the scale is + * negative. + * + * Note that the implementation limits on the precision and display scale of a + * numeric value are much larger --- beware of what you use these for! + */ +#define NUMERIC_MAX_PRECISION 1000 + +#define NUMERIC_MIN_SCALE (-1000) +#define NUMERIC_MAX_SCALE 1000 + +/* + * Internal limits on the scales chosen for calculation results + */ +#define NUMERIC_MAX_DISPLAY_SCALE NUMERIC_MAX_PRECISION +#define NUMERIC_MIN_DISPLAY_SCALE 0 + +#define NUMERIC_MAX_RESULT_SCALE (NUMERIC_MAX_PRECISION * 2) + +/* + * For inherently inexact calculations such as division and square root, + * we try to get at least this many significant digits; the idea is to + * deliver a result no worse than float8 would. + */ +#define NUMERIC_MIN_SIG_DIGITS 16 + +/* The actual contents of Numeric are private to numeric.c */ +struct NumericData; +typedef struct NumericData *Numeric; + +/* + * fmgr interface macros + */ + +#define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X)) +#define DatumGetNumericCopy(X) ((Numeric) PG_DETOAST_DATUM_COPY(X)) +#define NumericGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_NUMERIC(n) DatumGetNumeric(PG_GETARG_DATUM(n)) +#define PG_GETARG_NUMERIC_COPY(n) DatumGetNumericCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_NUMERIC(x) return NumericGetDatum(x) + +/* + * Utility functions in numeric.c + */ +extern bool numeric_is_nan(Numeric num); +extern bool numeric_is_inf(Numeric num); +extern int32 numeric_maximum_size(int32 typmod); +extern char *numeric_out_sci(Numeric num, int scale); +extern char *numeric_normalize(Numeric num); + +extern Numeric int64_to_numeric(int64 val); +extern Numeric int64_div_fast_to_numeric(int64 val1, int log10val2); + +extern Numeric numeric_add_opt_error(Numeric num1, Numeric num2, + bool *have_error); +extern Numeric numeric_sub_opt_error(Numeric num1, Numeric num2, + bool *have_error); +extern Numeric numeric_mul_opt_error(Numeric num1, Numeric num2, + bool *have_error); +extern Numeric numeric_div_opt_error(Numeric num1, Numeric num2, + bool *have_error); +extern Numeric numeric_mod_opt_error(Numeric num1, Numeric num2, + bool *have_error); +extern int32 numeric_int4_opt_error(Numeric num, bool *error); + +#endif /* _PG_NUMERIC_H_ */ diff --git a/src/include/utils/old_snapshot.h b/src/include/utils/old_snapshot.h new file mode 100644 index 0000000..e5b9d35 --- /dev/null +++ b/src/include/utils/old_snapshot.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * old_snapshot.h + * Data structures for 'snapshot too old' + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/old_snapshot.h + * + *------------------------------------------------------------------------- + */ + +#ifndef OLD_SNAPSHOT_H +#define OLD_SNAPSHOT_H + +#include "datatype/timestamp.h" +#include "storage/s_lock.h" + +/* + * Structure for dealing with old_snapshot_threshold implementation. + */ +typedef struct OldSnapshotControlData +{ + /* + * Variables for old snapshot handling are shared among processes and are + * only allowed to move forward. + */ + slock_t mutex_current; /* protect current_timestamp */ + TimestampTz current_timestamp; /* latest snapshot timestamp */ + slock_t mutex_latest_xmin; /* protect latest_xmin and next_map_update */ + TransactionId latest_xmin; /* latest snapshot xmin */ + TimestampTz next_map_update; /* latest snapshot valid up to */ + slock_t mutex_threshold; /* protect threshold fields */ + TimestampTz threshold_timestamp; /* earlier snapshot is old */ + TransactionId threshold_xid; /* earlier xid may be gone */ + + /* + * Keep one xid per minute for old snapshot error handling. + * + * Use a circular buffer with a head offset, a count of entries currently + * used, and a timestamp corresponding to the xid at the head offset. A + * count_used value of zero means that there are no times stored; a + * count_used value of OLD_SNAPSHOT_TIME_MAP_ENTRIES means that the buffer + * is full and the head must be advanced to add new entries. Use + * timestamps aligned to minute boundaries, since that seems less + * surprising than aligning based on the first usage timestamp. The + * latest bucket is effectively stored within latest_xmin. The circular + * buffer is updated when we get a new xmin value that doesn't fall into + * the same interval. + * + * It is OK if the xid for a given time slot is from earlier than + * calculated by adding the number of minutes corresponding to the + * (possibly wrapped) distance from the head offset to the time of the + * head entry, since that just results in the vacuuming of old tuples + * being slightly less aggressive. It would not be OK for it to be off in + * the other direction, since it might result in vacuuming tuples that are + * still expected to be there. + * + * Use of an SLRU was considered but not chosen because it is more + * heavyweight than is needed for this, and would probably not be any less + * code to implement. + * + * Persistence is not needed. + */ + int head_offset; /* subscript of oldest tracked time */ + TimestampTz head_timestamp; /* time corresponding to head xid */ + int count_used; /* how many slots are in use */ + TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER]; +} OldSnapshotControlData; + +extern PGDLLIMPORT volatile OldSnapshotControlData *oldSnapshotControl; + +#endif diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h new file mode 100644 index 0000000..a0b62aa --- /dev/null +++ b/src/include/utils/palloc.h @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------- + * + * palloc.h + * POSTGRES memory allocator definitions. + * + * This file contains the basic memory allocation interface that is + * needed by almost every backend module. It is included directly by + * postgres.h, so the definitions here are automatically available + * everywhere. Keep it lean! + * + * Memory allocation occurs within "contexts". Every chunk obtained from + * palloc()/MemoryContextAlloc() is allocated within a specific context. + * The entire contents of a context can be freed easily and quickly by + * resetting or deleting the context --- this is both faster and less + * prone to memory-leakage bugs than releasing chunks individually. + * We organize contexts into context trees to allow fine-grain control + * over chunk lifetime while preserving the certainty that we will free + * everything that should be freed. See utils/mmgr/README for more info. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/palloc.h + * + *------------------------------------------------------------------------- + */ +#ifndef PALLOC_H +#define PALLOC_H + +/* + * Type MemoryContextData is declared in nodes/memnodes.h. Most users + * of memory allocation should just treat it as an abstract type, so we + * do not provide the struct contents here. + */ +typedef struct MemoryContextData *MemoryContext; + +/* + * A memory context can have callback functions registered on it. Any such + * function will be called once just before the context is next reset or + * deleted. The MemoryContextCallback struct describing such a callback + * typically would be allocated within the context itself, thereby avoiding + * any need to manage it explicitly (the reset/delete action will free it). + */ +typedef void (*MemoryContextCallbackFunction) (void *arg); + +typedef struct MemoryContextCallback +{ + MemoryContextCallbackFunction func; /* function to call */ + void *arg; /* argument to pass it */ + struct MemoryContextCallback *next; /* next in list of callbacks */ +} MemoryContextCallback; + +/* + * CurrentMemoryContext is the default allocation context for palloc(). + * Avoid accessing it directly! Instead, use MemoryContextSwitchTo() + * to change the setting. + */ +extern PGDLLIMPORT MemoryContext CurrentMemoryContext; + +/* + * Flags for MemoryContextAllocExtended. + */ +#define MCXT_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */ +#define MCXT_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ +#define MCXT_ALLOC_ZERO 0x04 /* zero allocated memory */ + +/* + * Fundamental memory-allocation operations (more are in utils/memutils.h) + */ +extern void *MemoryContextAlloc(MemoryContext context, Size size); +extern void *MemoryContextAllocZero(MemoryContext context, Size size); +extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size); +extern void *MemoryContextAllocExtended(MemoryContext context, + Size size, int flags); + +extern void *palloc(Size size); +extern void *palloc0(Size size); +extern void *palloc_extended(Size size, int flags); +extern pg_nodiscard void *repalloc(void *pointer, Size size); +extern void pfree(void *pointer); + +/* + * Variants with easier notation and more type safety + */ + +/* + * Allocate space for one object of type "type" + */ +#define palloc_object(type) ((type *) palloc(sizeof(type))) +#define palloc0_object(type) ((type *) palloc0(sizeof(type))) + +/* + * Allocate space for "count" objects of type "type" + */ +#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count))) +#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count))) + +/* + * Change size of allocation pointed to by "pointer" to have space for "count" + * objects of type "type" + */ +#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count))) + +/* + * The result of palloc() is always word-aligned, so we can skip testing + * alignment of the pointer when deciding which MemSet variant to use. + * Note that this variant does not offer any advantage, and should not be + * used, unless its "sz" argument is a compile-time constant; therefore, the + * issue that it evaluates the argument multiple times isn't a problem in + * practice. + */ +#define palloc0fast(sz) \ + ( MemSetTest(0, sz) ? \ + MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \ + MemoryContextAllocZero(CurrentMemoryContext, sz) ) + +/* Higher-limit allocators. */ +extern void *MemoryContextAllocHuge(MemoryContext context, Size size); +extern pg_nodiscard void *repalloc_huge(void *pointer, Size size); + +/* + * Although this header file is nominally backend-only, certain frontend + * programs like pg_controldata include it via postgres.h. For some compilers + * it's necessary to hide the inline definition of MemoryContextSwitchTo in + * this scenario; hence the #ifndef FRONTEND. + */ + +#ifndef FRONTEND +static inline MemoryContext +MemoryContextSwitchTo(MemoryContext context) +{ + MemoryContext old = CurrentMemoryContext; + + CurrentMemoryContext = context; + return old; +} +#endif /* FRONTEND */ + +/* Registration of memory context reset/delete callbacks */ +extern void MemoryContextRegisterResetCallback(MemoryContext context, + MemoryContextCallback *cb); + +/* + * These are like standard strdup() except the copied string is + * allocated in a context, not with malloc(). + */ +extern char *MemoryContextStrdup(MemoryContext context, const char *string); +extern char *pstrdup(const char *in); +extern char *pnstrdup(const char *in, Size len); + +extern char *pchomp(const char *in); + +/* sprintf into a palloc'd buffer --- these are in psprintf.c */ +extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2); +extern size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) pg_attribute_printf(3, 0); + +#endif /* PALLOC_H */ diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h new file mode 100644 index 0000000..3394e1f --- /dev/null +++ b/src/include/utils/partcache.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------- + * + * partcache.h + * + * Copyright (c) 1996-2022, PostgreSQL Global Development Group + * + * src/include/utils/partcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTCACHE_H +#define PARTCACHE_H + +#include "access/attnum.h" +#include "fmgr.h" +#include "nodes/pg_list.h" +#include "nodes/primnodes.h" +#include "partitioning/partdefs.h" +#include "utils/relcache.h" + +/* + * Information about the partition key of a relation + */ +typedef struct PartitionKeyData +{ + char strategy; /* partitioning strategy */ + int16 partnatts; /* number of columns in the partition key */ + AttrNumber *partattrs; /* attribute numbers of columns in the + * partition key or 0 if it's an expr */ + List *partexprs; /* list of expressions in the partitioning + * key, one for each zero-valued partattrs */ + + Oid *partopfamily; /* OIDs of operator families */ + Oid *partopcintype; /* OIDs of opclass declared input data types */ + FmgrInfo *partsupfunc; /* lookup info for support funcs */ + + /* Partitioning collation per attribute */ + Oid *partcollation; + + /* Type information per attribute */ + Oid *parttypid; + int32 *parttypmod; + int16 *parttyplen; + bool *parttypbyval; + char *parttypalign; + Oid *parttypcoll; +} PartitionKeyData; + + +extern PartitionKey RelationGetPartitionKey(Relation rel); +extern List *RelationGetPartitionQual(Relation rel); +extern Expr *get_partition_qual_relid(Oid relid); + +/* + * PartitionKey inquiry functions + */ +static inline int +get_partition_strategy(PartitionKey key) +{ + return key->strategy; +} + +static inline int +get_partition_natts(PartitionKey key) +{ + return key->partnatts; +} + +static inline List * +get_partition_exprs(PartitionKey key) +{ + return key->partexprs; +} + +/* + * PartitionKey inquiry functions - one column + */ +static inline int16 +get_partition_col_attnum(PartitionKey key, int col) +{ + return key->partattrs[col]; +} + +static inline Oid +get_partition_col_typid(PartitionKey key, int col) +{ + return key->parttypid[col]; +} + +static inline int32 +get_partition_col_typmod(PartitionKey key, int col) +{ + return key->parttypmod[col]; +} + +static inline Oid +get_partition_col_collation(PartitionKey key, int col) +{ + return key->partcollation[col]; +} + +#endif /* PARTCACHE_H */ diff --git a/src/include/utils/pg_crc.h b/src/include/utils/pg_crc.h new file mode 100644 index 0000000..48a064e --- /dev/null +++ b/src/include/utils/pg_crc.h @@ -0,0 +1,107 @@ +/* + * pg_crc.h + * + * PostgreSQL CRC support + * + * See Ross Williams' excellent introduction + * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from + * http://ross.net/crc/ or several other net sites. + * + * We have three slightly different variants of a 32-bit CRC calculation: + * CRC-32C (Castagnoli polynomial), CRC-32 (Ethernet polynomial), and a legacy + * CRC-32 version that uses the lookup table in a funny way. They all consist + * of four macros: + * + * INIT_<variant>(crc) + * Initialize a CRC accumulator + * + * COMP_<variant>(crc, data, len) + * Accumulate some (more) bytes into a CRC + * + * FIN_<variant>(crc) + * Finish a CRC calculation + * + * EQ_<variant>(c1, c2) + * Check for equality of two CRCs. + * + * The CRC-32C variant is in port/pg_crc32c.h. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/pg_crc.h + */ +#ifndef PG_CRC_H +#define PG_CRC_H + +typedef uint32 pg_crc32; + +/* + * CRC-32, the same used e.g. in Ethernet. + * + * This is currently only used in ltree and hstore contrib modules. It uses + * the same lookup table as the legacy algorithm below. New code should + * use the Castagnoli version instead. + */ +#define INIT_TRADITIONAL_CRC32(crc) ((crc) = 0xFFFFFFFF) +#define FIN_TRADITIONAL_CRC32(crc) ((crc) ^= 0xFFFFFFFF) +#define COMP_TRADITIONAL_CRC32(crc, data, len) \ + COMP_CRC32_NORMAL_TABLE(crc, data, len, pg_crc32_table) +#define EQ_TRADITIONAL_CRC32(c1, c2) ((c1) == (c2)) + +/* Sarwate's algorithm, for use with a "normal" lookup table */ +#define COMP_CRC32_NORMAL_TABLE(crc, data, len, table) \ +do { \ + const unsigned char *__data = (const unsigned char *) (data); \ + uint32 __len = (len); \ +\ + while (__len-- > 0) \ + { \ + int __tab_index = ((int) (crc) ^ *__data++) & 0xFF; \ + (crc) = table[__tab_index] ^ ((crc) >> 8); \ + } \ +} while (0) + +/* + * The CRC algorithm used for WAL et al in pre-9.5 versions. + * + * This closely resembles the normal CRC-32 algorithm, but is subtly + * different. Using Williams' terms, we use the "normal" table, but with + * "reflected" code. That's bogus, but it was like that for years before + * anyone noticed. It does not correspond to any polynomial in a normal CRC + * algorithm, so it's not clear what the error-detection properties of this + * algorithm actually are. + * + * We still need to carry this around because it is used in a few on-disk + * structures that need to be pg_upgradeable. It should not be used in new + * code. + */ +#define INIT_LEGACY_CRC32(crc) ((crc) = 0xFFFFFFFF) +#define FIN_LEGACY_CRC32(crc) ((crc) ^= 0xFFFFFFFF) +#define COMP_LEGACY_CRC32(crc, data, len) \ + COMP_CRC32_REFLECTED_TABLE(crc, data, len, pg_crc32_table) +#define EQ_LEGACY_CRC32(c1, c2) ((c1) == (c2)) + +/* + * Sarwate's algorithm, for use with a "reflected" lookup table (but in the + * legacy algorithm, we actually use it on a "normal" table, see above) + */ +#define COMP_CRC32_REFLECTED_TABLE(crc, data, len, table) \ +do { \ + const unsigned char *__data = (const unsigned char *) (data); \ + uint32 __len = (len); \ +\ + while (__len-- > 0) \ + { \ + int __tab_index = ((int) ((crc) >> 24) ^ *__data++) & 0xFF; \ + (crc) = table[__tab_index] ^ ((crc) << 8); \ + } \ +} while (0) + +/* + * Constant table for the CRC-32 polynomials. The same table is used by both + * the normal and traditional variants. + */ +extern PGDLLIMPORT const uint32 pg_crc32_table[256]; + +#endif /* PG_CRC_H */ diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h new file mode 100644 index 0000000..de7c5e3 --- /dev/null +++ b/src/include/utils/pg_locale.h @@ -0,0 +1,129 @@ +/*----------------------------------------------------------------------- + * + * PostgreSQL locale utilities + * + * src/include/utils/pg_locale.h + * + * Copyright (c) 2002-2022, PostgreSQL Global Development Group + * + *----------------------------------------------------------------------- + */ + +#ifndef _PG_LOCALE_ +#define _PG_LOCALE_ + +#if defined(LOCALE_T_IN_XLOCALE) || defined(WCSTOMBS_L_IN_XLOCALE) +#include <xlocale.h> +#endif +#ifdef USE_ICU +#include <unicode/ucol.h> +#endif + +#include "utils/guc.h" + +#ifdef USE_ICU +/* + * ucol_strcollUTF8() was introduced in ICU 50, but it is buggy before ICU 53. + * (see + * <https://www.postgresql.org/message-id/flat/f1438ec6-22aa-4029-9a3b-26f79d330e72%40manitou-mail.org>) + */ +#if U_ICU_VERSION_MAJOR_NUM >= 53 +#define HAVE_UCOL_STRCOLLUTF8 1 +#else +#undef HAVE_UCOL_STRCOLLUTF8 +#endif +#endif + +/* use for libc locale names */ +#define LOCALE_NAME_BUFLEN 128 + +/* GUC settings */ +extern PGDLLIMPORT char *locale_messages; +extern PGDLLIMPORT char *locale_monetary; +extern PGDLLIMPORT char *locale_numeric; +extern PGDLLIMPORT char *locale_time; + +/* lc_time localization cache */ +extern PGDLLIMPORT char *localized_abbrev_days[]; +extern PGDLLIMPORT char *localized_full_days[]; +extern PGDLLIMPORT char *localized_abbrev_months[]; +extern PGDLLIMPORT char *localized_full_months[]; + +/* is the databases's LC_CTYPE the C locale? */ +extern PGDLLIMPORT bool database_ctype_is_c; + +extern bool check_locale_messages(char **newval, void **extra, GucSource source); +extern void assign_locale_messages(const char *newval, void *extra); +extern bool check_locale_monetary(char **newval, void **extra, GucSource source); +extern void assign_locale_monetary(const char *newval, void *extra); +extern bool check_locale_numeric(char **newval, void **extra, GucSource source); +extern void assign_locale_numeric(const char *newval, void *extra); +extern bool check_locale_time(char **newval, void **extra, GucSource source); +extern void assign_locale_time(const char *newval, void *extra); + +extern bool check_locale(int category, const char *locale, char **canonname); +extern char *pg_perm_setlocale(int category, const char *locale); +extern void check_strxfrm_bug(void); + +extern bool lc_collate_is_c(Oid collation); +extern bool lc_ctype_is_c(Oid collation); + +/* + * Return the POSIX lconv struct (contains number/money formatting + * information) with locale information for all categories. + */ +extern struct lconv *PGLC_localeconv(void); + +extern void cache_locale_time(void); + + +/* + * We define our own wrapper around locale_t so we can keep the same + * function signatures for all builds, while not having to create a + * fake version of the standard type locale_t in the global namespace. + * pg_locale_t is occasionally checked for truth, so make it a pointer. + */ +struct pg_locale_struct +{ + char provider; + bool deterministic; + union + { +#ifdef HAVE_LOCALE_T + locale_t lt; +#endif +#ifdef USE_ICU + struct + { + const char *locale; + UCollator *ucol; + } icu; +#endif + int dummy; /* in case we have neither LOCALE_T nor ICU */ + } info; +}; + +typedef struct pg_locale_struct *pg_locale_t; + +extern PGDLLIMPORT struct pg_locale_struct default_locale; + +extern void make_icu_collator(const char *iculocstr, + struct pg_locale_struct *resultp); + +extern pg_locale_t pg_newlocale_from_collation(Oid collid); + +extern char *get_collation_actual_version(char collprovider, const char *collcollate); + +#ifdef USE_ICU +extern int32_t icu_to_uchar(UChar **buff_uchar, const char *buff, size_t nbytes); +extern int32_t icu_from_uchar(char **result, const UChar *buff_uchar, int32_t len_uchar); +#endif +extern void check_icu_locale(const char *icu_locale); + +/* These functions convert from/to libc's wchar_t, *not* pg_wchar_t */ +extern size_t wchar2char(char *to, const wchar_t *from, size_t tolen, + pg_locale_t locale); +extern size_t char2wchar(wchar_t *to, size_t tolen, + const char *from, size_t fromlen, pg_locale_t locale); + +#endif /* _PG_LOCALE_ */ diff --git a/src/include/utils/pg_lsn.h b/src/include/utils/pg_lsn.h new file mode 100644 index 0000000..7b708f1 --- /dev/null +++ b/src/include/utils/pg_lsn.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * pg_lsn.h + * Declarations for operations on log sequence numbers (LSNs) of + * PostgreSQL. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/pg_lsn.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_LSN_H +#define PG_LSN_H + +#include "access/xlogdefs.h" +#include "fmgr.h" + +#define DatumGetLSN(X) ((XLogRecPtr) DatumGetInt64(X)) +#define LSNGetDatum(X) (Int64GetDatum((int64) (X))) + +#define PG_GETARG_LSN(n) DatumGetLSN(PG_GETARG_DATUM(n)) +#define PG_RETURN_LSN(x) return LSNGetDatum(x) + +extern XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error); + +#endif /* PG_LSN_H */ diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h new file mode 100644 index 0000000..a6344ab --- /dev/null +++ b/src/include/utils/pg_rusage.h @@ -0,0 +1,37 @@ +/*------------------------------------------------------------------------- + * + * pg_rusage.h + * header file for resource usage measurement support routines + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/pg_rusage.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_RUSAGE_H +#define PG_RUSAGE_H + +#include <sys/time.h> + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#else +#include "rusagestub.h" +#endif + + +/* State structure for pg_rusage_init/pg_rusage_show */ +typedef struct PGRUsage +{ + struct timeval tv; + struct rusage ru; +} PGRUsage; + + +extern void pg_rusage_init(PGRUsage *ru0); +extern const char *pg_rusage_show(const PGRUsage *ru0); + +#endif /* PG_RUSAGE_H */ diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h new file mode 100644 index 0000000..4b65dfe --- /dev/null +++ b/src/include/utils/pgstat_internal.h @@ -0,0 +1,784 @@ +/* ---------- + * pgstat_internal.h + * + * Definitions for the PostgreSQL cumulative statistics system that should + * only be needed by files implementing statistics support (rather than ones + * reporting / querying stats). + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/utils/pgstat_internal.h + * ---------- + */ +#ifndef PGSTAT_INTERNAL_H +#define PGSTAT_INTERNAL_H + + +#include "common/hashfn.h" +#include "lib/dshash.h" +#include "lib/ilist.h" +#include "pgstat.h" +#include "storage/lwlock.h" +#include "utils/dsa.h" + + +/* + * Types related to shared memory storage of statistics. + * + * Per-object statistics are stored in the "shared stats" hashtable. That + * table's entries (PgStatShared_HashEntry) contain a pointer to the actual stats + * data for the object (the size of the stats data varies depending on the + * kind of stats). The table is keyed by PgStat_HashKey. + * + * Once a backend has a reference to a shared stats entry, it increments the + * entry's refcount. Even after stats data is dropped (e.g., due to a DROP + * TABLE), the entry itself can only be deleted once all references have been + * released. + * + * These refcounts, in combination with a backend local hashtable + * (pgStatEntryRefHash, with entries pointing to PgStat_EntryRef) in front of + * the shared hash table, mean that most stats work can happen without + * touching the shared hash table, reducing contention. + * + * Once there are pending stats updates for a table PgStat_EntryRef->pending + * is allocated to contain a working space for as-of-yet-unapplied stats + * updates. Once the stats are flushed, PgStat_EntryRef->pending is freed. + * + * Each stat kind in the shared hash table has a fixed member + * PgStatShared_Common as the first element. + */ + +/* struct for shared statistics hash entry key. */ +typedef struct PgStat_HashKey +{ + PgStat_Kind kind; /* statistics entry kind */ + Oid dboid; /* database ID. InvalidOid for shared objects. */ + Oid objoid; /* object ID, either table or function. */ +} PgStat_HashKey; + +/* + * Shared statistics hash entry. Doesn't itself contain any stats, but points + * to them (with ->body). That allows the stats entries themselves to be of + * variable size. + */ +typedef struct PgStatShared_HashEntry +{ + PgStat_HashKey key; /* hash key */ + + /* + * If dropped is set, backends need to release their references so that + * the memory for the entry can be freed. No new references may be made + * once marked as dropped. + */ + bool dropped; + + /* + * Refcount managing lifetime of the entry itself (as opposed to the + * dshash entry pointing to it). The stats lifetime has to be separate + * from the hash table entry lifetime because we allow backends to point + * to a stats entry without holding a hash table lock (and some other + * reasons). + * + * As long as the entry is not dropped, 1 is added to the refcount + * representing that the entry should not be dropped. In addition each + * backend that has a reference to the entry needs to increment the + * refcount as long as it does. + * + * May only be incremented / decremented while holding at least a shared + * lock on the dshash partition containing the entry. It needs to be an + * atomic variable because multiple backends can increment the refcount + * with just a shared lock. + * + * When the refcount reaches 0 the entry needs to be freed. + */ + pg_atomic_uint32 refcount; + + /* + * Pointer to shared stats. The stats entry always starts with + * PgStatShared_Common, embedded in a larger struct containing the + * PgStat_Kind specific stats fields. + */ + dsa_pointer body; +} PgStatShared_HashEntry; + +/* + * Common header struct for PgStatShm_Stat*Entry. + */ +typedef struct PgStatShared_Common +{ + uint32 magic; /* just a validity cross-check */ + /* lock protecting stats contents (i.e. data following the header) */ + LWLock lock; +} PgStatShared_Common; + +/* + * A backend local reference to a shared stats entry. As long as at least one + * such reference exists, the shared stats entry will not be released. + * + * If there are pending stats update to the shared stats, these are stored in + * ->pending. + */ +typedef struct PgStat_EntryRef +{ + /* + * Pointer to the PgStatShared_HashEntry entry in the shared stats + * hashtable. + */ + PgStatShared_HashEntry *shared_entry; + + /* + * Pointer to the stats data (i.e. PgStatShared_HashEntry->body), resolved + * as a local pointer, to avoid repeated dsa_get_address() calls. + */ + PgStatShared_Common *shared_stats; + + /* + * Pending statistics data that will need to be flushed to shared memory + * stats eventually. Each stats kind utilizing pending data defines what + * format its pending data has and needs to provide a + * PgStat_KindInfo->flush_pending_cb callback to merge pending into shared + * stats. + */ + void *pending; + dlist_node pending_node; /* membership in pgStatPending list */ +} PgStat_EntryRef; + + +/* + * Some stats changes are transactional. To maintain those, a stack of + * PgStat_SubXactStatus entries is maintained, which contain data pertaining + * to the current transaction and its active subtransactions. + */ +typedef struct PgStat_SubXactStatus +{ + int nest_level; /* subtransaction nest level */ + + struct PgStat_SubXactStatus *prev; /* higher-level subxact if any */ + + /* + * Statistics for transactionally dropped objects need to be + * transactionally dropped as well. Collect the stats dropped in the + * current (sub-)transaction and only execute the stats drop when we know + * if the transaction commits/aborts. To handle replicas and crashes, + * stats drops are included in commit / abort records. + */ + dlist_head pending_drops; + int pending_drops_count; + + /* + * Tuple insertion/deletion counts for an open transaction can't be + * propagated into PgStat_TableStatus counters until we know if it is + * going to commit or abort. Hence, we keep these counts in per-subxact + * structs that live in TopTransactionContext. This data structure is + * designed on the assumption that subxacts won't usually modify very many + * tables. + */ + PgStat_TableXactStatus *first; /* head of list for this subxact */ +} PgStat_SubXactStatus; + + +/* + * Metadata for a specific kind of statistics. + */ +typedef struct PgStat_KindInfo +{ + /* + * Do a fixed number of stats objects exist for this kind of stats (e.g. + * bgwriter stats) or not (e.g. tables). + */ + bool fixed_amount:1; + + /* + * Can stats of this kind be accessed from another database? Determines + * whether a stats object gets included in stats snapshots. + */ + bool accessed_across_databases:1; + + /* + * For variable-numbered stats: Identified on-disk using a name, rather + * than PgStat_HashKey. Probably only needed for replication slot stats. + */ + bool named_on_disk:1; + + /* + * The size of an entry in the shared stats hash table (pointed to by + * PgStatShared_HashEntry->body). + */ + uint32 shared_size; + + /* + * The offset/size of statistics inside the shared stats entry. Used when + * [de-]serializing statistics to / from disk respectively. Separate from + * shared_size because [de-]serialization may not include in-memory state + * like lwlocks. + */ + uint32 shared_data_off; + uint32 shared_data_len; + + /* + * The size of the pending data for this kind. E.g. how large + * PgStat_EntryRef->pending is. Used for allocations. + * + * 0 signals that an entry of this kind should never have a pending entry. + */ + uint32 pending_size; + + /* + * For variable-numbered stats: flush pending stats. Required if pending + * data is used. + */ + bool (*flush_pending_cb) (PgStat_EntryRef *sr, bool nowait); + + /* + * For variable-numbered stats: delete pending stats. Optional. + */ + void (*delete_pending_cb) (PgStat_EntryRef *sr); + + /* + * For variable-numbered stats: reset the reset timestamp. Optional. + */ + void (*reset_timestamp_cb) (PgStatShared_Common *header, TimestampTz ts); + + /* + * For variable-numbered stats with named_on_disk. Optional. + */ + void (*to_serialized_name) (const PgStat_HashKey *key, + const PgStatShared_Common *header, NameData *name); + bool (*from_serialized_name) (const NameData *name, PgStat_HashKey *key); + + /* + * For fixed-numbered statistics: Reset All. + */ + void (*reset_all_cb) (TimestampTz ts); + + /* + * For fixed-numbered statistics: Build snapshot for entry + */ + void (*snapshot_cb) (void); + + /* name of the kind of stats */ + const char *const name; +} PgStat_KindInfo; + + +/* + * List of SLRU names that we keep stats for. There is no central registry of + * SLRUs, so we use this fixed list instead. The "other" entry is used for + * all SLRUs without an explicit entry (e.g. SLRUs in extensions). + * + * This is only defined here so that SLRU_NUM_ELEMENTS is known for later type + * definitions. + */ +static const char *const slru_names[] = { + "CommitTs", + "MultiXactMember", + "MultiXactOffset", + "Notify", + "Serial", + "Subtrans", + "Xact", + "other" /* has to be last */ +}; + +#define SLRU_NUM_ELEMENTS lengthof(slru_names) + + +/* ---------- + * Types and definitions for different kinds of fixed-amount stats. + * + * Single-writer stats use the changecount mechanism to achieve low-overhead + * writes - they're obviously more performance critical than reads. Check the + * definition of struct PgBackendStatus for some explanation of the + * changecount mechanism. + * + * Because the obvious implementation of resetting single-writer stats isn't + * compatible with that (another backend needs to write), we don't scribble on + * shared stats while resetting. Instead, just record the current counter + * values in a copy of the stats data, which is protected by ->lock. See + * pgstat_fetch_stat_(archiver|bgwriter|checkpointer) for the reader side. + * + * The only exception to that is the stat_reset_timestamp in these structs, + * which is protected by ->lock, because it has to be written by another + * backend while resetting. + * ---------- + */ + +typedef struct PgStatShared_Archiver +{ + /* lock protects ->reset_offset as well as stats->stat_reset_timestamp */ + LWLock lock; + uint32 changecount; + PgStat_ArchiverStats stats; + PgStat_ArchiverStats reset_offset; +} PgStatShared_Archiver; + +typedef struct PgStatShared_BgWriter +{ + /* lock protects ->reset_offset as well as stats->stat_reset_timestamp */ + LWLock lock; + uint32 changecount; + PgStat_BgWriterStats stats; + PgStat_BgWriterStats reset_offset; +} PgStatShared_BgWriter; + +typedef struct PgStatShared_Checkpointer +{ + /* lock protects ->reset_offset as well as stats->stat_reset_timestamp */ + LWLock lock; + uint32 changecount; + PgStat_CheckpointerStats stats; + PgStat_CheckpointerStats reset_offset; +} PgStatShared_Checkpointer; + +typedef struct PgStatShared_SLRU +{ + /* lock protects ->stats */ + LWLock lock; + PgStat_SLRUStats stats[SLRU_NUM_ELEMENTS]; +} PgStatShared_SLRU; + +typedef struct PgStatShared_Wal +{ + /* lock protects ->stats */ + LWLock lock; + PgStat_WalStats stats; +} PgStatShared_Wal; + + + +/* ---------- + * Types and definitions for different kinds of variable-amount stats. + * + * Each struct has to start with PgStatShared_Common, containing information + * common across the different types of stats. Kind-specific data follows. + * ---------- + */ + +typedef struct PgStatShared_Database +{ + PgStatShared_Common header; + PgStat_StatDBEntry stats; +} PgStatShared_Database; + +typedef struct PgStatShared_Relation +{ + PgStatShared_Common header; + PgStat_StatTabEntry stats; +} PgStatShared_Relation; + +typedef struct PgStatShared_Function +{ + PgStatShared_Common header; + PgStat_StatFuncEntry stats; +} PgStatShared_Function; + +typedef struct PgStatShared_Subscription +{ + PgStatShared_Common header; + PgStat_StatSubEntry stats; +} PgStatShared_Subscription; + +typedef struct PgStatShared_ReplSlot +{ + PgStatShared_Common header; + PgStat_StatReplSlotEntry stats; +} PgStatShared_ReplSlot; + + +/* + * Central shared memory entry for the cumulative stats system. + * + * Fixed amount stats, the dynamic shared memory hash table for + * non-fixed-amount stats, as well as remaining bits and pieces are all + * reached from here. + */ +typedef struct PgStat_ShmemControl +{ + void *raw_dsa_area; + + /* + * Stats for variable-numbered objects are kept in this shared hash table. + * See comment above PgStat_Kind for details. + */ + dshash_table_handle hash_handle; /* shared dbstat hash */ + + /* Has the stats system already been shut down? Just a debugging check. */ + bool is_shutdown; + + /* + * Whenever statistics for dropped objects could not be freed - because + * backends still have references - the dropping backend calls + * pgstat_request_entry_refs_gc() incrementing this counter. Eventually + * that causes backends to run pgstat_gc_entry_refs(), allowing memory to + * be reclaimed. + */ + pg_atomic_uint64 gc_request_count; + + /* + * Stats data for fixed-numbered objects. + */ + PgStatShared_Archiver archiver; + PgStatShared_BgWriter bgwriter; + PgStatShared_Checkpointer checkpointer; + PgStatShared_SLRU slru; + PgStatShared_Wal wal; +} PgStat_ShmemControl; + + +/* + * Cached statistics snapshot + */ +typedef struct PgStat_Snapshot +{ + PgStat_FetchConsistency mode; + + /* time at which snapshot was taken */ + TimestampTz snapshot_timestamp; + + bool fixed_valid[PGSTAT_NUM_KINDS]; + + PgStat_ArchiverStats archiver; + + PgStat_BgWriterStats bgwriter; + + PgStat_CheckpointerStats checkpointer; + + PgStat_SLRUStats slru[SLRU_NUM_ELEMENTS]; + + PgStat_WalStats wal; + + /* to free snapshot in bulk */ + MemoryContext context; + struct pgstat_snapshot_hash *stats; +} PgStat_Snapshot; + + +/* + * Collection of backend-local stats state. + */ +typedef struct PgStat_LocalState +{ + PgStat_ShmemControl *shmem; + dsa_area *dsa; + dshash_table *shared_hash; + + /* the current statistics snapshot */ + PgStat_Snapshot snapshot; +} PgStat_LocalState; + + +/* + * Inline functions defined further below. + */ + +static inline void pgstat_begin_changecount_write(uint32 *cc); +static inline void pgstat_end_changecount_write(uint32 *cc); +static inline uint32 pgstat_begin_changecount_read(uint32 *cc); +static inline bool pgstat_end_changecount_read(uint32 *cc, uint32 cc_before); + +static inline void pgstat_copy_changecounted_stats(void *dst, void *src, size_t len, + uint32 *cc); + +static inline int pgstat_cmp_hash_key(const void *a, const void *b, size_t size, void *arg); +static inline uint32 pgstat_hash_hash_key(const void *d, size_t size, void *arg); +static inline size_t pgstat_get_entry_len(PgStat_Kind kind); +static inline void *pgstat_get_entry_data(PgStat_Kind kind, PgStatShared_Common *entry); + + +/* + * Functions in pgstat.c + */ + +extern const PgStat_KindInfo *pgstat_get_kind_info(PgStat_Kind kind); + +#ifdef USE_ASSERT_CHECKING +extern void pgstat_assert_is_up(void); +#else +#define pgstat_assert_is_up() ((void)true) +#endif + +extern void pgstat_delete_pending_entry(PgStat_EntryRef *entry_ref); +extern PgStat_EntryRef *pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid, bool *created_entry); +extern PgStat_EntryRef *pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid); + +extern void *pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid); +extern void pgstat_snapshot_fixed(PgStat_Kind kind); + + +/* + * Functions in pgstat_archiver.c + */ + +extern void pgstat_archiver_reset_all_cb(TimestampTz ts); +extern void pgstat_archiver_snapshot_cb(void); + + +/* + * Functions in pgstat_bgwriter.c + */ + +extern void pgstat_bgwriter_reset_all_cb(TimestampTz ts); +extern void pgstat_bgwriter_snapshot_cb(void); + + +/* + * Functions in pgstat_checkpointer.c + */ + +extern void pgstat_checkpointer_reset_all_cb(TimestampTz ts); +extern void pgstat_checkpointer_snapshot_cb(void); + + +/* + * Functions in pgstat_database.c + */ + +extern void pgstat_report_disconnect(Oid dboid); +extern void pgstat_update_dbstats(TimestampTz ts); +extern void AtEOXact_PgStat_Database(bool isCommit, bool parallel); + +extern PgStat_StatDBEntry *pgstat_prep_database_pending(Oid dboid); +extern void pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts); +extern bool pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern void pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts); + + +/* + * Functions in pgstat_function.c + */ + +extern bool pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); + + +/* + * Functions in pgstat_relation.c + */ + +extern void AtEOXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit); +extern void AtEOSubXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit, int nestDepth); +extern void AtPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state); +extern void PostPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state); + +extern bool pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern void pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref); + + +/* + * Functions in pgstat_replslot.c + */ + +extern void pgstat_replslot_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts); +extern void pgstat_replslot_to_serialized_name_cb(const PgStat_HashKey *key, const PgStatShared_Common *header, NameData *name); +extern bool pgstat_replslot_from_serialized_name_cb(const NameData *name, PgStat_HashKey *key); + + +/* + * Functions in pgstat_shmem.c + */ + +extern void pgstat_attach_shmem(void); +extern void pgstat_detach_shmem(void); + +extern PgStat_EntryRef *pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, Oid objoid, + bool create, bool *found); +extern bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait); +extern bool pgstat_lock_entry_shared(PgStat_EntryRef *entry_ref, bool nowait); +extern void pgstat_unlock_entry(PgStat_EntryRef *entry_ref); +extern bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid); +extern void pgstat_drop_all_entries(void); +extern PgStat_EntryRef *pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, Oid objoid, + bool nowait); +extern void pgstat_reset_entry(PgStat_Kind kind, Oid dboid, Oid objoid, TimestampTz ts); +extern void pgstat_reset_entries_of_kind(PgStat_Kind kind, TimestampTz ts); +extern void pgstat_reset_matching_entries(bool (*do_reset) (PgStatShared_HashEntry *, Datum), + Datum match_data, + TimestampTz ts); + +extern void pgstat_request_entry_refs_gc(void); +extern PgStatShared_Common *pgstat_init_entry(PgStat_Kind kind, + PgStatShared_HashEntry *shhashent); + + +/* + * Functions in pgstat_slru.c + */ + +extern bool pgstat_slru_flush(bool nowait); +extern void pgstat_slru_reset_all_cb(TimestampTz ts); +extern void pgstat_slru_snapshot_cb(void); + + +/* + * Functions in pgstat_wal.c + */ + +extern bool pgstat_flush_wal(bool nowait); +extern void pgstat_init_wal(void); +extern bool pgstat_have_pending_wal(void); + +extern void pgstat_wal_reset_all_cb(TimestampTz ts); +extern void pgstat_wal_snapshot_cb(void); + + +/* + * Functions in pgstat_subscription.c + */ + +extern bool pgstat_subscription_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern void pgstat_subscription_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts); + +/* + * Functions in pgstat_xact.c + */ + +extern PgStat_SubXactStatus *pgstat_get_xact_stack_level(int nest_level); +extern void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid); +extern void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid); + + +/* + * Variables in pgstat.c + */ + +extern PGDLLIMPORT PgStat_LocalState pgStatLocal; + + +/* + * Variables in pgstat_slru.c + */ + +extern PGDLLIMPORT bool have_slrustats; + + +/* + * Implementation of inline functions declared above. + */ + +/* + * Helpers for changecount manipulation. See comments around struct + * PgBackendStatus for details. + */ + +static inline void +pgstat_begin_changecount_write(uint32 *cc) +{ + Assert((*cc & 1) == 0); + + START_CRIT_SECTION(); + (*cc)++; + pg_write_barrier(); +} + +static inline void +pgstat_end_changecount_write(uint32 *cc) +{ + Assert((*cc & 1) == 1); + + pg_write_barrier(); + + (*cc)++; + + END_CRIT_SECTION(); +} + +static inline uint32 +pgstat_begin_changecount_read(uint32 *cc) +{ + uint32 before_cc = *cc; + + CHECK_FOR_INTERRUPTS(); + + pg_read_barrier(); + + return before_cc; +} + +/* + * Returns true if the read succeeded, false if it needs to be repeated. + */ +static inline bool +pgstat_end_changecount_read(uint32 *cc, uint32 before_cc) +{ + uint32 after_cc; + + pg_read_barrier(); + + after_cc = *cc; + + /* was a write in progress when we started? */ + if (before_cc & 1) + return false; + + /* did writes start and complete while we read? */ + return before_cc == after_cc; +} + + +/* + * helper function for PgStat_KindInfo->snapshot_cb + * PgStat_KindInfo->reset_all_cb callbacks. + * + * Copies out the specified memory area following change-count protocol. + */ +static inline void +pgstat_copy_changecounted_stats(void *dst, void *src, size_t len, + uint32 *cc) +{ + uint32 cc_before; + + do + { + cc_before = pgstat_begin_changecount_read(cc); + + memcpy(dst, src, len); + } + while (!pgstat_end_changecount_read(cc, cc_before)); +} + +/* helpers for dshash / simplehash hashtables */ +static inline int +pgstat_cmp_hash_key(const void *a, const void *b, size_t size, void *arg) +{ + AssertArg(size == sizeof(PgStat_HashKey) && arg == NULL); + return memcmp(a, b, sizeof(PgStat_HashKey)); +} + +static inline uint32 +pgstat_hash_hash_key(const void *d, size_t size, void *arg) +{ + const PgStat_HashKey *key = (PgStat_HashKey *) d; + uint32 hash; + + AssertArg(size == sizeof(PgStat_HashKey) && arg == NULL); + + hash = murmurhash32(key->kind); + hash = hash_combine(hash, murmurhash32(key->dboid)); + hash = hash_combine(hash, murmurhash32(key->objoid)); + + return hash; +} + +/* + * The length of the data portion of a shared memory stats entry (i.e. without + * transient data such as refcounts, lwlocks, ...). + */ +static inline size_t +pgstat_get_entry_len(PgStat_Kind kind) +{ + return pgstat_get_kind_info(kind)->shared_data_len; +} + +/* + * Returns a pointer to the data portion of a shared memory stats entry. + */ +static inline void * +pgstat_get_entry_data(PgStat_Kind kind, PgStatShared_Common *entry) +{ + size_t off = pgstat_get_kind_info(kind)->shared_data_off; + + Assert(off != 0 && off < PG_UINT32_MAX); + + return ((char *) (entry)) + off; +} + +#endif /* PGSTAT_INTERNAL_H */ diff --git a/src/include/utils/pidfile.h b/src/include/utils/pidfile.h new file mode 100644 index 0000000..14bfba4 --- /dev/null +++ b/src/include/utils/pidfile.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * pidfile.h + * Declarations describing the data directory lock file (postmaster.pid) + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/pidfile.h + * + *------------------------------------------------------------------------- + */ +#ifndef UTILS_PIDFILE_H +#define UTILS_PIDFILE_H + +/* + * As of Postgres 10, the contents of the data-directory lock file are: + * + * line # + * 1 postmaster PID (or negative of a standalone backend's PID) + * 2 data directory path + * 3 postmaster start timestamp (time_t representation) + * 4 port number + * 5 first Unix socket directory path (empty if none) + * 6 first listen_address (IP address or "*"; empty if no TCP port) + * 7 shared memory key (empty on Windows) + * 8 postmaster status (see values below) + * + * Lines 6 and up are added via AddToDataDirLockFile() after initial file + * creation; also, line 5 is initially empty and is changed after the first + * Unix socket is opened. Onlookers should not assume that lines 4 and up + * are filled in any particular order. + * + * Socket lock file(s), if used, have the same contents as lines 1-5, with + * line 5 being their own directory. + */ +#define LOCK_FILE_LINE_PID 1 +#define LOCK_FILE_LINE_DATA_DIR 2 +#define LOCK_FILE_LINE_START_TIME 3 +#define LOCK_FILE_LINE_PORT 4 +#define LOCK_FILE_LINE_SOCKET_DIR 5 +#define LOCK_FILE_LINE_LISTEN_ADDR 6 +#define LOCK_FILE_LINE_SHMEM_KEY 7 +#define LOCK_FILE_LINE_PM_STATUS 8 + +/* + * The PM_STATUS line may contain one of these values. All these strings + * must be the same length, per comments for AddToDataDirLockFile(). + * We pad with spaces as needed to make that true. + */ +#define PM_STATUS_STARTING "starting" /* still starting up */ +#define PM_STATUS_STOPPING "stopping" /* in shutdown sequence */ +#define PM_STATUS_READY "ready " /* ready for connections */ +#define PM_STATUS_STANDBY "standby " /* up, won't accept connections */ + +#endif /* UTILS_PIDFILE_H */ diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h new file mode 100644 index 0000000..0499635 --- /dev/null +++ b/src/include/utils/plancache.h @@ -0,0 +1,236 @@ +/*------------------------------------------------------------------------- + * + * plancache.h + * Plan cache definitions. + * + * See plancache.c for comments. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/plancache.h + * + *------------------------------------------------------------------------- + */ +#ifndef PLANCACHE_H +#define PLANCACHE_H + +#include "access/tupdesc.h" +#include "lib/ilist.h" +#include "nodes/params.h" +#include "tcop/cmdtag.h" +#include "utils/queryenvironment.h" +#include "utils/resowner.h" + + +/* Forward declaration, to avoid including parsenodes.h here */ +struct RawStmt; + +/* possible values for plan_cache_mode */ +typedef enum +{ + PLAN_CACHE_MODE_AUTO, + PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, + PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN +} PlanCacheMode; + +/* GUC parameter */ +extern PGDLLIMPORT int plan_cache_mode; + +#define CACHEDPLANSOURCE_MAGIC 195726186 +#define CACHEDPLAN_MAGIC 953717834 +#define CACHEDEXPR_MAGIC 838275847 + +/* + * CachedPlanSource (which might better have been called CachedQuery) + * represents a SQL query that we expect to use multiple times. It stores + * the query source text, the raw parse tree, and the analyzed-and-rewritten + * query tree, as well as adjunct data. Cache invalidation can happen as a + * result of DDL affecting objects used by the query. In that case we discard + * the analyzed-and-rewritten query tree, and rebuild it when next needed. + * + * An actual execution plan, represented by CachedPlan, is derived from the + * CachedPlanSource when we need to execute the query. The plan could be + * either generic (usable with any set of plan parameters) or custom (for a + * specific set of parameters). plancache.c contains the logic that decides + * which way to do it for any particular execution. If we are using a generic + * cached plan then it is meant to be re-used across multiple executions, so + * callers must always treat CachedPlans as read-only. + * + * Once successfully built and "saved", CachedPlanSources typically live + * for the life of the backend, although they can be dropped explicitly. + * CachedPlans are reference-counted and go away automatically when the last + * reference is dropped. A CachedPlan can outlive the CachedPlanSource it + * was created from. + * + * An "unsaved" CachedPlanSource can be used for generating plans, but it + * lives in transient storage and will not be updated in response to sinval + * events. + * + * CachedPlans made from saved CachedPlanSources are likewise in permanent + * storage, so to avoid memory leaks, the reference-counted references to them + * must be held in permanent data structures or ResourceOwners. CachedPlans + * made from unsaved CachedPlanSources are in children of the caller's + * memory context, so references to them should not be longer-lived than + * that context. (Reference counting is somewhat pro forma in that case, + * though it may be useful if the CachedPlan can be discarded early.) + * + * A CachedPlanSource has two associated memory contexts: one that holds the + * struct itself, the query source text and the raw parse tree, and another + * context that holds the rewritten query tree and associated data. This + * allows the query tree to be discarded easily when it is invalidated. + * + * Some callers wish to use the CachedPlan API even with one-shot queries + * that have no reason to be saved at all. We therefore support a "oneshot" + * variant that does no data copying or invalidation checking. In this case + * there are no separate memory contexts: the CachedPlanSource struct and + * all subsidiary data live in the caller's CurrentMemoryContext, and there + * is no way to free memory short of clearing that entire context. A oneshot + * plan is always treated as unsaved. + * + * Note: the string referenced by commandTag is not subsidiary storage; + * it is assumed to be a compile-time-constant string. As with portals, + * commandTag shall be NULL if and only if the original query string (before + * rewriting) was an empty string. + */ +typedef struct CachedPlanSource +{ + int magic; /* should equal CACHEDPLANSOURCE_MAGIC */ + struct RawStmt *raw_parse_tree; /* output of raw_parser(), or NULL */ + const char *query_string; /* source text of query */ + CommandTag commandTag; /* 'nuff said */ + Oid *param_types; /* array of parameter type OIDs, or NULL */ + int num_params; /* length of param_types array */ + ParserSetupHook parserSetup; /* alternative parameter spec method */ + void *parserSetupArg; + int cursor_options; /* cursor options used for planning */ + bool fixed_result; /* disallow change in result tupdesc? */ + TupleDesc resultDesc; /* result type; NULL = doesn't return tuples */ + MemoryContext context; /* memory context holding all above */ + /* These fields describe the current analyzed-and-rewritten query tree: */ + List *query_list; /* list of Query nodes, or NIL if not valid */ + List *relationOids; /* OIDs of relations the queries depend on */ + List *invalItems; /* other dependencies, as PlanInvalItems */ + struct OverrideSearchPath *search_path; /* search_path used for parsing + * and planning */ + MemoryContext query_context; /* context holding the above, or NULL */ + Oid rewriteRoleId; /* Role ID we did rewriting for */ + bool rewriteRowSecurity; /* row_security used during rewrite */ + bool dependsOnRLS; /* is rewritten query specific to the above? */ + /* If we have a generic plan, this is a reference-counted link to it: */ + struct CachedPlan *gplan; /* generic plan, or NULL if not valid */ + /* Some state flags: */ + bool is_oneshot; /* is it a "oneshot" plan? */ + bool is_complete; /* has CompleteCachedPlan been done? */ + bool is_saved; /* has CachedPlanSource been "saved"? */ + bool is_valid; /* is the query_list currently valid? */ + int generation; /* increments each time we create a plan */ + /* If CachedPlanSource has been saved, it is a member of a global list */ + dlist_node node; /* list link, if is_saved */ + /* State kept to help decide whether to use custom or generic plans: */ + double generic_cost; /* cost of generic plan, or -1 if not known */ + double total_custom_cost; /* total cost of custom plans so far */ + int64 num_custom_plans; /* # of custom plans included in total */ + int64 num_generic_plans; /* # of generic plans */ +} CachedPlanSource; + +/* + * CachedPlan represents an execution plan derived from a CachedPlanSource. + * The reference count includes both the link from the parent CachedPlanSource + * (if any), and any active plan executions, so the plan can be discarded + * exactly when refcount goes to zero. Both the struct itself and the + * subsidiary data live in the context denoted by the context field. + * This makes it easy to free a no-longer-needed cached plan. (However, + * if is_oneshot is true, the context does not belong solely to the CachedPlan + * so no freeing is possible.) + */ +typedef struct CachedPlan +{ + int magic; /* should equal CACHEDPLAN_MAGIC */ + List *stmt_list; /* list of PlannedStmts */ + bool is_oneshot; /* is it a "oneshot" plan? */ + bool is_saved; /* is CachedPlan in a long-lived context? */ + bool is_valid; /* is the stmt_list currently valid? */ + Oid planRoleId; /* Role ID the plan was created for */ + bool dependsOnRole; /* is plan specific to that role? */ + TransactionId saved_xmin; /* if valid, replan when TransactionXmin + * changes from this value */ + int generation; /* parent's generation number for this plan */ + int refcount; /* count of live references to this struct */ + MemoryContext context; /* context containing this CachedPlan */ +} CachedPlan; + +/* + * CachedExpression is a low-overhead mechanism for caching the planned form + * of standalone scalar expressions. While such expressions are not usually + * subject to cache invalidation events, that can happen, for example because + * of replacement of a SQL function that was inlined into the expression. + * The plancache takes care of storing the expression tree and marking it + * invalid if a cache invalidation occurs, but the caller must notice the + * !is_valid status and discard the obsolete expression without reusing it. + * We do not store the original parse tree, only the planned expression; + * this is an optimization based on the assumption that we usually will not + * need to replan for the life of the session. + */ +typedef struct CachedExpression +{ + int magic; /* should equal CACHEDEXPR_MAGIC */ + Node *expr; /* planned form of expression */ + bool is_valid; /* is the expression still valid? */ + /* remaining fields should be treated as private to plancache.c: */ + List *relationOids; /* OIDs of relations the expr depends on */ + List *invalItems; /* other dependencies, as PlanInvalItems */ + MemoryContext context; /* context containing this CachedExpression */ + dlist_node node; /* link in global list of CachedExpressions */ +} CachedExpression; + + +extern void InitPlanCache(void); +extern void ResetPlanCache(void); + +extern CachedPlanSource *CreateCachedPlan(struct RawStmt *raw_parse_tree, + const char *query_string, + CommandTag commandTag); +extern CachedPlanSource *CreateOneShotCachedPlan(struct RawStmt *raw_parse_tree, + const char *query_string, + CommandTag commandTag); +extern void CompleteCachedPlan(CachedPlanSource *plansource, + List *querytree_list, + MemoryContext querytree_context, + Oid *param_types, + int num_params, + ParserSetupHook parserSetup, + void *parserSetupArg, + int cursor_options, + bool fixed_result); + +extern void SaveCachedPlan(CachedPlanSource *plansource); +extern void DropCachedPlan(CachedPlanSource *plansource); + +extern void CachedPlanSetParentContext(CachedPlanSource *plansource, + MemoryContext newcontext); + +extern CachedPlanSource *CopyCachedPlan(CachedPlanSource *plansource); + +extern bool CachedPlanIsValid(CachedPlanSource *plansource); + +extern List *CachedPlanGetTargetList(CachedPlanSource *plansource, + QueryEnvironment *queryEnv); + +extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource, + ParamListInfo boundParams, + ResourceOwner owner, + QueryEnvironment *queryEnv); +extern void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner); + +extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource, + CachedPlan *plan, + ResourceOwner owner); +extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource, + CachedPlan *plan, + ResourceOwner owner); + +extern CachedExpression *GetCachedExpression(Node *expr); +extern void FreeCachedExpression(CachedExpression *cexpr); + +#endif /* PLANCACHE_H */ diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h new file mode 100644 index 0000000..aeddbda --- /dev/null +++ b/src/include/utils/portal.h @@ -0,0 +1,252 @@ +/*------------------------------------------------------------------------- + * + * portal.h + * POSTGRES portal definitions. + * + * A portal is an abstraction which represents the execution state of + * a running or runnable query. Portals support both SQL-level CURSORs + * and protocol-level portals. + * + * Scrolling (nonsequential access) and suspension of execution are allowed + * only for portals that contain a single SELECT-type query. We do not want + * to let the client suspend an update-type query partway through! Because + * the query rewriter does not allow arbitrary ON SELECT rewrite rules, + * only queries that were originally update-type could produce multiple + * plan trees; so the restriction to a single query is not a problem + * in practice. + * + * For SQL cursors, we support three kinds of scroll behavior: + * + * (1) Neither NO SCROLL nor SCROLL was specified: to remain backward + * compatible, we allow backward fetches here, unless it would + * impose additional runtime overhead to do so. + * + * (2) NO SCROLL was specified: don't allow any backward fetches. + * + * (3) SCROLL was specified: allow all kinds of backward fetches, even + * if we need to take a performance hit to do so. (The planner sticks + * a Materialize node atop the query plan if needed.) + * + * Case #1 is converted to #2 or #3 by looking at the query itself and + * determining if scrollability can be supported without additional + * overhead. + * + * Protocol-level portals have no nonsequential-fetch API and so the + * distinction doesn't matter for them. They are always initialized + * to look like NO SCROLL cursors. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/portal.h + * + *------------------------------------------------------------------------- + */ +#ifndef PORTAL_H +#define PORTAL_H + +#include "datatype/timestamp.h" +#include "executor/execdesc.h" +#include "tcop/cmdtag.h" +#include "utils/plancache.h" +#include "utils/resowner.h" + +/* + * We have several execution strategies for Portals, depending on what + * query or queries are to be executed. (Note: in all cases, a Portal + * executes just a single source-SQL query, and thus produces just a + * single result from the user's viewpoint. However, the rule rewriter + * may expand the single source query to zero or many actual queries.) + * + * PORTAL_ONE_SELECT: the portal contains one single SELECT query. We run + * the Executor incrementally as results are demanded. This strategy also + * supports holdable cursors (the Executor results can be dumped into a + * tuplestore for access after transaction completion). + * + * PORTAL_ONE_RETURNING: the portal contains a single INSERT/UPDATE/DELETE + * query with a RETURNING clause (plus possibly auxiliary queries added by + * rule rewriting). On first execution, we run the portal to completion + * and dump the primary query's results into the portal tuplestore; the + * results are then returned to the client as demanded. (We can't support + * suspension of the query partway through, because the AFTER TRIGGER code + * can't cope, and also because we don't want to risk failing to execute + * all the auxiliary queries.) + * + * PORTAL_ONE_MOD_WITH: the portal contains one single SELECT query, but + * it has data-modifying CTEs. This is currently treated the same as the + * PORTAL_ONE_RETURNING case because of the possibility of needing to fire + * triggers. It may act more like PORTAL_ONE_SELECT in future. + * + * PORTAL_UTIL_SELECT: the portal contains a utility statement that returns + * a SELECT-like result (for example, EXPLAIN or SHOW). On first execution, + * we run the statement and dump its results into the portal tuplestore; + * the results are then returned to the client as demanded. + * + * PORTAL_MULTI_QUERY: all other cases. Here, we do not support partial + * execution: the portal's queries will be run to completion on first call. + */ +typedef enum PortalStrategy +{ + PORTAL_ONE_SELECT, + PORTAL_ONE_RETURNING, + PORTAL_ONE_MOD_WITH, + PORTAL_UTIL_SELECT, + PORTAL_MULTI_QUERY +} PortalStrategy; + +/* + * A portal is always in one of these states. It is possible to transit + * from ACTIVE back to READY if the query is not run to completion; + * otherwise we never back up in status. + */ +typedef enum PortalStatus +{ + PORTAL_NEW, /* freshly created */ + PORTAL_DEFINED, /* PortalDefineQuery done */ + PORTAL_READY, /* PortalStart complete, can run it */ + PORTAL_ACTIVE, /* portal is running (can't delete it) */ + PORTAL_DONE, /* portal is finished (don't re-run it) */ + PORTAL_FAILED /* portal got error (can't re-run it) */ +} PortalStatus; + +typedef struct PortalData *Portal; + +typedef struct PortalData +{ + /* Bookkeeping data */ + const char *name; /* portal's name */ + const char *prepStmtName; /* source prepared statement (NULL if none) */ + MemoryContext portalContext; /* subsidiary memory for portal */ + ResourceOwner resowner; /* resources owned by portal */ + void (*cleanup) (Portal portal); /* cleanup hook */ + + /* + * State data for remembering which subtransaction(s) the portal was + * created or used in. If the portal is held over from a previous + * transaction, both subxids are InvalidSubTransactionId. Otherwise, + * createSubid is the creating subxact and activeSubid is the last subxact + * in which we ran the portal. + */ + SubTransactionId createSubid; /* the creating subxact */ + SubTransactionId activeSubid; /* the last subxact with activity */ + int createLevel; /* creating subxact's nesting level */ + + /* The query or queries the portal will execute */ + const char *sourceText; /* text of query (as of 8.4, never NULL) */ + CommandTag commandTag; /* command tag for original query */ + QueryCompletion qc; /* command completion data for executed query */ + List *stmts; /* list of PlannedStmts */ + CachedPlan *cplan; /* CachedPlan, if stmts are from one */ + + ParamListInfo portalParams; /* params to pass to query */ + QueryEnvironment *queryEnv; /* environment for query */ + + /* Features/options */ + PortalStrategy strategy; /* see above */ + int cursorOptions; /* DECLARE CURSOR option bits */ + bool run_once; /* portal will only be run once */ + + /* Status data */ + PortalStatus status; /* see above */ + bool portalPinned; /* a pinned portal can't be dropped */ + bool autoHeld; /* was automatically converted from pinned to + * held (see HoldPinnedPortals()) */ + + /* If not NULL, Executor is active; call ExecutorEnd eventually: */ + QueryDesc *queryDesc; /* info needed for executor invocation */ + + /* If portal returns tuples, this is their tupdesc: */ + TupleDesc tupDesc; /* descriptor for result tuples */ + /* and these are the format codes to use for the columns: */ + int16 *formats; /* a format code for each column */ + + /* + * Outermost ActiveSnapshot for execution of the portal's queries. For + * all but a few utility commands, we require such a snapshot to exist. + * This ensures that TOAST references in query results can be detoasted, + * and helps to reduce thrashing of the process's exposed xmin. + */ + Snapshot portalSnapshot; /* active snapshot, or NULL if none */ + + /* + * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or + * PORTAL_UTIL_SELECT query. (A cursor held past the end of its + * transaction no longer has any active executor state.) + */ + Tuplestorestate *holdStore; /* store for holdable cursors */ + MemoryContext holdContext; /* memory containing holdStore */ + + /* + * Snapshot under which tuples in the holdStore were read. We must keep a + * reference to this snapshot if there is any possibility that the tuples + * contain TOAST references, because releasing the snapshot could allow + * recently-dead rows to be vacuumed away, along with any toast data + * belonging to them. In the case of a held cursor, we avoid needing to + * keep such a snapshot by forcibly detoasting the data. + */ + Snapshot holdSnapshot; /* registered snapshot, or NULL if none */ + + /* + * atStart, atEnd and portalPos indicate the current cursor position. + * portalPos is zero before the first row, N after fetching N'th row of + * query. After we run off the end, portalPos = # of rows in query, and + * atEnd is true. Note that atStart implies portalPos == 0, but not the + * reverse: we might have backed up only as far as the first row, not to + * the start. Also note that various code inspects atStart and atEnd, but + * only the portal movement routines should touch portalPos. + */ + bool atStart; + bool atEnd; + uint64 portalPos; + + /* Presentation data, primarily used by the pg_cursors system view */ + TimestampTz creation_time; /* time at which this portal was defined */ + bool visible; /* include this portal in pg_cursors? */ +} PortalData; + +/* + * PortalIsValid + * True iff portal is valid. + */ +#define PortalIsValid(p) PointerIsValid(p) + + +/* Prototypes for functions in utils/mmgr/portalmem.c */ +extern void EnablePortalManager(void); +extern bool PreCommit_Portals(bool isPrepare); +extern void AtAbort_Portals(void); +extern void AtCleanup_Portals(void); +extern void PortalErrorCleanup(void); +extern void AtSubCommit_Portals(SubTransactionId mySubid, + SubTransactionId parentSubid, + int parentLevel, + ResourceOwner parentXactOwner); +extern void AtSubAbort_Portals(SubTransactionId mySubid, + SubTransactionId parentSubid, + ResourceOwner myXactOwner, + ResourceOwner parentXactOwner); +extern void AtSubCleanup_Portals(SubTransactionId mySubid); +extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent); +extern Portal CreateNewPortal(void); +extern void PinPortal(Portal portal); +extern void UnpinPortal(Portal portal); +extern void MarkPortalActive(Portal portal); +extern void MarkPortalDone(Portal portal); +extern void MarkPortalFailed(Portal portal); +extern void PortalDrop(Portal portal, bool isTopCommit); +extern Portal GetPortalByName(const char *name); +extern void PortalDefineQuery(Portal portal, + const char *prepStmtName, + const char *sourceText, + CommandTag commandTag, + List *stmts, + CachedPlan *cplan); +extern PlannedStmt *PortalGetPrimaryStmt(Portal portal); +extern void PortalCreateHoldStore(Portal portal); +extern void PortalHashTableDeleteAll(void); +extern bool ThereAreNoReadyPortals(void); +extern void HoldPinnedPortals(void); +extern void ForgetPortalSnapshots(void); + +#endif /* PORTAL_H */ diff --git a/src/include/utils/ps_status.h b/src/include/utils/ps_status.h new file mode 100644 index 0000000..bba4635 --- /dev/null +++ b/src/include/utils/ps_status.h @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * ps_status.h + * + * Declarations for backend/utils/misc/ps_status.c + * + * src/include/utils/ps_status.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PS_STATUS_H +#define PS_STATUS_H + +extern PGDLLIMPORT bool update_process_title; + +extern char **save_ps_display_args(int argc, char **argv); + +extern void init_ps_display(const char *fixed_part); + +extern void set_ps_display(const char *activity); + +extern const char *get_ps_display(int *displen); + +#endif /* PS_STATUS_H */ diff --git a/src/include/utils/queryenvironment.h b/src/include/utils/queryenvironment.h new file mode 100644 index 0000000..23a16a9 --- /dev/null +++ b/src/include/utils/queryenvironment.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * queryenvironment.h + * Access to functions to mutate the query environment and retrieve the + * actual data related to entries (if any). + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/queryenvironment.h + * + *------------------------------------------------------------------------- + */ +#ifndef QUERYENVIRONMENT_H +#define QUERYENVIRONMENT_H + +#include "access/tupdesc.h" + + +typedef enum EphemeralNameRelationType +{ + ENR_NAMED_TUPLESTORE /* named tuplestore relation; e.g., deltas */ +} EphemeralNameRelationType; + +/* + * Some ephemeral named relations must match some relation (e.g., trigger + * transition tables), so to properly handle cached plans and DDL, we should + * carry the OID of that relation. In other cases an ENR might be independent + * of any relation which is stored in the system catalogs, so we need to be + * able to directly store the TupleDesc. We never need both. + */ +typedef struct EphemeralNamedRelationMetadataData +{ + char *name; /* name used to identify the relation */ + + /* only one of the next two fields should be used */ + Oid reliddesc; /* oid of relation to get tupdesc */ + TupleDesc tupdesc; /* description of result rows */ + + EphemeralNameRelationType enrtype; /* to identify type of relation */ + double enrtuples; /* estimated number of tuples */ +} EphemeralNamedRelationMetadataData; + +typedef EphemeralNamedRelationMetadataData *EphemeralNamedRelationMetadata; + +/* + * Ephemeral Named Relation data; used for parsing named relations not in the + * catalog, like transition tables in AFTER triggers. + */ +typedef struct EphemeralNamedRelationData +{ + EphemeralNamedRelationMetadataData md; + void *reldata; /* structure for execution-time access to data */ +} EphemeralNamedRelationData; + +typedef EphemeralNamedRelationData *EphemeralNamedRelation; + +/* + * This is an opaque structure outside of queryenvironment.c itself. The + * intention is to be able to change the implementation or add new context + * features without needing to change existing code for use of existing + * features. + */ +typedef struct QueryEnvironment QueryEnvironment; + + +extern QueryEnvironment *create_queryEnv(void); +extern EphemeralNamedRelationMetadata get_visible_ENR_metadata(QueryEnvironment *queryEnv, const char *refname); +extern void register_ENR(QueryEnvironment *queryEnv, EphemeralNamedRelation enr); +extern void unregister_ENR(QueryEnvironment *queryEnv, const char *name); +extern EphemeralNamedRelation get_ENR(QueryEnvironment *queryEnv, const char *name); +extern TupleDesc ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd); + +#endif /* QUERYENVIRONMENT_H */ diff --git a/src/include/utils/queryjumble.h b/src/include/utils/queryjumble.h new file mode 100644 index 0000000..3c2d9be --- /dev/null +++ b/src/include/utils/queryjumble.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------- + * + * queryjumble.h + * Query normalization and fingerprinting. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/utils/queryjumble.h + * + *------------------------------------------------------------------------- + */ +#ifndef QUERYJUBLE_H +#define QUERYJUBLE_H + +#include "nodes/parsenodes.h" + +#define JUMBLE_SIZE 1024 /* query serialization buffer size */ + +/* + * Struct for tracking locations/lengths of constants during normalization + */ +typedef struct LocationLen +{ + int location; /* start offset in query text */ + int length; /* length in bytes, or -1 to ignore */ +} LocationLen; + +/* + * Working state for computing a query jumble and producing a normalized + * query string + */ +typedef struct JumbleState +{ + /* Jumble of current query tree */ + unsigned char *jumble; + + /* Number of bytes used in jumble[] */ + Size jumble_len; + + /* Array of locations of constants that should be removed */ + LocationLen *clocations; + + /* Allocated length of clocations array */ + int clocations_buf_size; + + /* Current number of valid entries in clocations array */ + int clocations_count; + + /* highest Param id we've seen, in order to start normalization correctly */ + int highest_extern_param_id; +} JumbleState; + +/* Values for the compute_query_id GUC */ +enum ComputeQueryIdType +{ + COMPUTE_QUERY_ID_OFF, + COMPUTE_QUERY_ID_ON, + COMPUTE_QUERY_ID_AUTO, + COMPUTE_QUERY_ID_REGRESS +}; + +/* GUC parameters */ +extern PGDLLIMPORT int compute_query_id; + + +extern const char *CleanQuerytext(const char *query, int *location, int *len); +extern JumbleState *JumbleQuery(Query *query, const char *querytext); +extern void EnableQueryId(void); + +extern PGDLLIMPORT bool query_id_enabled; + +/* + * Returns whether query identifier computation has been enabled, either + * directly in the GUC or by a module when the setting is 'auto'. + */ +static inline bool +IsQueryIdEnabled(void) +{ + if (compute_query_id == COMPUTE_QUERY_ID_OFF) + return false; + if (compute_query_id == COMPUTE_QUERY_ID_ON) + return true; + return query_id_enabled; +} + +#endif /* QUERYJUMBLE_H */ diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h new file mode 100644 index 0000000..993fad4 --- /dev/null +++ b/src/include/utils/rangetypes.h @@ -0,0 +1,151 @@ +/*------------------------------------------------------------------------- + * + * rangetypes.h + * Declarations for Postgres range types. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/rangetypes.h + * + *------------------------------------------------------------------------- + */ +#ifndef RANGETYPES_H +#define RANGETYPES_H + +#include "utils/typcache.h" + + +/* + * Ranges are varlena objects, so must meet the varlena convention that + * the first int32 of the object contains the total object size in bytes. + * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + Oid rangetypid; /* range type's own OID */ + /* Following the OID are zero to two bound values, then a flags byte */ +} RangeType; + +#define RANGE_EMPTY_LITERAL "empty" + +/* Use this macro in preference to fetching rangetypid field directly */ +#define RangeTypeGetOid(r) ((r)->rangetypid) + +/* A range's flags byte contains these bits: */ +#define RANGE_EMPTY 0x01 /* range is empty */ +#define RANGE_LB_INC 0x02 /* lower bound is inclusive */ +#define RANGE_UB_INC 0x04 /* upper bound is inclusive */ +#define RANGE_LB_INF 0x08 /* lower bound is -infinity */ +#define RANGE_UB_INF 0x10 /* upper bound is +infinity */ +#define RANGE_LB_NULL 0x20 /* lower bound is null (NOT USED) */ +#define RANGE_UB_NULL 0x40 /* upper bound is null (NOT USED) */ +#define RANGE_CONTAIN_EMPTY 0x80 /* marks a GiST internal-page entry whose + * subtree contains some empty ranges */ + +#define RANGE_HAS_LBOUND(flags) (!((flags) & (RANGE_EMPTY | \ + RANGE_LB_NULL | \ + RANGE_LB_INF))) + +#define RANGE_HAS_UBOUND(flags) (!((flags) & (RANGE_EMPTY | \ + RANGE_UB_NULL | \ + RANGE_UB_INF))) + +#define RangeIsEmpty(r) ((range_get_flags(r) & RANGE_EMPTY) != 0) +#define RangeIsOrContainsEmpty(r) \ + ((range_get_flags(r) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0) + + +/* Internal representation of either bound of a range (not what's on disk) */ +typedef struct +{ + Datum val; /* the bound value, if any */ + bool infinite; /* bound is +/- infinity */ + bool inclusive; /* bound is inclusive (vs exclusive) */ + bool lower; /* this is the lower (vs upper) bound */ +} RangeBound; + +/* + * fmgr macros for range type objects + */ +#define DatumGetRangeTypeP(X) ((RangeType *) PG_DETOAST_DATUM(X)) +#define DatumGetRangeTypePCopy(X) ((RangeType *) PG_DETOAST_DATUM_COPY(X)) +#define RangeTypePGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_RANGE_P(n) DatumGetRangeTypeP(PG_GETARG_DATUM(n)) +#define PG_GETARG_RANGE_P_COPY(n) DatumGetRangeTypePCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_RANGE_P(x) return RangeTypePGetDatum(x) + +/* Operator strategy numbers used in the GiST and SP-GiST range opclasses */ +/* Numbers are chosen to match up operator names with existing usages */ +#define RANGESTRAT_BEFORE RTLeftStrategyNumber +#define RANGESTRAT_OVERLEFT RTOverLeftStrategyNumber +#define RANGESTRAT_OVERLAPS RTOverlapStrategyNumber +#define RANGESTRAT_OVERRIGHT RTOverRightStrategyNumber +#define RANGESTRAT_AFTER RTRightStrategyNumber +#define RANGESTRAT_ADJACENT RTSameStrategyNumber +#define RANGESTRAT_CONTAINS RTContainsStrategyNumber +#define RANGESTRAT_CONTAINED_BY RTContainedByStrategyNumber +#define RANGESTRAT_CONTAINS_ELEM RTContainsElemStrategyNumber +#define RANGESTRAT_EQ RTEqualStrategyNumber + +/* + * prototypes for functions defined in rangetypes.c + */ + +extern bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val); + +/* internal versions of the above */ +extern bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_ne_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_after_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern bool range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); +extern RangeType *range_union_internal(TypeCacheEntry *typcache, RangeType *r1, + RangeType *r2, bool strict); +extern RangeType *range_minus_internal(TypeCacheEntry *typcache, RangeType *r1, + RangeType *r2); +extern RangeType *range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2); + +/* assorted support functions */ +extern TypeCacheEntry *range_get_typcache(FunctionCallInfo fcinfo, + Oid rngtypid); +extern RangeType *range_serialize(TypeCacheEntry *typcache, RangeBound *lower, + RangeBound *upper, bool empty); +extern void range_deserialize(TypeCacheEntry *typcache, const RangeType *range, + RangeBound *lower, RangeBound *upper, + bool *empty); +extern char range_get_flags(const RangeType *range); +extern void range_set_contain_empty(RangeType *range); +extern RangeType *make_range(TypeCacheEntry *typcache, RangeBound *lower, + RangeBound *upper, bool empty); +extern int range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1, + const RangeBound *b2); +extern int range_cmp_bound_values(TypeCacheEntry *typcache, const RangeBound *b1, + const RangeBound *b2); +extern int range_compare(const void *key1, const void *key2, void *arg); +extern bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound bound1, + RangeBound bound2); +extern RangeType *make_empty_range(TypeCacheEntry *typcache); +extern bool range_split_internal(TypeCacheEntry *typcache, const RangeType *r1, + const RangeType *r2, RangeType **output1, + RangeType **output2); + +#endif /* RANGETYPES_H */ diff --git a/src/include/utils/regproc.h b/src/include/utils/regproc.h new file mode 100644 index 0000000..a36ceba --- /dev/null +++ b/src/include/utils/regproc.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * regproc.h + * Functions for the built-in types regproc, regclass, regtype, etc. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/regproc.h + * + *------------------------------------------------------------------------- + */ +#ifndef REGPROC_H +#define REGPROC_H + +#include "nodes/pg_list.h" + +/* Control flags for format_procedure_extended */ +#define FORMAT_PROC_INVALID_AS_NULL 0x01 /* NULL if undefined */ +#define FORMAT_PROC_FORCE_QUALIFY 0x02 /* force qualification */ +extern char *format_procedure_extended(Oid procedure_oid, bits16 flags); + +/* Control flags for format_operator_extended */ +#define FORMAT_OPERATOR_INVALID_AS_NULL 0x01 /* NULL if undefined */ +#define FORMAT_OPERATOR_FORCE_QUALIFY 0x02 /* force qualification */ +extern char *format_operator_extended(Oid operator_oid, bits16 flags); + +extern List *stringToQualifiedNameList(const char *string); +extern char *format_procedure(Oid procedure_oid); +extern char *format_procedure_qualified(Oid procedure_oid); +extern void format_procedure_parts(Oid operator_oid, List **objnames, + List **objargs, bool missing_ok); + +extern char *format_operator(Oid operator_oid); +extern char *format_operator_qualified(Oid operator_oid); +extern void format_operator_parts(Oid operator_oid, List **objnames, + List **objargs, bool missing_ok); + +#endif diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h new file mode 100644 index 0000000..a1bc071 --- /dev/null +++ b/src/include/utils/rel.h @@ -0,0 +1,697 @@ +/*------------------------------------------------------------------------- + * + * rel.h + * POSTGRES relation descriptor (a/k/a relcache entry) definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/rel.h + * + *------------------------------------------------------------------------- + */ +#ifndef REL_H +#define REL_H + +#include "access/tupdesc.h" +#include "access/xlog.h" +#include "catalog/pg_class.h" +#include "catalog/pg_index.h" +#include "catalog/pg_publication.h" +#include "nodes/bitmapset.h" +#include "partitioning/partdefs.h" +#include "rewrite/prs2lock.h" +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "storage/smgr.h" +#include "utils/relcache.h" +#include "utils/reltrigger.h" + + +/* + * LockRelId and LockInfo really belong to lmgr.h, but it's more convenient + * to declare them here so we can have a LockInfoData field in a Relation. + */ + +typedef struct LockRelId +{ + Oid relId; /* a relation identifier */ + Oid dbId; /* a database identifier */ +} LockRelId; + +typedef struct LockInfoData +{ + LockRelId lockRelId; +} LockInfoData; + +typedef LockInfoData *LockInfo; + +/* + * Here are the contents of a relation cache entry. + */ + +typedef struct RelationData +{ + RelFileNode rd_node; /* relation physical identifier */ + SMgrRelation rd_smgr; /* cached file handle, or NULL */ + int rd_refcnt; /* reference count */ + BackendId rd_backend; /* owning backend id, if temporary relation */ + bool rd_islocaltemp; /* rel is a temp rel of this session */ + bool rd_isnailed; /* rel is nailed in cache */ + bool rd_isvalid; /* relcache entry is valid */ + bool rd_indexvalid; /* is rd_indexlist valid? (also rd_pkindex and + * rd_replidindex) */ + bool rd_statvalid; /* is rd_statlist valid? */ + + /*---------- + * rd_createSubid is the ID of the highest subtransaction the rel has + * survived into or zero if the rel or its rd_node was created before the + * current top transaction. (IndexStmt.oldNode leads to the case of a new + * rel with an old rd_node.) rd_firstRelfilenodeSubid is the ID of the + * highest subtransaction an rd_node change has survived into or zero if + * rd_node matches the value it had at the start of the current top + * transaction. (Rolling back the subtransaction that + * rd_firstRelfilenodeSubid denotes would restore rd_node to the value it + * had at the start of the current top transaction. Rolling back any + * lower subtransaction would not.) Their accuracy is critical to + * RelationNeedsWAL(). + * + * rd_newRelfilenodeSubid is the ID of the highest subtransaction the + * most-recent relfilenode change has survived into or zero if not changed + * in the current transaction (or we have forgotten changing it). This + * field is accurate when non-zero, but it can be zero when a relation has + * multiple new relfilenodes within a single transaction, with one of them + * occurring in a subsequently aborted subtransaction, e.g. + * BEGIN; + * TRUNCATE t; + * SAVEPOINT save; + * TRUNCATE t; + * ROLLBACK TO save; + * -- rd_newRelfilenodeSubid is now forgotten + * + * If every rd_*Subid field is zero, they are read-only outside + * relcache.c. Files that trigger rd_node changes by updating + * pg_class.reltablespace and/or pg_class.relfilenode call + * RelationAssumeNewRelfilenode() to update rd_*Subid. + * + * rd_droppedSubid is the ID of the highest subtransaction that a drop of + * the rel has survived into. In entries visible outside relcache.c, this + * is always zero. + */ + SubTransactionId rd_createSubid; /* rel was created in current xact */ + SubTransactionId rd_newRelfilenodeSubid; /* highest subxact changing + * rd_node to current value */ + SubTransactionId rd_firstRelfilenodeSubid; /* highest subxact changing + * rd_node to any value */ + SubTransactionId rd_droppedSubid; /* dropped with another Subid set */ + + Form_pg_class rd_rel; /* RELATION tuple */ + TupleDesc rd_att; /* tuple descriptor */ + Oid rd_id; /* relation's object id */ + LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */ + RuleLock *rd_rules; /* rewrite rules */ + MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ + TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ + /* use "struct" here to avoid needing to include rowsecurity.h: */ + struct RowSecurityDesc *rd_rsdesc; /* row security policies, or NULL */ + + /* data managed by RelationGetFKeyList: */ + List *rd_fkeylist; /* list of ForeignKeyCacheInfo (see below) */ + bool rd_fkeyvalid; /* true if list has been computed */ + + /* data managed by RelationGetPartitionKey: */ + PartitionKey rd_partkey; /* partition key, or NULL */ + MemoryContext rd_partkeycxt; /* private context for rd_partkey, if any */ + + /* data managed by RelationGetPartitionDesc: */ + PartitionDesc rd_partdesc; /* partition descriptor, or NULL */ + MemoryContext rd_pdcxt; /* private context for rd_partdesc, if any */ + + /* Same as above, for partdescs that omit detached partitions */ + PartitionDesc rd_partdesc_nodetached; /* partdesc w/o detached parts */ + MemoryContext rd_pddcxt; /* for rd_partdesc_nodetached, if any */ + + /* + * pg_inherits.xmin of the partition that was excluded in + * rd_partdesc_nodetached. This informs a future user of that partdesc: + * if this value is not in progress for the active snapshot, then the + * partdesc can be used, otherwise they have to build a new one. (This + * matches what find_inheritance_children_extended would do). + */ + TransactionId rd_partdesc_nodetached_xmin; + + /* data managed by RelationGetPartitionQual: */ + List *rd_partcheck; /* partition CHECK quals */ + bool rd_partcheckvalid; /* true if list has been computed */ + MemoryContext rd_partcheckcxt; /* private cxt for rd_partcheck, if any */ + + /* data managed by RelationGetIndexList: */ + List *rd_indexlist; /* list of OIDs of indexes on relation */ + Oid rd_pkindex; /* OID of primary key, if any */ + Oid rd_replidindex; /* OID of replica identity index, if any */ + + /* data managed by RelationGetStatExtList: */ + List *rd_statlist; /* list of OIDs of extended stats */ + + /* data managed by RelationGetIndexAttrBitmap: */ + Bitmapset *rd_indexattr; /* identifies columns used in indexes */ + Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ + Bitmapset *rd_pkattr; /* cols included in primary key */ + Bitmapset *rd_idattr; /* included in replica identity index */ + + PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */ + + /* + * rd_options is set whenever rd_rel is loaded into the relcache entry. + * Note that you can NOT look into rd_rel for this data. NULL means "use + * defaults". + */ + bytea *rd_options; /* parsed pg_class.reloptions */ + + /* + * Oid of the handler for this relation. For an index this is a function + * returning IndexAmRoutine, for table like relations a function returning + * TableAmRoutine. This is stored separately from rd_indam, rd_tableam as + * its lookup requires syscache access, but during relcache bootstrap we + * need to be able to initialize rd_tableam without syscache lookups. + */ + Oid rd_amhandler; /* OID of index AM's handler function */ + + /* + * Table access method. + */ + const struct TableAmRoutine *rd_tableam; + + /* These are non-NULL only for an index relation: */ + Form_pg_index rd_index; /* pg_index tuple describing this index */ + /* use "struct" here to avoid needing to include htup.h: */ + struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ + + /* + * index access support info (used only for an index relation) + * + * Note: only default support procs for each opclass are cached, namely + * those with lefttype and righttype equal to the opclass's opcintype. The + * arrays are indexed by support function number, which is a sufficient + * identifier given that restriction. + */ + MemoryContext rd_indexcxt; /* private memory cxt for this stuff */ + /* use "struct" here to avoid needing to include amapi.h: */ + struct IndexAmRoutine *rd_indam; /* index AM's API struct */ + Oid *rd_opfamily; /* OIDs of op families for each index col */ + Oid *rd_opcintype; /* OIDs of opclass declared input data types */ + RegProcedure *rd_support; /* OIDs of support procedures */ + struct FmgrInfo *rd_supportinfo; /* lookup info for support procedures */ + int16 *rd_indoption; /* per-column AM-specific flags */ + List *rd_indexprs; /* index expression trees, if any */ + List *rd_indpred; /* index predicate tree, if any */ + Oid *rd_exclops; /* OIDs of exclusion operators, if any */ + Oid *rd_exclprocs; /* OIDs of exclusion ops' procs, if any */ + uint16 *rd_exclstrats; /* exclusion ops' strategy numbers, if any */ + Oid *rd_indcollation; /* OIDs of index collations */ + bytea **rd_opcoptions; /* parsed opclass-specific options */ + + /* + * rd_amcache is available for index and table AMs to cache private data + * about the relation. This must be just a cache since it may get reset + * at any time (in particular, it will get reset by a relcache inval + * message for the relation). If used, it must point to a single memory + * chunk palloc'd in CacheMemoryContext, or in rd_indexcxt for an index + * relation. A relcache reset will include freeing that chunk and setting + * rd_amcache = NULL. + */ + void *rd_amcache; /* available for use by index/table AM */ + + /* + * foreign-table support + * + * rd_fdwroutine must point to a single memory chunk palloc'd in + * CacheMemoryContext. It will be freed and reset to NULL on a relcache + * reset. + */ + + /* use "struct" here to avoid needing to include fdwapi.h: */ + struct FdwRoutine *rd_fdwroutine; /* cached function pointers, or NULL */ + + /* + * Hack for CLUSTER, rewriting ALTER TABLE, etc: when writing a new + * version of a table, we need to make any toast pointers inserted into it + * have the existing toast table's OID, not the OID of the transient toast + * table. If rd_toastoid isn't InvalidOid, it is the OID to place in + * toast pointers inserted into this rel. (Note it's set on the new + * version of the main heap, not the toast table itself.) This also + * causes toast_save_datum() to try to preserve toast value OIDs. + */ + Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */ + + bool pgstat_enabled; /* should relation stats be counted */ + /* use "struct" here to avoid needing to include pgstat.h: */ + struct PgStat_TableStatus *pgstat_info; /* statistics collection area */ +} RelationData; + + +/* + * ForeignKeyCacheInfo + * Information the relcache can cache about foreign key constraints + * + * This is basically just an image of relevant columns from pg_constraint. + * We make it a subclass of Node so that copyObject() can be used on a list + * of these, but we also ensure it is a "flat" object without substructure, + * so that list_free_deep() is sufficient to free such a list. + * The per-FK-column arrays can be fixed-size because we allow at most + * INDEX_MAX_KEYS columns in a foreign key constraint. + * + * Currently, we mostly cache fields of interest to the planner, but the set + * of fields has already grown the constraint OID for other uses. + */ +typedef struct ForeignKeyCacheInfo +{ + NodeTag type; + Oid conoid; /* oid of the constraint itself */ + Oid conrelid; /* relation constrained by the foreign key */ + Oid confrelid; /* relation referenced by the foreign key */ + int nkeys; /* number of columns in the foreign key */ + /* these arrays each have nkeys valid entries: */ + AttrNumber conkey[INDEX_MAX_KEYS]; /* cols in referencing table */ + AttrNumber confkey[INDEX_MAX_KEYS]; /* cols in referenced table */ + Oid conpfeqop[INDEX_MAX_KEYS]; /* PK = FK operator OIDs */ +} ForeignKeyCacheInfo; + + +/* + * StdRdOptions + * Standard contents of rd_options for heaps. + * + * 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 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!) */ + int fillfactor; /* page fill factor in percent (0..100) */ + int toast_tuple_target; /* target for tuple toasting */ + 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 */ +} StdRdOptions; + +#define HEAP_MIN_FILLFACTOR 10 +#define HEAP_DEFAULT_FILLFACTOR 100 + +/* + * RelationGetToastTupleTarget + * Returns the relation's toast_tuple_target. Note multiple eval of argument! + */ +#define RelationGetToastTupleTarget(relation, defaulttarg) \ + ((relation)->rd_options ? \ + ((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg)) + +/* + * RelationGetFillFactor + * 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. + */ +#define RelationGetTargetPageUsage(relation, defaultff) \ + (BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100) + +/* + * RelationGetTargetPageFreeSpace + * Returns the relation's desired freespace per page in bytes. + */ +#define RelationGetTargetPageFreeSpace(relation, defaultff) \ + (BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100) + +/* + * RelationIsUsedAsCatalogTable + * Returns whether the relation should be treated as a catalog table + * from the pov of logical decoding. Note multiple eval of argument! + */ +#define RelationIsUsedAsCatalogTable(relation) \ + ((relation)->rd_options && \ + ((relation)->rd_rel->relkind == RELKIND_RELATION || \ + (relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \ + ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false) + +/* + * RelationGetParallelWorkers + * Returns the relation's parallel_workers reloption setting. + * Note multiple eval of argument! + */ +#define RelationGetParallelWorkers(relation, defaultpw) \ + ((relation)->rd_options ? \ + ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw)) + +/* ViewOptions->check_option values */ +typedef enum ViewOptCheckOption +{ + VIEW_OPTION_CHECK_OPTION_NOT_SET, + VIEW_OPTION_CHECK_OPTION_LOCAL, + VIEW_OPTION_CHECK_OPTION_CASCADED +} ViewOptCheckOption; + +/* + * ViewOptions + * Contents of rd_options for views + */ +typedef struct ViewOptions +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + bool security_barrier; + bool security_invoker; + ViewOptCheckOption check_option; +} ViewOptions; + +/* + * RelationIsSecurityView + * Returns whether the relation is security view, or not. Note multiple + * eval of argument! + */ +#define RelationIsSecurityView(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + (relation)->rd_options ? \ + ((ViewOptions *) (relation)->rd_options)->security_barrier : false) + +/* + * RelationHasSecurityInvoker + * Returns true if the relation has the security_invoker property set. + * Note multiple eval of argument! + */ +#define RelationHasSecurityInvoker(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + (relation)->rd_options ? \ + ((ViewOptions *) (relation)->rd_options)->security_invoker : false) + +/* + * RelationHasCheckOption + * Returns true if the relation is a view defined with either the local + * or the cascaded check option. Note multiple eval of argument! + */ +#define RelationHasCheckOption(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + (relation)->rd_options && \ + ((ViewOptions *) (relation)->rd_options)->check_option != \ + VIEW_OPTION_CHECK_OPTION_NOT_SET) + +/* + * RelationHasLocalCheckOption + * Returns true if the relation is a view defined with the local check + * option. Note multiple eval of argument! + */ +#define RelationHasLocalCheckOption(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + (relation)->rd_options && \ + ((ViewOptions *) (relation)->rd_options)->check_option == \ + VIEW_OPTION_CHECK_OPTION_LOCAL) + +/* + * RelationHasCascadedCheckOption + * Returns true if the relation is a view defined with the cascaded check + * option. Note multiple eval of argument! + */ +#define RelationHasCascadedCheckOption(relation) \ + (AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW), \ + (relation)->rd_options && \ + ((ViewOptions *) (relation)->rd_options)->check_option == \ + VIEW_OPTION_CHECK_OPTION_CASCADED) + +/* + * RelationIsValid + * True iff relation descriptor is valid. + */ +#define RelationIsValid(relation) PointerIsValid(relation) + +#define InvalidRelation ((Relation) NULL) + +/* + * RelationHasReferenceCountZero + * True iff relation reference count is zero. + * + * Note: + * Assumes relation descriptor is valid. + */ +#define RelationHasReferenceCountZero(relation) \ + ((bool)((relation)->rd_refcnt == 0)) + +/* + * RelationGetForm + * Returns pg_class tuple for a relation. + * + * Note: + * Assumes relation descriptor is valid. + */ +#define RelationGetForm(relation) ((relation)->rd_rel) + +/* + * RelationGetRelid + * Returns the OID of the relation + */ +#define RelationGetRelid(relation) ((relation)->rd_id) + +/* + * RelationGetNumberOfAttributes + * Returns the total number of attributes in a relation. + */ +#define RelationGetNumberOfAttributes(relation) ((relation)->rd_rel->relnatts) + +/* + * IndexRelationGetNumberOfAttributes + * Returns the number of attributes in an index. + */ +#define IndexRelationGetNumberOfAttributes(relation) \ + ((relation)->rd_index->indnatts) + +/* + * IndexRelationGetNumberOfKeyAttributes + * Returns the number of key attributes in an index. + */ +#define IndexRelationGetNumberOfKeyAttributes(relation) \ + ((relation)->rd_index->indnkeyatts) + +/* + * RelationGetDescr + * Returns tuple descriptor for a relation. + */ +#define RelationGetDescr(relation) ((relation)->rd_att) + +/* + * RelationGetRelationName + * Returns the rel's name. + * + * Note that the name is only unique within the containing namespace. + */ +#define RelationGetRelationName(relation) \ + (NameStr((relation)->rd_rel->relname)) + +/* + * RelationGetNamespace + * Returns the rel's namespace OID. + */ +#define RelationGetNamespace(relation) \ + ((relation)->rd_rel->relnamespace) + +/* + * RelationIsMapped + * True if the relation uses the relfilenode map. Note multiple eval + * of argument! + */ +#define RelationIsMapped(relation) \ + (RELKIND_HAS_STORAGE((relation)->rd_rel->relkind) && \ + ((relation)->rd_rel->relfilenode == InvalidOid)) + +#ifndef FRONTEND +/* + * RelationGetSmgr + * Returns smgr file handle for a relation, opening it if needed. + * + * Very little code is authorized to touch rel->rd_smgr directly. Instead + * use this function to fetch its value. + * + * Note: since a relcache flush can cause the file handle to be closed again, + * it's unwise to hold onto the pointer returned by this function for any + * long period. Recommended practice is to just re-execute RelationGetSmgr + * each time you need to access the SMgrRelation. It's quite cheap in + * comparison to whatever an smgr function is going to do. + */ +static inline SMgrRelation +RelationGetSmgr(Relation rel) +{ + if (unlikely(rel->rd_smgr == NULL)) + smgrsetowner(&(rel->rd_smgr), smgropen(rel->rd_node, rel->rd_backend)); + return rel->rd_smgr; +} +#endif /* !FRONTEND */ + +/* + * RelationCloseSmgr + * Close the relation at the smgr level, if not already done. + * + * Note: smgrclose should unhook from owner pointer, hence the Assert. + */ +#define RelationCloseSmgr(relation) \ + do { \ + if ((relation)->rd_smgr != NULL) \ + { \ + smgrclose((relation)->rd_smgr); \ + Assert((relation)->rd_smgr == NULL); \ + } \ + } while (0) + +/* + * RelationGetTargetBlock + * Fetch relation's current insertion target block. + * + * Returns InvalidBlockNumber if there is no current target block. Note + * that the target block status is discarded on any smgr-level invalidation, + * so there's no need to re-open the smgr handle if it's not currently open. + */ +#define RelationGetTargetBlock(relation) \ + ( (relation)->rd_smgr != NULL ? (relation)->rd_smgr->smgr_targblock : InvalidBlockNumber ) + +/* + * RelationSetTargetBlock + * Set relation's current insertion target block. + */ +#define RelationSetTargetBlock(relation, targblock) \ + do { \ + RelationGetSmgr(relation)->smgr_targblock = (targblock); \ + } while (0) + +/* + * RelationIsPermanent + * True if relation is permanent. + */ +#define RelationIsPermanent(relation) \ + ((relation)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT) + +/* + * RelationNeedsWAL + * True if relation needs WAL. + * + * Returns false if wal_level = minimal and this relation is created or + * truncated in the current transaction. See "Skipping WAL for New + * RelFileNode" in src/backend/access/transam/README. + */ +#define RelationNeedsWAL(relation) \ + (RelationIsPermanent(relation) && (XLogIsNeeded() || \ + (relation->rd_createSubid == InvalidSubTransactionId && \ + relation->rd_firstRelfilenodeSubid == InvalidSubTransactionId))) + +/* + * RelationUsesLocalBuffers + * True if relation's pages are stored in local buffers. + */ +#define RelationUsesLocalBuffers(relation) \ + ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP) + +/* + * RELATION_IS_LOCAL + * If a rel is either temp or newly created in the current transaction, + * it can be assumed to be accessible only to the current backend. + * This is typically used to decide that we can skip acquiring locks. + * + * Beware of multiple eval of argument + */ +#define RELATION_IS_LOCAL(relation) \ + ((relation)->rd_islocaltemp || \ + (relation)->rd_createSubid != InvalidSubTransactionId) + +/* + * RELATION_IS_OTHER_TEMP + * Test for a temporary relation that belongs to some other session. + * + * Beware of multiple eval of argument + */ +#define RELATION_IS_OTHER_TEMP(relation) \ + ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP && \ + !(relation)->rd_islocaltemp) + + +/* + * RelationIsScannable + * Currently can only be false for a materialized view which has not been + * populated by its query. This is likely to get more complicated later, + * so use a macro which looks like a function. + */ +#define RelationIsScannable(relation) ((relation)->rd_rel->relispopulated) + +/* + * RelationIsPopulated + * Currently, we don't physically distinguish the "populated" and + * "scannable" properties of matviews, but that may change later. + * Hence, use the appropriate one of these macros in code tests. + */ +#define RelationIsPopulated(relation) ((relation)->rd_rel->relispopulated) + +/* + * RelationIsAccessibleInLogicalDecoding + * True if we need to log enough information to have access via + * decoding snapshot. + */ +#define RelationIsAccessibleInLogicalDecoding(relation) \ + (XLogLogicalInfoActive() && \ + RelationNeedsWAL(relation) && \ + (IsCatalogRelation(relation) || RelationIsUsedAsCatalogTable(relation))) + +/* + * RelationIsLogicallyLogged + * True if we need to log enough information to extract the data from the + * WAL stream. + * + * We don't log information for unlogged tables (since they don't WAL log + * anyway), for foreign tables (since they don't WAL log, either), + * and for system tables (their content is hard to make sense of, and + * it would complicate decoding slightly for little gain). Note that we *do* + * log information for user defined catalog tables since they presumably are + * interesting to the user... + */ +#define RelationIsLogicallyLogged(relation) \ + (XLogLogicalInfoActive() && \ + RelationNeedsWAL(relation) && \ + (relation)->rd_rel->relkind != RELKIND_FOREIGN_TABLE && \ + !IsCatalogRelation(relation)) + +/* routines in utils/cache/relcache.c */ +extern void RelationIncrementReferenceCount(Relation rel); +extern void RelationDecrementReferenceCount(Relation rel); + +#endif /* REL_H */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h new file mode 100644 index 0000000..c93d865 --- /dev/null +++ b/src/include/utils/relcache.h @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- + * + * relcache.h + * Relation descriptor cache definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELCACHE_H +#define RELCACHE_H + +#include "access/tupdesc.h" +#include "nodes/bitmapset.h" + + +/* + * Name of relcache init file(s), used to speed up backend startup + */ +#define RELCACHE_INIT_FILENAME "pg_internal.init" + +typedef struct RelationData *Relation; + +/* ---------------- + * RelationPtr is used in the executor to support index scans + * where we have to keep track of several index relations in an + * array. -cim 9/10/89 + * ---------------- + */ +typedef Relation *RelationPtr; + +/* + * Routines to open (lookup) and close a relcache entry + */ +extern Relation RelationIdGetRelation(Oid relationId); +extern void RelationClose(Relation relation); + +/* + * Routines to compute/retrieve additional cached information + */ +extern List *RelationGetFKeyList(Relation relation); +extern List *RelationGetIndexList(Relation relation); +extern List *RelationGetStatExtList(Relation relation); +extern Oid RelationGetPrimaryKeyIndex(Relation relation); +extern Oid RelationGetReplicaIndex(Relation relation); +extern List *RelationGetIndexExpressions(Relation relation); +extern List *RelationGetDummyIndexExpressions(Relation relation); +extern List *RelationGetIndexPredicate(Relation relation); +extern Datum *RelationGetIndexRawAttOptions(Relation relation); +extern bytea **RelationGetIndexAttOptions(Relation relation, bool copy); + +typedef enum IndexAttrBitmapKind +{ + INDEX_ATTR_BITMAP_ALL, + INDEX_ATTR_BITMAP_KEY, + INDEX_ATTR_BITMAP_PRIMARY_KEY, + INDEX_ATTR_BITMAP_IDENTITY_KEY +} IndexAttrBitmapKind; + +extern Bitmapset *RelationGetIndexAttrBitmap(Relation relation, + IndexAttrBitmapKind attrKind); + +extern Bitmapset *RelationGetIdentityKeyBitmap(Relation relation); + +extern void RelationGetExclusionInfo(Relation indexRelation, + Oid **operators, + Oid **procs, + uint16 **strategies); + +extern void RelationInitIndexAccessInfo(Relation relation); + +/* caller must include pg_publication.h */ +struct PublicationDesc; +extern void RelationBuildPublicationDesc(Relation relation, + struct PublicationDesc *pubdesc); + +extern void RelationInitTableAccessMethod(Relation relation); + +/* + * Routines to support ereport() reports of relation-related errors + */ +extern int errtable(Relation rel); +extern int errtablecol(Relation rel, int attnum); +extern int errtablecolname(Relation rel, const char *colname); +extern int errtableconstraint(Relation rel, const char *conname); + +/* + * Routines for backend startup + */ +extern void RelationCacheInitialize(void); +extern void RelationCacheInitializePhase2(void); +extern void RelationCacheInitializePhase3(void); + +/* + * Routine to create a relcache entry for an about-to-be-created relation + */ +extern Relation RelationBuildLocalRelation(const char *relname, + Oid relnamespace, + TupleDesc tupDesc, + Oid relid, + Oid accessmtd, + Oid relfilenode, + Oid reltablespace, + bool shared_relation, + bool mapped_relation, + char relpersistence, + char relkind); + +/* + * Routines to manage assignment of new relfilenode to a relation + */ +extern void RelationSetNewRelfilenode(Relation relation, char persistence); +extern void RelationAssumeNewRelfilenode(Relation relation); + +/* + * Routines for flushing/rebuilding relcache entries in various scenarios + */ +extern void RelationForgetRelation(Oid rid); + +extern void RelationCacheInvalidateEntry(Oid relationId); + +extern void RelationCacheInvalidate(bool debug_discard); + +extern void RelationCloseSmgrByOid(Oid relationId); + +#ifdef USE_ASSERT_CHECKING +extern void AssertPendingSyncs_RelationCache(void); +#else +#define AssertPendingSyncs_RelationCache() do {} while (0) +#endif +extern void AtEOXact_RelationCache(bool isCommit); +extern void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid, + SubTransactionId parentSubid); + +/* + * Routines to help manage rebuilding of relcache init files + */ +extern bool RelationIdIsInInitFile(Oid relationId); +extern void RelationCacheInitFilePreInvalidate(void); +extern void RelationCacheInitFilePostInvalidate(void); +extern void RelationCacheInitFileRemove(void); + +/* should be used only by relcache.c and catcache.c */ +extern PGDLLIMPORT bool criticalRelcachesBuilt; + +/* should be used only by relcache.c and postinit.c */ +extern PGDLLIMPORT bool criticalSharedRelcachesBuilt; + +#endif /* RELCACHE_H */ diff --git a/src/include/utils/relfilenodemap.h b/src/include/utils/relfilenodemap.h new file mode 100644 index 0000000..77d8046 --- /dev/null +++ b/src/include/utils/relfilenodemap.h @@ -0,0 +1,18 @@ +/*------------------------------------------------------------------------- + * + * relfilenodemap.h + * relfilenode to oid mapping cache. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relfilenodemap.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELFILENODEMAP_H +#define RELFILENODEMAP_H + +extern Oid RelidByRelfilenode(Oid reltablespace, Oid relfilenode); + +#endif /* RELFILENODEMAP_H */ diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h new file mode 100644 index 0000000..557f77e --- /dev/null +++ b/src/include/utils/relmapper.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- + * + * relmapper.h + * Catalog-to-filenode mapping + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relmapper.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELMAPPER_H +#define RELMAPPER_H + +#include "access/xlogreader.h" +#include "lib/stringinfo.h" + +/* ---------------- + * relmap-related XLOG entries + * ---------------- + */ + +#define XLOG_RELMAP_UPDATE 0x00 + +typedef struct xl_relmap_update +{ + Oid dbid; /* database ID, or 0 for shared map */ + Oid tsid; /* database's tablespace, or pg_global */ + int32 nbytes; /* size of relmap data */ + char data[FLEXIBLE_ARRAY_MEMBER]; +} xl_relmap_update; + +#define MinSizeOfRelmapUpdate offsetof(xl_relmap_update, data) + + +extern Oid RelationMapOidToFilenode(Oid relationId, bool shared); + +extern Oid RelationMapFilenodeToOid(Oid relationId, bool shared); +extern Oid RelationMapOidToFilenodeForDatabase(char *dbpath, Oid relationId); +extern void RelationMapCopy(Oid dbid, Oid tsid, char *srcdbpath, + char *dstdbpath); +extern void RelationMapUpdateMap(Oid relationId, Oid fileNode, bool shared, + bool immediate); + +extern void RelationMapRemoveMapping(Oid relationId); + +extern void RelationMapInvalidate(bool shared); +extern void RelationMapInvalidateAll(void); + +extern void AtCCI_RelationMap(void); +extern void AtEOXact_RelationMap(bool isCommit, bool isParallelWorker); +extern void AtPrepare_RelationMap(void); + +extern void CheckPointRelationMap(void); + +extern void RelationMapFinishBootstrap(void); + +extern void RelationMapInitialize(void); +extern void RelationMapInitializePhase2(void); +extern void RelationMapInitializePhase3(void); + +extern Size EstimateRelationMapSpace(void); +extern void SerializeRelationMap(Size maxSize, char *startAddress); +extern void RestoreRelationMap(char *startAddress); + +extern void relmap_redo(XLogReaderState *record); +extern void relmap_desc(StringInfo buf, XLogReaderState *record); +extern const char *relmap_identify(uint8 info); + +#endif /* RELMAPPER_H */ diff --git a/src/include/utils/relptr.h b/src/include/utils/relptr.h new file mode 100644 index 0000000..9364dd6 --- /dev/null +++ b/src/include/utils/relptr.h @@ -0,0 +1,93 @@ +/*------------------------------------------------------------------------- + * + * relptr.h + * This file contains basic declarations for relative pointers. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relptr.h + * + *------------------------------------------------------------------------- + */ + +#ifndef RELPTR_H +#define RELPTR_H + +/* + * Relative pointers are intended to be used when storing an address that may + * be relative either to the base of the process's address space or some + * dynamic shared memory segment mapped therein. + * + * The idea here is that you declare a relative pointer as relptr(type) + * and then use relptr_access to dereference it and relptr_store to change + * it. The use of a union here is a hack, because what's stored in the + * relptr is always a Size, never an actual pointer. But including a pointer + * in the union allows us to use stupid macro tricks to provide some measure + * of type-safety. + */ +#define relptr(type) union { type *relptr_type; Size relptr_off; } + +/* + * pgindent gets confused by declarations that use "relptr(type)" directly, + * so preferred style is to write + * typedef struct ... SomeStruct; + * relptr_declare(SomeStruct, RelptrSomeStruct); + * and then declare pointer variables as "RelptrSomeStruct someptr". + */ +#define relptr_declare(type, relptrtype) \ + typedef relptr(type) relptrtype + +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define relptr_access(base, rp) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (__typeof__((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \ + (base) + (rp).relptr_off - 1)) +#else +/* + * If we don't have __builtin_types_compatible_p, assume we might not have + * __typeof__ either. + */ +#define relptr_access(base, rp) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (void *) ((rp).relptr_off == 0 ? NULL : (base) + (rp).relptr_off - 1)) +#endif + +#define relptr_is_null(rp) \ + ((rp).relptr_off == 0) + +#define relptr_offset(rp) \ + ((rp).relptr_off - 1) + +/* We use this inline to avoid double eval of "val" in relptr_store */ +static inline Size +relptr_store_eval(char *base, char *val) +{ + if (val == NULL) + return 0; + else + { + Assert(val >= base); + return val - base + 1; + } +} + +#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P +#define relptr_store(base, rp, val) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \ + (rp).relptr_off = relptr_store_eval((base), (char *) (val))) +#else +/* + * If we don't have __builtin_types_compatible_p, assume we might not have + * __typeof__ either. + */ +#define relptr_store(base, rp, val) \ + (AssertVariableIsOfTypeMacro(base, char *), \ + (rp).relptr_off = relptr_store_eval((base), (char *) (val))) +#endif + +#define relptr_copy(rp1, rp2) \ + ((rp1).relptr_off = (rp2).relptr_off) + +#endif /* RELPTR_H */ diff --git a/src/include/utils/reltrigger.h b/src/include/utils/reltrigger.h new file mode 100644 index 0000000..9bac164 --- /dev/null +++ b/src/include/utils/reltrigger.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * reltrigger.h + * POSTGRES relation trigger definitions. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/reltrigger.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELTRIGGER_H +#define RELTRIGGER_H + + +/* + * These struct really belongs to trigger.h, but we put it separately so that + * it can be cleanly included in rel.h and other places. + */ + +typedef struct Trigger +{ + Oid tgoid; /* OID of trigger (pg_trigger row) */ + /* Remaining fields are copied from pg_trigger, see pg_trigger.h */ + char *tgname; + Oid tgfoid; + int16 tgtype; + char tgenabled; + bool tgisinternal; + bool tgisclone; + Oid tgconstrrelid; + Oid tgconstrindid; + Oid tgconstraint; + bool tgdeferrable; + bool tginitdeferred; + int16 tgnargs; + int16 tgnattr; + int16 *tgattr; + char **tgargs; + char *tgqual; + char *tgoldtable; + char *tgnewtable; +} Trigger; + +typedef struct TriggerDesc +{ + Trigger *triggers; /* array of Trigger structs */ + int numtriggers; /* number of array entries */ + + /* + * These flags indicate whether the array contains at least one of each + * type of trigger. We use these to skip searching the array if not. + */ + bool trig_insert_before_row; + bool trig_insert_after_row; + bool trig_insert_instead_row; + bool trig_insert_before_statement; + bool trig_insert_after_statement; + bool trig_update_before_row; + bool trig_update_after_row; + bool trig_update_instead_row; + bool trig_update_before_statement; + bool trig_update_after_statement; + bool trig_delete_before_row; + bool trig_delete_after_row; + bool trig_delete_instead_row; + bool trig_delete_before_statement; + bool trig_delete_after_statement; + /* there are no row-level truncate triggers */ + bool trig_truncate_before_statement; + bool trig_truncate_after_statement; + /* Is there at least one trigger specifying each transition relation? */ + bool trig_insert_new_table; + bool trig_update_old_table; + bool trig_update_new_table; + bool trig_delete_old_table; +} TriggerDesc; + +#endif /* RELTRIGGER_H */ diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h new file mode 100644 index 0000000..4aff701 --- /dev/null +++ b/src/include/utils/resowner.h @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------- + * + * resowner.h + * POSTGRES resource owner definitions. + * + * Query-lifespan resources are tracked by associating them with + * ResourceOwner objects. This provides a simple mechanism for ensuring + * that such resources are freed at the right time. + * See utils/resowner/README for more info. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/resowner.h + * + *------------------------------------------------------------------------- + */ +#ifndef RESOWNER_H +#define RESOWNER_H + + +/* + * ResourceOwner objects are an opaque data structure known only within + * resowner.c. + */ +typedef struct ResourceOwnerData *ResourceOwner; + + +/* + * Globally known ResourceOwners + */ +extern PGDLLIMPORT ResourceOwner CurrentResourceOwner; +extern PGDLLIMPORT ResourceOwner CurTransactionResourceOwner; +extern PGDLLIMPORT ResourceOwner TopTransactionResourceOwner; +extern PGDLLIMPORT ResourceOwner AuxProcessResourceOwner; + +/* + * Resource releasing is done in three phases: pre-locks, locks, and + * post-locks. The pre-lock phase must release any resources that are + * visible to other backends (such as pinned buffers); this ensures that + * when we release a lock that another backend may be waiting on, it will + * see us as being fully out of our transaction. The post-lock phase + * should be used for backend-internal cleanup. + */ +typedef enum +{ + RESOURCE_RELEASE_BEFORE_LOCKS, + RESOURCE_RELEASE_LOCKS, + RESOURCE_RELEASE_AFTER_LOCKS +} ResourceReleasePhase; + +/* + * Dynamically loaded modules can get control during ResourceOwnerRelease + * by providing a callback of this form. + */ +typedef void (*ResourceReleaseCallback) (ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg); + + +/* + * Functions in resowner.c + */ + +/* generic routines */ +extern ResourceOwner ResourceOwnerCreate(ResourceOwner parent, + const char *name); +extern void ResourceOwnerRelease(ResourceOwner owner, + ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel); +extern void ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner); +extern void ResourceOwnerDelete(ResourceOwner owner); +extern ResourceOwner ResourceOwnerGetParent(ResourceOwner owner); +extern void ResourceOwnerNewParent(ResourceOwner owner, + ResourceOwner newparent); +extern void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, + void *arg); +extern void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, + void *arg); +extern void CreateAuxProcessResourceOwner(void); +extern void ReleaseAuxProcessResources(bool isCommit); + +#endif /* RESOWNER_H */ diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h new file mode 100644 index 0000000..d01cccc --- /dev/null +++ b/src/include/utils/resowner_private.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- + * + * resowner_private.h + * POSTGRES resource owner private definitions. + * + * See utils/resowner/README for more info. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/resowner_private.h + * + *------------------------------------------------------------------------- + */ +#ifndef RESOWNER_PRIVATE_H +#define RESOWNER_PRIVATE_H + +#include "storage/dsm.h" +#include "storage/fd.h" +#include "storage/lock.h" +#include "utils/catcache.h" +#include "utils/plancache.h" +#include "utils/resowner.h" +#include "utils/snapshot.h" + + +/* support for buffer refcount management */ +extern void ResourceOwnerEnlargeBuffers(ResourceOwner owner); +extern void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer); +extern void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer); + +/* support for local lock management */ +extern void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock); +extern void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock); + +/* support for catcache refcount management */ +extern void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner); +extern void ResourceOwnerRememberCatCacheRef(ResourceOwner owner, + HeapTuple tuple); +extern void ResourceOwnerForgetCatCacheRef(ResourceOwner owner, + HeapTuple tuple); +extern void ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner); +extern void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, + CatCList *list); +extern void ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, + CatCList *list); + +/* support for relcache refcount management */ +extern void ResourceOwnerEnlargeRelationRefs(ResourceOwner owner); +extern void ResourceOwnerRememberRelationRef(ResourceOwner owner, + Relation rel); +extern void ResourceOwnerForgetRelationRef(ResourceOwner owner, + Relation rel); + +/* support for plancache refcount management */ +extern void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner); +extern void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, + CachedPlan *plan); +extern void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, + CachedPlan *plan); + +/* support for tupledesc refcount management */ +extern void ResourceOwnerEnlargeTupleDescs(ResourceOwner owner); +extern void ResourceOwnerRememberTupleDesc(ResourceOwner owner, + TupleDesc tupdesc); +extern void ResourceOwnerForgetTupleDesc(ResourceOwner owner, + TupleDesc tupdesc); + +/* support for snapshot refcount management */ +extern void ResourceOwnerEnlargeSnapshots(ResourceOwner owner); +extern void ResourceOwnerRememberSnapshot(ResourceOwner owner, + Snapshot snapshot); +extern void ResourceOwnerForgetSnapshot(ResourceOwner owner, + Snapshot snapshot); + +/* support for temporary file management */ +extern void ResourceOwnerEnlargeFiles(ResourceOwner owner); +extern void ResourceOwnerRememberFile(ResourceOwner owner, + File file); +extern void ResourceOwnerForgetFile(ResourceOwner owner, + File file); + +/* support for dynamic shared memory management */ +extern void ResourceOwnerEnlargeDSMs(ResourceOwner owner); +extern void ResourceOwnerRememberDSM(ResourceOwner owner, + dsm_segment *); +extern void ResourceOwnerForgetDSM(ResourceOwner owner, + dsm_segment *); + +/* support for JITContext management */ +extern void ResourceOwnerEnlargeJIT(ResourceOwner owner); +extern void ResourceOwnerRememberJIT(ResourceOwner owner, + Datum handle); +extern void ResourceOwnerForgetJIT(ResourceOwner owner, + Datum handle); + +/* support for cryptohash context management */ +extern void ResourceOwnerEnlargeCryptoHash(ResourceOwner owner); +extern void ResourceOwnerRememberCryptoHash(ResourceOwner owner, + Datum handle); +extern void ResourceOwnerForgetCryptoHash(ResourceOwner owner, + Datum handle); + +/* support for HMAC context management */ +extern void ResourceOwnerEnlargeHMAC(ResourceOwner owner); +extern void ResourceOwnerRememberHMAC(ResourceOwner owner, + Datum handle); +extern void ResourceOwnerForgetHMAC(ResourceOwner owner, + Datum handle); + +#endif /* RESOWNER_PRIVATE_H */ diff --git a/src/include/utils/rls.h b/src/include/utils/rls.h new file mode 100644 index 0000000..75259cc --- /dev/null +++ b/src/include/utils/rls.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------- + * + * rls.h + * Header file for Row Level Security (RLS) utility commands to be used + * with the rowsecurity feature. + * + * Copyright (c) 2007-2022, PostgreSQL Global Development Group + * + * src/include/utils/rls.h + * + *------------------------------------------------------------------------- + */ +#ifndef RLS_H +#define RLS_H + +/* GUC variable */ +extern PGDLLIMPORT bool row_security; + +/* + * Used by callers of check_enable_rls. + * + * RLS could be completely disabled on the tables involved in the query, + * which is the simple case, or it may depend on the current environment + * (the role which is running the query or the value of the row_security + * GUC), or it might be simply enabled as usual. + * + * If RLS isn't on the table involved then RLS_NONE is returned to indicate + * that we don't need to worry about invalidating the query plan for RLS + * reasons. If RLS is on the table, but we are bypassing it for now, then + * we return RLS_NONE_ENV to indicate that, if the environment changes, + * we need to invalidate and replan. Finally, if RLS should be turned on + * for the query, then we return RLS_ENABLED, which means we also need to + * invalidate if the environment changes. + * + * Note that RLS_ENABLED will also be returned if noError is true + * (indicating that the caller simply want to know if RLS should be applied + * for this user but doesn't want an error thrown if it is; this is used + * by other error cases where we're just trying to decide if data from the + * table should be passed back to the user or not). + */ +enum CheckEnableRlsResult +{ + RLS_NONE, + RLS_NONE_ENV, + RLS_ENABLED +}; + +extern int check_enable_rls(Oid relid, Oid checkAsUser, bool noError); + +#endif /* RLS_H */ diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h new file mode 100644 index 0000000..951d78d --- /dev/null +++ b/src/include/utils/ruleutils.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * ruleutils.h + * Declarations for ruleutils.c + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/ruleutils.h + * + *------------------------------------------------------------------------- + */ +#ifndef RULEUTILS_H +#define RULEUTILS_H + +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" + +struct Plan; /* avoid including plannodes.h here */ +struct PlannedStmt; + +/* Flags for pg_get_indexdef_columns_extended() */ +#define RULE_INDEXDEF_PRETTY 0x01 +#define RULE_INDEXDEF_KEYS_ONLY 0x02 /* ignore included attributes */ + +extern char *pg_get_indexdef_string(Oid indexrelid); +extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty); +extern char *pg_get_indexdef_columns_extended(Oid indexrelid, + bits16 flags); +extern char *pg_get_querydef(Query *query, bool pretty); + +extern char *pg_get_partkeydef_columns(Oid relid, bool pretty); +extern char *pg_get_partconstrdef_string(Oid partitionId, char *aliasname); + +extern char *pg_get_constraintdef_command(Oid constraintId); +extern char *deparse_expression(Node *expr, List *dpcontext, + bool forceprefix, bool showimplicit); +extern List *deparse_context_for(const char *aliasname, Oid relid); +extern List *deparse_context_for_plan_tree(struct PlannedStmt *pstmt, + List *rtable_names); +extern List *set_deparse_context_plan(List *dpcontext, + struct Plan *plan, List *ancestors); +extern List *select_rtable_names_for_explain(List *rtable, + Bitmapset *rels_used); +extern char *generate_collation_name(Oid collid); +extern char *generate_opclass_name(Oid opclass); +extern char *get_range_partbound_string(List *bound_datums); + +extern char *pg_get_statisticsobjdef_string(Oid statextid); + +#endif /* RULEUTILS_H */ diff --git a/src/include/utils/sampling.h b/src/include/utils/sampling.h new file mode 100644 index 0000000..c773b59 --- /dev/null +++ b/src/include/utils/sampling.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * sampling.h + * definitions for sampling functions + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/sampling.h + * + *------------------------------------------------------------------------- + */ +#ifndef SAMPLING_H +#define SAMPLING_H + +#include "common/pg_prng.h" +#include "storage/block.h" /* for typedef BlockNumber */ + + +/* Random generator for sampling code */ +extern void sampler_random_init_state(uint32 seed, + pg_prng_state *randstate); +extern double sampler_random_fract(pg_prng_state *randstate); + +/* Block sampling methods */ + +/* Data structure for Algorithm S from Knuth 3.4.2 */ +typedef struct +{ + BlockNumber N; /* number of blocks, known in advance */ + int n; /* desired sample size */ + BlockNumber t; /* current block number */ + int m; /* blocks selected so far */ + pg_prng_state randstate; /* random generator state */ +} BlockSamplerData; + +typedef BlockSamplerData *BlockSampler; + +extern BlockNumber BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, + int samplesize, uint32 randseed); +extern bool BlockSampler_HasMore(BlockSampler bs); +extern BlockNumber BlockSampler_Next(BlockSampler bs); + +/* Reservoir sampling methods */ + +typedef struct +{ + double W; + pg_prng_state randstate; /* random generator state */ +} ReservoirStateData; + +typedef ReservoirStateData *ReservoirState; + +extern void reservoir_init_selection_state(ReservoirState rs, int n); +extern double reservoir_get_next_S(ReservoirState rs, double t, int n); + +/* Old API, still in use by assorted FDWs */ +/* For backwards compatibility, these declarations are duplicated in vacuum.h */ + +extern double anl_random_fract(void); +extern double anl_init_selection_state(int n); +extern double anl_get_next_S(double t, int n, double *stateptr); + +#endif /* SAMPLING_H */ diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h new file mode 100644 index 0000000..8f3d73e --- /dev/null +++ b/src/include/utils/selfuncs.h @@ -0,0 +1,241 @@ +/*------------------------------------------------------------------------- + * + * selfuncs.h + * Selectivity functions for standard operators, and assorted + * infrastructure for selectivity and cost estimation. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/selfuncs.h + * + *------------------------------------------------------------------------- + */ +#ifndef SELFUNCS_H +#define SELFUNCS_H + +#include "access/htup.h" +#include "fmgr.h" +#include "nodes/pathnodes.h" + + +/* + * Note: the default selectivity estimates are not chosen entirely at random. + * We want them to be small enough to ensure that indexscans will be used if + * available, for typical table densities of ~100 tuples/page. Thus, for + * example, 0.01 is not quite small enough, since that makes it appear that + * nearly all pages will be hit anyway. Also, since we sometimes estimate + * eqsel as 1/num_distinct, we probably want DEFAULT_NUM_DISTINCT to equal + * 1/DEFAULT_EQ_SEL. + */ + +/* default selectivity estimate for equalities such as "A = b" */ +#define DEFAULT_EQ_SEL 0.005 + +/* default selectivity estimate for inequalities such as "A < b" */ +#define DEFAULT_INEQ_SEL 0.3333333333333333 + +/* default selectivity estimate for range inequalities "A > b AND A < c" */ +#define DEFAULT_RANGE_INEQ_SEL 0.005 + +/* default selectivity estimate for multirange inequalities "A > b AND A < c" */ +#define DEFAULT_MULTIRANGE_INEQ_SEL 0.005 + +/* default selectivity estimate for pattern-match operators such as LIKE */ +#define DEFAULT_MATCH_SEL 0.005 + +/* default selectivity estimate for other matching operators */ +#define DEFAULT_MATCHING_SEL 0.010 + +/* default number of distinct values in a table */ +#define DEFAULT_NUM_DISTINCT 200 + +/* default selectivity estimate for boolean and null test nodes */ +#define DEFAULT_UNK_SEL 0.005 +#define DEFAULT_NOT_UNK_SEL (1.0 - DEFAULT_UNK_SEL) + + +/* + * Clamp a computed probability estimate (which may suffer from roundoff or + * estimation errors) to valid range. Argument must be a float variable. + */ +#define CLAMP_PROBABILITY(p) \ + do { \ + if (p < 0.0) \ + p = 0.0; \ + else if (p > 1.0) \ + p = 1.0; \ + } while (0) + +/* + * A set of flags which some selectivity estimation functions can pass back to + * callers to provide further details about some assumptions which were made + * during the estimation. + */ +#define SELFLAG_USED_DEFAULT (1 << 0) /* Estimation fell back on one + * of the DEFAULTs as defined + * above. */ + +typedef struct EstimationInfo +{ + uint32 flags; /* Flags, as defined above to mark special + * properties of the estimation. */ +} EstimationInfo; + +/* Return data from examine_variable and friends */ +typedef struct VariableStatData +{ + Node *var; /* the Var or expression tree */ + RelOptInfo *rel; /* Relation, or NULL if not identifiable */ + HeapTuple statsTuple; /* pg_statistic tuple, or NULL if none */ + /* NB: if statsTuple!=NULL, it must be freed when caller is done */ + void (*freefunc) (HeapTuple tuple); /* how to free statsTuple */ + Oid vartype; /* exposed type of expression */ + Oid atttype; /* actual type (after stripping relabel) */ + int32 atttypmod; /* actual typmod (after stripping relabel) */ + bool isunique; /* matches unique index or DISTINCT clause */ + bool acl_ok; /* result of ACL check on table or column */ +} VariableStatData; + +#define ReleaseVariableStats(vardata) \ + do { \ + if (HeapTupleIsValid((vardata).statsTuple)) \ + (vardata).freefunc((vardata).statsTuple); \ + } while(0) + + +/* + * genericcostestimate is a general-purpose estimator that can be used for + * most index types. In some cases we use genericcostestimate as the base + * code and then incorporate additional index-type-specific knowledge in + * the type-specific calling function. To avoid code duplication, we make + * genericcostestimate return a number of intermediate values as well as + * its preliminary estimates of the output cost values. The GenericCosts + * struct includes all these values. + * + * Callers should initialize all fields of GenericCosts to zero. In addition, + * they can set numIndexTuples to some positive value if they have a better + * than default way of estimating the number of leaf index tuples visited. + */ +typedef struct +{ + /* These are the values the cost estimator must return to the planner */ + Cost indexStartupCost; /* index-related startup cost */ + Cost indexTotalCost; /* total index-related scan cost */ + Selectivity indexSelectivity; /* selectivity of index */ + double indexCorrelation; /* order correlation of index */ + + /* Intermediate values we obtain along the way */ + double numIndexPages; /* number of leaf pages visited */ + double numIndexTuples; /* number of leaf tuples visited */ + double spc_random_page_cost; /* relevant random_page_cost value */ + double num_sa_scans; /* # indexscans from ScalarArrayOpExprs */ +} GenericCosts; + +/* Hooks for plugins to get control when we ask for stats */ +typedef bool (*get_relation_stats_hook_type) (PlannerInfo *root, + RangeTblEntry *rte, + AttrNumber attnum, + VariableStatData *vardata); +extern PGDLLIMPORT get_relation_stats_hook_type get_relation_stats_hook; +typedef bool (*get_index_stats_hook_type) (PlannerInfo *root, + Oid indexOid, + AttrNumber indexattnum, + VariableStatData *vardata); +extern PGDLLIMPORT get_index_stats_hook_type get_index_stats_hook; + +/* Functions in selfuncs.c */ + +extern void examine_variable(PlannerInfo *root, Node *node, int varRelid, + VariableStatData *vardata); +extern bool statistic_proc_security_check(VariableStatData *vardata, Oid func_oid); +extern bool get_restriction_variable(PlannerInfo *root, List *args, + int varRelid, + VariableStatData *vardata, Node **other, + bool *varonleft); +extern void get_join_variables(PlannerInfo *root, List *args, + SpecialJoinInfo *sjinfo, + VariableStatData *vardata1, + VariableStatData *vardata2, + bool *join_is_reversed); +extern double get_variable_numdistinct(VariableStatData *vardata, + bool *isdefault); +extern double mcv_selectivity(VariableStatData *vardata, + FmgrInfo *opproc, Oid collation, + Datum constval, bool varonleft, + double *sumcommonp); +extern double histogram_selectivity(VariableStatData *vardata, + FmgrInfo *opproc, Oid collation, + Datum constval, bool varonleft, + int min_hist_size, int n_skip, + int *hist_size); +extern double generic_restriction_selectivity(PlannerInfo *root, + Oid oproid, Oid collation, + List *args, int varRelid, + double default_selectivity); +extern double ineq_histogram_selectivity(PlannerInfo *root, + VariableStatData *vardata, + Oid opoid, FmgrInfo *opproc, + bool isgt, bool iseq, + Oid collation, + Datum constval, Oid consttype); +extern double var_eq_const(VariableStatData *vardata, + Oid oproid, Oid collation, + Datum constval, bool constisnull, + bool varonleft, bool negate); +extern double var_eq_non_const(VariableStatData *vardata, + Oid oproid, Oid collation, + Node *other, + bool varonleft, bool negate); + +extern Selectivity boolvarsel(PlannerInfo *root, Node *arg, int varRelid); +extern Selectivity booltestsel(PlannerInfo *root, BoolTestType booltesttype, + Node *arg, int varRelid, + JoinType jointype, SpecialJoinInfo *sjinfo); +extern Selectivity nulltestsel(PlannerInfo *root, NullTestType nulltesttype, + Node *arg, int varRelid, + JoinType jointype, SpecialJoinInfo *sjinfo); +extern Selectivity scalararraysel(PlannerInfo *root, + ScalarArrayOpExpr *clause, + bool is_join_clause, + int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo); +extern int estimate_array_length(Node *arrayexpr); +extern Selectivity rowcomparesel(PlannerInfo *root, + RowCompareExpr *clause, + int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo); + +extern void mergejoinscansel(PlannerInfo *root, Node *clause, + Oid opfamily, int strategy, bool nulls_first, + Selectivity *leftstart, Selectivity *leftend, + Selectivity *rightstart, Selectivity *rightend); + +extern double estimate_num_groups(PlannerInfo *root, List *groupExprs, + double input_rows, List **pgset, + EstimationInfo *estinfo); + +extern void estimate_hash_bucket_stats(PlannerInfo *root, + Node *hashkey, double nbuckets, + Selectivity *mcv_freq, + Selectivity *bucketsize_frac); +extern double estimate_hashagg_tablesize(PlannerInfo *root, Path *path, + const AggClauseCosts *agg_costs, + double dNumGroups); + +extern List *get_quals_from_indexclauses(List *indexclauses); +extern Cost index_other_operands_eval_cost(PlannerInfo *root, + List *indexquals); +extern List *add_predicate_to_index_quals(IndexOptInfo *index, + List *indexQuals); +extern void genericcostestimate(PlannerInfo *root, IndexPath *path, + double loop_count, + GenericCosts *costs); + +/* Functions in array_selfuncs.c */ + +extern Selectivity scalararraysel_containment(PlannerInfo *root, + Node *leftop, Node *rightop, + Oid elemtype, bool isEquality, bool useOr, + int varRelid); + +#endif /* SELFUNCS_H */ diff --git a/src/include/utils/sharedtuplestore.h b/src/include/utils/sharedtuplestore.h new file mode 100644 index 0000000..79be13d --- /dev/null +++ b/src/include/utils/sharedtuplestore.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * sharedtuplestore.h + * Simple mechanism for sharing tuples between backends. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/sharedtuplestore.h + * + *------------------------------------------------------------------------- + */ +#ifndef SHAREDTUPLESTORE_H +#define SHAREDTUPLESTORE_H + +#include "access/htup.h" +#include "storage/fd.h" +#include "storage/sharedfileset.h" + +struct SharedTuplestore; +typedef struct SharedTuplestore SharedTuplestore; + +struct SharedTuplestoreAccessor; +typedef struct SharedTuplestoreAccessor SharedTuplestoreAccessor; + +/* + * A flag indicating that the tuplestore will only be scanned once, so backing + * files can be unlinked early. + */ +#define SHARED_TUPLESTORE_SINGLE_PASS 0x01 + +extern size_t sts_estimate(int participants); + +extern SharedTuplestoreAccessor *sts_initialize(SharedTuplestore *sts, + int participants, + int my_participant_number, + size_t meta_data_size, + int flags, + SharedFileSet *fileset, + const char *name); + +extern SharedTuplestoreAccessor *sts_attach(SharedTuplestore *sts, + int my_participant_number, + SharedFileSet *fileset); + +extern void sts_end_write(SharedTuplestoreAccessor *accessor); + +extern void sts_reinitialize(SharedTuplestoreAccessor *accessor); + +extern void sts_begin_parallel_scan(SharedTuplestoreAccessor *accessor); + +extern void sts_end_parallel_scan(SharedTuplestoreAccessor *accessor); + +extern void sts_puttuple(SharedTuplestoreAccessor *accessor, + void *meta_data, + MinimalTuple tuple); + +extern MinimalTuple sts_parallel_scan_next(SharedTuplestoreAccessor *accessor, + void *meta_data); + +#endif /* SHAREDTUPLESTORE_H */ diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h new file mode 100644 index 0000000..06eafdf --- /dev/null +++ b/src/include/utils/snapmgr.h @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + * + * snapmgr.h + * POSTGRES snapshot manager + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/snapmgr.h + * + *------------------------------------------------------------------------- + */ +#ifndef SNAPMGR_H +#define SNAPMGR_H + +#include "access/transam.h" +#include "utils/relcache.h" +#include "utils/resowner.h" +#include "utils/snapshot.h" + + +/* + * The structure used to map times to TransactionId values for the "snapshot + * too old" feature must have a few entries at the tail to hold old values; + * otherwise the lookup will often fail and the expected early pruning or + * vacuum will not usually occur. It is best if this padding is for a number + * of minutes greater than a thread would normally be stalled, but it's OK if + * early vacuum opportunities are occasionally missed, so there's no need to + * use an extreme value or get too fancy. 10 minutes seems plenty. + */ +#define OLD_SNAPSHOT_PADDING_ENTRIES 10 +#define OLD_SNAPSHOT_TIME_MAP_ENTRIES (old_snapshot_threshold + OLD_SNAPSHOT_PADDING_ENTRIES) + +/* + * Common definition of relation properties that allow early pruning/vacuuming + * when old_snapshot_threshold >= 0. + */ +#define RelationAllowsEarlyPruning(rel) \ +( \ + RelationIsPermanent(rel) && !IsCatalogRelation(rel) \ + && !RelationIsAccessibleInLogicalDecoding(rel) \ +) + +#define EarlyPruningEnabled(rel) (old_snapshot_threshold >= 0 && RelationAllowsEarlyPruning(rel)) + +/* GUC variables */ +extern PGDLLIMPORT int old_snapshot_threshold; + + +extern Size SnapMgrShmemSize(void); +extern void SnapMgrInit(void); +extern TimestampTz GetSnapshotCurrentTimestamp(void); +extern TimestampTz GetOldSnapshotThresholdTimestamp(void); +extern void SnapshotTooOldMagicForTest(void); + +extern PGDLLIMPORT bool FirstSnapshotSet; + +extern PGDLLIMPORT TransactionId TransactionXmin; +extern PGDLLIMPORT TransactionId RecentXmin; + +/* Variables representing various special snapshot semantics */ +extern PGDLLIMPORT SnapshotData SnapshotSelfData; +extern PGDLLIMPORT SnapshotData SnapshotAnyData; +extern PGDLLIMPORT SnapshotData CatalogSnapshotData; + +#define SnapshotSelf (&SnapshotSelfData) +#define SnapshotAny (&SnapshotAnyData) + +/* + * We don't provide a static SnapshotDirty variable because it would be + * non-reentrant. Instead, users of that snapshot type should declare a + * local variable of type SnapshotData, and initialize it with this macro. + */ +#define InitDirtySnapshot(snapshotdata) \ + ((snapshotdata).snapshot_type = SNAPSHOT_DIRTY) + +/* + * Similarly, some initialization is required for a NonVacuumable snapshot. + * The caller must supply the visibility cutoff state to use (c.f. + * GlobalVisTestFor()). + */ +#define InitNonVacuumableSnapshot(snapshotdata, vistestp) \ + ((snapshotdata).snapshot_type = SNAPSHOT_NON_VACUUMABLE, \ + (snapshotdata).vistest = (vistestp)) + +/* + * Similarly, some initialization is required for SnapshotToast. We need + * to set lsn and whenTaken correctly to support snapshot_too_old. + */ +#define InitToastSnapshot(snapshotdata, l, w) \ + ((snapshotdata).snapshot_type = SNAPSHOT_TOAST, \ + (snapshotdata).lsn = (l), \ + (snapshotdata).whenTaken = (w)) + +/* This macro encodes the knowledge of which snapshots are MVCC-safe */ +#define IsMVCCSnapshot(snapshot) \ + ((snapshot)->snapshot_type == SNAPSHOT_MVCC || \ + (snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC) + +#ifndef FRONTEND +static inline bool +OldSnapshotThresholdActive(void) +{ + return old_snapshot_threshold >= 0; +} +#endif + +extern Snapshot GetTransactionSnapshot(void); +extern Snapshot GetLatestSnapshot(void); +extern void SnapshotSetCommandId(CommandId curcid); +extern Snapshot GetOldestSnapshot(void); + +extern Snapshot GetCatalogSnapshot(Oid relid); +extern Snapshot GetNonHistoricCatalogSnapshot(Oid relid); +extern void InvalidateCatalogSnapshot(void); +extern void InvalidateCatalogSnapshotConditionally(void); + +extern void PushActiveSnapshot(Snapshot snapshot); +extern void PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level); +extern void PushCopiedSnapshot(Snapshot snapshot); +extern void UpdateActiveSnapshotCommandId(void); +extern void PopActiveSnapshot(void); +extern Snapshot GetActiveSnapshot(void); +extern bool ActiveSnapshotSet(void); + +extern Snapshot RegisterSnapshot(Snapshot snapshot); +extern void UnregisterSnapshot(Snapshot snapshot); +extern Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner); +extern void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner); + +extern void AtSubCommit_Snapshot(int level); +extern void AtSubAbort_Snapshot(int level); +extern void AtEOXact_Snapshot(bool isCommit, bool resetXmin); + +extern void ImportSnapshot(const char *idstr); +extern bool XactHasExportedSnapshots(void); +extern void DeleteAllExportedSnapshotFiles(void); +extern void WaitForOlderSnapshots(TransactionId limitXmin, bool progress); +extern bool ThereAreNoPriorRegisteredSnapshots(void); +extern bool HaveRegisteredOrActiveSnapshot(void); +extern bool TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, + Relation relation, + TransactionId *limit_xid, + TimestampTz *limit_ts); +extern void SetOldSnapshotThresholdTimestamp(TimestampTz ts, TransactionId xlimit); +extern void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, + TransactionId xmin); + +extern char *ExportSnapshot(Snapshot snapshot); + +/* + * These live in procarray.c because they're intimately linked to the + * procarray contents, but thematically they better fit into snapmgr.h. + */ +typedef struct GlobalVisState GlobalVisState; +extern GlobalVisState *GlobalVisTestFor(Relation rel); +extern bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid); +extern bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid); +extern FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state); +extern TransactionId GlobalVisTestNonRemovableHorizon(GlobalVisState *state); +extern bool GlobalVisCheckRemovableXid(Relation rel, TransactionId xid); +extern bool GlobalVisCheckRemovableFullXid(Relation rel, FullTransactionId fxid); + +/* + * Utility functions for implementing visibility routines in table AMs. + */ +extern bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); + +/* Support for catalog timetravel for logical decoding */ +struct HTAB; +extern struct HTAB *HistoricSnapshotGetTupleCids(void); +extern void SetupHistoricSnapshot(Snapshot snapshot_now, struct HTAB *tuplecids); +extern void TeardownHistoricSnapshot(bool is_error); +extern bool HistoricSnapshotActive(void); + +extern Size EstimateSnapshotSpace(Snapshot snapshot); +extern void SerializeSnapshot(Snapshot snapshot, char *start_address); +extern Snapshot RestoreSnapshot(char *start_address); +extern void RestoreTransactionSnapshot(Snapshot snapshot, void *source_pgproc); + +#endif /* SNAPMGR_H */ diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h new file mode 100644 index 0000000..4e96f1a --- /dev/null +++ b/src/include/utils/snapshot.h @@ -0,0 +1,219 @@ +/*------------------------------------------------------------------------- + * + * snapshot.h + * POSTGRES snapshot definition + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/snapshot.h + * + *------------------------------------------------------------------------- + */ +#ifndef SNAPSHOT_H +#define SNAPSHOT_H + +#include "access/htup.h" +#include "access/xlogdefs.h" +#include "datatype/timestamp.h" +#include "lib/pairingheap.h" +#include "storage/buf.h" + + +/* + * The different snapshot types. We use SnapshotData structures to represent + * both "regular" (MVCC) snapshots and "special" snapshots that have non-MVCC + * semantics. The specific semantics of a snapshot are encoded by its type. + * + * The behaviour of each type of snapshot should be documented alongside its + * enum value, best in terms that are not specific to an individual table AM. + * + * The reason the snapshot type rather than a callback as it used to be is + * that that allows to use the same snapshot for different table AMs without + * having one callback per AM. + */ +typedef enum SnapshotType +{ + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid for the given MVCC snapshot. + * + * Here, we consider the effects of: + * - all transactions committed as of the time of the given snapshot + * - previous commands of this transaction + * + * Does _not_ include: + * - transactions shown as in-progress by the snapshot + * - transactions started after the snapshot was taken + * - changes made by the current command + * ------------------------------------------------------------------------- + */ + SNAPSHOT_MVCC = 0, + + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid "for itself". + * + * Here, we consider the effects of: + * - all committed transactions (as of the current instant) + * - previous commands of this transaction + * - changes made by the current command + * + * Does _not_ include: + * - in-progress transactions (as of the current instant) + * ------------------------------------------------------------------------- + */ + SNAPSHOT_SELF, + + /* + * Any tuple is visible. + */ + SNAPSHOT_ANY, + + /* + * A tuple is visible iff the tuple is valid as a TOAST row. + */ + SNAPSHOT_TOAST, + + /*------------------------------------------------------------------------- + * A tuple is visible iff the tuple is valid including effects of open + * transactions. + * + * Here, we consider the effects of: + * - all committed and in-progress transactions (as of the current instant) + * - previous commands of this transaction + * - changes made by the current command + * + * This is essentially like SNAPSHOT_SELF as far as effects of the current + * transaction and committed/aborted xacts are concerned. However, it + * also includes the effects of other xacts still in progress. + * + * A special hack is that when a snapshot of this type is used to + * determine tuple visibility, the passed-in snapshot struct is used as an + * output argument to return the xids of concurrent xacts that affected + * the tuple. snapshot->xmin is set to the tuple's xmin if that is + * another transaction that's still in progress; or to + * InvalidTransactionId if the tuple's xmin is committed good, committed + * dead, or my own xact. Similarly for snapshot->xmax and the tuple's + * xmax. If the tuple was inserted speculatively, meaning that the + * inserter might still back down on the insertion without aborting the + * whole transaction, the associated token is also returned in + * snapshot->speculativeToken. See also InitDirtySnapshot(). + * ------------------------------------------------------------------------- + */ + SNAPSHOT_DIRTY, + + /* + * A tuple is visible iff it follows the rules of SNAPSHOT_MVCC, but + * supports being called in timetravel context (for decoding catalog + * contents in the context of logical decoding). + */ + SNAPSHOT_HISTORIC_MVCC, + + /* + * A tuple is visible iff the tuple might be visible to some transaction; + * false if it's surely dead to everyone, i.e., vacuumable. + * + * For visibility checks snapshot->min must have been set up with the xmin + * horizon to use. + */ + SNAPSHOT_NON_VACUUMABLE +} SnapshotType; + +typedef struct SnapshotData *Snapshot; + +#define InvalidSnapshot ((Snapshot) NULL) + +/* + * Struct representing all kind of possible snapshots. + * + * There are several different kinds of snapshots: + * * Normal MVCC snapshots + * * MVCC snapshots taken during recovery (in Hot-Standby mode) + * * Historic MVCC snapshots used during logical decoding + * * snapshots passed to HeapTupleSatisfiesDirty() + * * snapshots passed to HeapTupleSatisfiesNonVacuumable() + * * snapshots used for SatisfiesAny, Toast, Self where no members are + * accessed. + * + * TODO: It's probably a good idea to split this struct using a NodeTag + * similar to how parser and executor nodes are handled, with one type for + * each different kind of snapshot to avoid overloading the meaning of + * individual fields. + */ +typedef struct SnapshotData +{ + SnapshotType snapshot_type; /* type of snapshot */ + + /* + * The remaining fields are used only for MVCC snapshots, and are normally + * just zeroes in special snapshots. (But xmin and xmax are used + * specially by HeapTupleSatisfiesDirty, and xmin is used specially by + * HeapTupleSatisfiesNonVacuumable.) + * + * An MVCC snapshot can never see the effects of XIDs >= xmax. It can see + * the effects of all older XIDs except those listed in the snapshot. xmin + * is stored as an optimization to avoid needing to search the XID arrays + * for most tuples. + */ + TransactionId xmin; /* all XID < xmin are visible to me */ + TransactionId xmax; /* all XID >= xmax are invisible to me */ + + /* + * For normal MVCC snapshot this contains the all xact IDs that are in + * progress, unless the snapshot was taken during recovery in which case + * it's empty. For historic MVCC snapshots, the meaning is inverted, i.e. + * it contains *committed* transactions between xmin and xmax. + * + * note: all ids in xip[] satisfy xmin <= xip[i] < xmax + */ + TransactionId *xip; + uint32 xcnt; /* # of xact ids in xip[] */ + + /* + * For non-historic MVCC snapshots, this contains subxact IDs that are in + * progress (and other transactions that are in progress if taken during + * recovery). For historic snapshot it contains *all* xids assigned to the + * replayed transaction, including the toplevel xid. + * + * note: all ids in subxip[] are >= xmin, but we don't bother filtering + * out any that are >= xmax + */ + TransactionId *subxip; + int32 subxcnt; /* # of xact ids in subxip[] */ + bool suboverflowed; /* has the subxip array overflowed? */ + + bool takenDuringRecovery; /* recovery-shaped snapshot? */ + bool copied; /* false if it's a static snapshot */ + + CommandId curcid; /* in my xact, CID < curcid are visible */ + + /* + * An extra return value for HeapTupleSatisfiesDirty, not used in MVCC + * snapshots. + */ + uint32 speculativeToken; + + /* + * For SNAPSHOT_NON_VACUUMABLE (and hopefully more in the future) this is + * used to determine whether row could be vacuumed. + */ + struct GlobalVisState *vistest; + + /* + * Book-keeping information, used by the snapshot manager + */ + uint32 active_count; /* refcount on ActiveSnapshot stack */ + uint32 regd_count; /* refcount on RegisteredSnapshots */ + pairingheap_node ph_node; /* link in the RegisteredSnapshots heap */ + + TimestampTz whenTaken; /* timestamp when snapshot was taken */ + XLogRecPtr lsn; /* position in the WAL stream when taken */ + + /* + * The transaction completion count at the time GetSnapshotData() built + * this snapshot. Allows to avoid re-computing static snapshots when no + * transactions completed since the last GetSnapshotData(). + */ + uint64 snapXactCompletionCount; +} SnapshotData; + +#endif /* SNAPSHOT_H */ diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h new file mode 100644 index 0000000..8c36cf8 --- /dev/null +++ b/src/include/utils/sortsupport.h @@ -0,0 +1,391 @@ +/*------------------------------------------------------------------------- + * + * sortsupport.h + * Framework for accelerated sorting. + * + * Traditionally, PostgreSQL has implemented sorting by repeatedly invoking + * an SQL-callable comparison function "cmp(x, y) returns int" on pairs of + * values to be compared, where the comparison function is the BTORDER_PROC + * pg_amproc support function of the appropriate btree index opclass. + * + * This file defines alternative APIs that allow sorting to be performed with + * reduced overhead. To support lower-overhead sorting, a btree opclass may + * provide a BTSORTSUPPORT_PROC pg_amproc entry, which must take a single + * argument of type internal and return void. The argument is actually a + * pointer to a SortSupportData struct, which is defined below. + * + * If provided, the BTSORTSUPPORT function will be called during sort setup, + * and it must initialize the provided struct with pointers to function(s) + * that can be called to perform sorting. This API is defined to allow + * multiple acceleration mechanisms to be supported, but no opclass is + * required to provide all of them. The BTSORTSUPPORT function should + * simply not set any function pointers for mechanisms it doesn't support. + * Opclasses that provide BTSORTSUPPORT and don't provide a comparator + * function will have a shim set up by sort support automatically. However, + * opclasses that support the optional additional abbreviated key capability + * must always provide an authoritative comparator used to tie-break + * inconclusive abbreviated comparisons and also used when aborting + * abbreviation. Furthermore, a converter and abort/costing function must be + * provided. + * + * All sort support functions will be passed the address of the + * SortSupportData struct when called, so they can use it to store + * additional private data as needed. In particular, for collation-aware + * datatypes, the ssup_collation field is set before calling BTSORTSUPPORT + * and is available to all support functions. Additional opclass-dependent + * data can be stored using the ssup_extra field. Any such data + * should be allocated in the ssup_cxt memory context. + * + * Note: since pg_amproc functions are indexed by (lefttype, righttype) + * it is possible to associate a BTSORTSUPPORT function with a cross-type + * comparison. This could sensibly be used to provide a fast comparator + * function for such cases, but probably not any other acceleration method. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/sortsupport.h + * + *------------------------------------------------------------------------- + */ +#ifndef SORTSUPPORT_H +#define SORTSUPPORT_H + +#include "access/attnum.h" +#include "utils/relcache.h" + +typedef struct SortSupportData *SortSupport; + +typedef struct SortSupportData +{ + /* + * These fields are initialized before calling the BTSORTSUPPORT function + * and should not be changed later. + */ + MemoryContext ssup_cxt; /* Context containing sort info */ + Oid ssup_collation; /* Collation to use, or InvalidOid */ + + /* + * Additional sorting parameters; but unlike ssup_collation, these can be + * changed after BTSORTSUPPORT is called, so don't use them in selecting + * sort support functions. + */ + bool ssup_reverse; /* descending-order sort? */ + bool ssup_nulls_first; /* sort nulls first? */ + + /* + * These fields are workspace for callers, and should not be touched by + * opclass-specific functions. + */ + AttrNumber ssup_attno; /* column number to sort */ + + /* + * ssup_extra is zeroed before calling the BTSORTSUPPORT function, and is + * not touched subsequently by callers. + */ + void *ssup_extra; /* Workspace for opclass functions */ + + /* + * Function pointers are zeroed before calling the BTSORTSUPPORT function, + * and must be set by it for any acceleration methods it wants to supply. + * The comparator pointer must be set, others are optional. + */ + + /* + * Comparator function has the same API as the traditional btree + * comparison function, ie, return <0, 0, or >0 according as x is less + * than, equal to, or greater than y. Note that x and y are guaranteed + * not null, and there is no way to return null either. + * + * This may be either the authoritative comparator, or the abbreviated + * comparator. Core code may switch this over the initial preference of + * an opclass support function despite originally indicating abbreviation + * was applicable, by assigning the authoritative comparator back. + */ + int (*comparator) (Datum x, Datum y, SortSupport ssup); + + /* + * "Abbreviated key" infrastructure follows. + * + * All callbacks must be set by sortsupport opclasses that make use of + * this optional additional infrastructure (unless for whatever reasons + * the opclass doesn't proceed with abbreviation, in which case + * abbrev_converter must not be set). + * + * This allows opclass authors to supply a conversion routine, used to + * create an alternative representation of the underlying type (an + * "abbreviated key"). This representation must be pass-by-value and + * typically will use some ad-hoc format that only the opclass has + * knowledge of. An alternative comparator, used only with this + * alternative representation must also be provided (which is assigned to + * "comparator"). This representation is a simple approximation of the + * original Datum. It must be possible to compare datums of this + * representation with each other using the supplied alternative + * comparator, and have any non-zero return value be a reliable proxy for + * what a proper comparison would indicate. Returning zero from the + * alternative comparator does not indicate equality, as with a + * conventional support routine 1, though -- it indicates that it wasn't + * possible to determine how the two abbreviated values compared. A + * proper comparison, using "abbrev_full_comparator"/ + * ApplySortAbbrevFullComparator() is therefore required. In many cases + * this results in most or all comparisons only using the cheap + * alternative comparison func, which is typically implemented as code + * that compiles to just a few CPU instructions. CPU cache miss penalties + * are expensive; to get good overall performance, sort infrastructure + * must heavily weigh cache performance. + * + * Opclass authors must consider the final cardinality of abbreviated keys + * when devising an encoding scheme. It's possible for a strategy to work + * better than an alternative strategy with one usage pattern, while the + * reverse might be true for another usage pattern. All of these factors + * must be considered. + */ + + /* + * "abbreviate" concerns whether or not the abbreviated key optimization + * is applicable in principle (that is, the sortsupport routine needs to + * know if its dealing with a key where an abbreviated representation can + * usefully be packed together. Conventionally, this is the leading + * attribute key). Note, however, that in order to determine that + * abbreviation is not in play, the core code always checks whether or not + * the opclass has set abbrev_converter. This is a one way, one time + * message to the opclass. + */ + bool abbreviate; + + /* + * Converter to abbreviated format, from original representation. Core + * code uses this callback to convert from a pass-by-reference "original" + * Datum to a pass-by-value abbreviated key Datum. Note that original is + * guaranteed NOT NULL, because it doesn't make sense to factor NULLness + * into ad-hoc cost model. + * + * abbrev_converter is tested to see if abbreviation is in play. Core + * code may set it to NULL to indicate abbreviation should not be used + * (which is something sortsupport routines need not concern themselves + * with). However, sortsupport routines must not set it when it is + * immediately established that abbreviation should not proceed (e.g., for + * !abbreviate calls, or due to platform-specific impediments to using + * abbreviation). + */ + Datum (*abbrev_converter) (Datum original, SortSupport ssup); + + /* + * abbrev_abort callback allows clients to verify that the current + * strategy is working out, using a sortsupport routine defined ad-hoc + * cost model. If there is a lot of duplicate abbreviated keys in + * practice, it's useful to be able to abandon the strategy before paying + * too high a cost in conversion (perhaps certain opclass-specific + * adaptations are useful too). + */ + bool (*abbrev_abort) (int memtupcount, SortSupport ssup); + + /* + * Full, authoritative comparator for key that an abbreviated + * representation was generated for, used when an abbreviated comparison + * was inconclusive (by calling ApplySortAbbrevFullComparator()), or used + * to replace "comparator" when core system ultimately decides against + * abbreviation. + */ + int (*abbrev_full_comparator) (Datum x, Datum y, SortSupport ssup); +} SortSupportData; + + +/* + * Apply a sort comparator function and return a 3-way comparison result. + * This takes care of handling reverse-sort and NULLs-ordering properly. + */ +static inline int +ApplySortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = ssup->comparator(datum1, datum2, ssup); + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +static inline int +ApplyUnsignedSortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = datum1 < datum2 ? -1 : datum1 > datum2 ? 1 : 0; + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +#if SIZEOF_DATUM >= 8 +static inline int +ApplySignedSortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = DatumGetInt64(datum1) < DatumGetInt64(datum2) ? -1 : + DatumGetInt64(datum1) > DatumGetInt64(datum2) ? 1 : 0; + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} +#endif + +static inline int +ApplyInt32SortComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = DatumGetInt32(datum1) < DatumGetInt32(datum2) ? -1 : + DatumGetInt32(datum1) > DatumGetInt32(datum2) ? 1 : 0; + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +/* + * Apply a sort comparator function and return a 3-way comparison using full, + * authoritative comparator. This takes care of handling reverse-sort and + * NULLs-ordering properly. + */ +static inline int +ApplySortAbbrevFullComparator(Datum datum1, bool isNull1, + Datum datum2, bool isNull2, + SortSupport ssup) +{ + int compare; + + if (isNull1) + { + if (isNull2) + compare = 0; /* NULL "=" NULL */ + else if (ssup->ssup_nulls_first) + compare = -1; /* NULL "<" NOT_NULL */ + else + compare = 1; /* NULL ">" NOT_NULL */ + } + else if (isNull2) + { + if (ssup->ssup_nulls_first) + compare = 1; /* NOT_NULL ">" NULL */ + else + compare = -1; /* NOT_NULL "<" NULL */ + } + else + { + compare = ssup->abbrev_full_comparator(datum1, datum2, ssup); + if (ssup->ssup_reverse) + INVERT_COMPARE_RESULT(compare); + } + + return compare; +} + +/* + * Datum comparison functions that we have specialized sort routines for. + * Datatypes that install these as their comparator or abbrevated comparator + * are eligible for faster sorting. + */ +extern int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup); +#if SIZEOF_DATUM >= 8 +extern int ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup); +#endif +extern int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup); + +/* Other functions in utils/sort/sortsupport.c */ +extern void PrepareSortSupportComparisonShim(Oid cmpFunc, SortSupport ssup); +extern void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup); +extern void PrepareSortSupportFromIndexRel(Relation indexRel, int16 strategy, + SortSupport ssup); +extern void PrepareSortSupportFromGistIndexRel(Relation indexRel, SortSupport ssup); + +#endif /* SORTSUPPORT_H */ diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h new file mode 100644 index 0000000..5163eee --- /dev/null +++ b/src/include/utils/spccache.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * spccache.h + * Tablespace cache. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/spccache.h + * + *------------------------------------------------------------------------- + */ +#ifndef SPCCACHE_H +#define SPCCACHE_H + +extern void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost, + float8 *spc_seq_page_cost); +extern int get_tablespace_io_concurrency(Oid spcid); +extern int get_tablespace_maintenance_io_concurrency(Oid spcid); + +#endif /* SPCCACHE_H */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h new file mode 100644 index 0000000..4463ea6 --- /dev/null +++ b/src/include/utils/syscache.h @@ -0,0 +1,224 @@ +/*------------------------------------------------------------------------- + * + * syscache.h + * System catalog cache definitions. + * + * See also lsyscache.h, which provides convenience routines for + * common cache-lookup operations. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/syscache.h + * + *------------------------------------------------------------------------- + */ +#ifndef SYSCACHE_H +#define SYSCACHE_H + +#include "access/attnum.h" +#include "access/htup.h" +/* we intentionally do not include utils/catcache.h here */ + +/* + * SysCache identifiers. + * + * The order of these identifiers must match the order + * of the entries in the array cacheinfo[] in syscache.c. + * Keep them in alphabetical order (renumbering only costs a + * backend rebuild). + */ + +enum SysCacheIdentifier +{ + AGGFNOID = 0, + AMNAME, + AMOID, + AMOPOPID, + AMOPSTRATEGY, + AMPROCNUM, + ATTNAME, + ATTNUM, + AUTHMEMMEMROLE, + AUTHMEMROLEMEM, + AUTHNAME, + AUTHOID, + CASTSOURCETARGET, + CLAAMNAMENSP, + CLAOID, + COLLNAMEENCNSP, + COLLOID, + CONDEFAULT, + CONNAMENSP, + CONSTROID, + CONVOID, + DATABASEOID, + DEFACLROLENSPOBJ, + ENUMOID, + ENUMTYPOIDNAME, + EVENTTRIGGERNAME, + EVENTTRIGGEROID, + FOREIGNDATAWRAPPERNAME, + FOREIGNDATAWRAPPEROID, + FOREIGNSERVERNAME, + FOREIGNSERVEROID, + FOREIGNTABLEREL, + INDEXRELID, + LANGNAME, + LANGOID, + NAMESPACENAME, + NAMESPACEOID, + OPERNAMENSP, + OPEROID, + OPFAMILYAMNAMENSP, + OPFAMILYOID, + PARAMETERACLNAME, + PARAMETERACLOID, + PARTRELID, + PROCNAMEARGSNSP, + PROCOID, + PUBLICATIONNAME, + PUBLICATIONNAMESPACE, + PUBLICATIONNAMESPACEMAP, + PUBLICATIONOID, + PUBLICATIONREL, + PUBLICATIONRELMAP, + RANGEMULTIRANGE, + RANGETYPE, + RELNAMENSP, + RELOID, + REPLORIGIDENT, + REPLORIGNAME, + RULERELNAME, + SEQRELID, + STATEXTDATASTXOID, + STATEXTNAMENSP, + STATEXTOID, + STATRELATTINH, + SUBSCRIPTIONNAME, + SUBSCRIPTIONOID, + SUBSCRIPTIONRELMAP, + TABLESPACEOID, + TRFOID, + TRFTYPELANG, + TSCONFIGMAP, + TSCONFIGNAMENSP, + TSCONFIGOID, + TSDICTNAMENSP, + TSDICTOID, + TSPARSERNAMENSP, + TSPARSEROID, + TSTEMPLATENAMENSP, + TSTEMPLATEOID, + TYPENAMENSP, + TYPEOID, + USERMAPPINGOID, + USERMAPPINGUSERSERVER + +#define SysCacheSize (USERMAPPINGUSERSERVER + 1) +}; + +extern void InitCatalogCache(void); +extern void InitCatalogCachePhase2(void); + +extern HeapTuple SearchSysCache(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); + +/* + * The use of argument specific numbers is encouraged. They're faster, and + * insulates the caller from changes in the maximum number of keys. + */ +extern HeapTuple SearchSysCache1(int cacheId, + Datum key1); +extern HeapTuple SearchSysCache2(int cacheId, + Datum key1, Datum key2); +extern HeapTuple SearchSysCache3(int cacheId, + Datum key1, Datum key2, Datum key3); +extern HeapTuple SearchSysCache4(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); + +extern void ReleaseSysCache(HeapTuple tuple); + +/* convenience routines */ +extern HeapTuple SearchSysCacheCopy(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); +extern bool SearchSysCacheExists(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); +extern Oid GetSysCacheOid(int cacheId, AttrNumber oidcol, + Datum key1, Datum key2, Datum key3, Datum key4); + +extern HeapTuple SearchSysCacheAttName(Oid relid, const char *attname); +extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname); +extern bool SearchSysCacheExistsAttName(Oid relid, const char *attname); + +extern HeapTuple SearchSysCacheAttNum(Oid relid, int16 attnum); +extern HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum); + +extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, + AttrNumber attributeNumber, bool *isNull); + +extern uint32 GetSysCacheHashValue(int cacheId, + Datum key1, Datum key2, Datum key3, Datum key4); + +/* list-search interface. Users of this must import catcache.h too */ +struct catclist; +extern struct catclist *SearchSysCacheList(int cacheId, int nkeys, + Datum key1, Datum key2, Datum key3); + +extern void SysCacheInvalidate(int cacheId, uint32 hashValue); + +extern bool RelationInvalidatesSnapshotsOnly(Oid relid); +extern bool RelationHasSysCache(Oid relid); +extern bool RelationSupportsSysCache(Oid relid); + +/* + * The use of the macros below rather than direct calls to the corresponding + * functions is encouraged, as it insulates the caller from changes in the + * maximum number of keys. + */ +#define SearchSysCacheCopy1(cacheId, key1) \ + SearchSysCacheCopy(cacheId, key1, 0, 0, 0) +#define SearchSysCacheCopy2(cacheId, key1, key2) \ + SearchSysCacheCopy(cacheId, key1, key2, 0, 0) +#define SearchSysCacheCopy3(cacheId, key1, key2, key3) \ + SearchSysCacheCopy(cacheId, key1, key2, key3, 0) +#define SearchSysCacheCopy4(cacheId, key1, key2, key3, key4) \ + SearchSysCacheCopy(cacheId, key1, key2, key3, key4) + +#define SearchSysCacheExists1(cacheId, key1) \ + SearchSysCacheExists(cacheId, key1, 0, 0, 0) +#define SearchSysCacheExists2(cacheId, key1, key2) \ + SearchSysCacheExists(cacheId, key1, key2, 0, 0) +#define SearchSysCacheExists3(cacheId, key1, key2, key3) \ + SearchSysCacheExists(cacheId, key1, key2, key3, 0) +#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4) \ + SearchSysCacheExists(cacheId, key1, key2, key3, key4) + +#define GetSysCacheOid1(cacheId, oidcol, key1) \ + GetSysCacheOid(cacheId, oidcol, key1, 0, 0, 0) +#define GetSysCacheOid2(cacheId, oidcol, key1, key2) \ + GetSysCacheOid(cacheId, oidcol, key1, key2, 0, 0) +#define GetSysCacheOid3(cacheId, oidcol, key1, key2, key3) \ + GetSysCacheOid(cacheId, oidcol, key1, key2, key3, 0) +#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4) \ + GetSysCacheOid(cacheId, oidcol, key1, key2, key3, key4) + +#define GetSysCacheHashValue1(cacheId, key1) \ + GetSysCacheHashValue(cacheId, key1, 0, 0, 0) +#define GetSysCacheHashValue2(cacheId, key1, key2) \ + GetSysCacheHashValue(cacheId, key1, key2, 0, 0) +#define GetSysCacheHashValue3(cacheId, key1, key2, key3) \ + GetSysCacheHashValue(cacheId, key1, key2, key3, 0) +#define GetSysCacheHashValue4(cacheId, key1, key2, key3, key4) \ + GetSysCacheHashValue(cacheId, key1, key2, key3, key4) + +#define SearchSysCacheList1(cacheId, key1) \ + SearchSysCacheList(cacheId, 1, key1, 0, 0) +#define SearchSysCacheList2(cacheId, key1, key2) \ + SearchSysCacheList(cacheId, 2, key1, key2, 0) +#define SearchSysCacheList3(cacheId, key1, key2, key3) \ + SearchSysCacheList(cacheId, 3, key1, key2, key3) + +#define ReleaseSysCacheList(x) ReleaseCatCacheList(x) + +#endif /* SYSCACHE_H */ diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h new file mode 100644 index 0000000..c068986 --- /dev/null +++ b/src/include/utils/timeout.h @@ -0,0 +1,95 @@ +/*------------------------------------------------------------------------- + * + * timeout.h + * Routines to multiplex SIGALRM interrupts for multiple timeout reasons. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/timeout.h + * + *------------------------------------------------------------------------- + */ +#ifndef TIMEOUT_H +#define TIMEOUT_H + +#include "datatype/timestamp.h" + +/* + * Identifiers for timeout reasons. Note that in case multiple timeouts + * trigger at the same time, they are serviced in the order of this enum. + */ +typedef enum TimeoutId +{ + /* Predefined timeout reasons */ + STARTUP_PACKET_TIMEOUT, + DEADLOCK_TIMEOUT, + LOCK_TIMEOUT, + STATEMENT_TIMEOUT, + STANDBY_DEADLOCK_TIMEOUT, + STANDBY_TIMEOUT, + STANDBY_LOCK_TIMEOUT, + IDLE_IN_TRANSACTION_SESSION_TIMEOUT, + IDLE_SESSION_TIMEOUT, + IDLE_STATS_UPDATE_TIMEOUT, + CLIENT_CONNECTION_CHECK_TIMEOUT, + STARTUP_PROGRESS_TIMEOUT, + /* First user-definable timeout reason */ + USER_TIMEOUT, + /* Maximum number of timeout reasons */ + MAX_TIMEOUTS = USER_TIMEOUT + 10 +} TimeoutId; + +/* callback function signature */ +typedef void (*timeout_handler_proc) (void); + +/* + * Parameter structure for setting multiple timeouts at once + */ +typedef enum TimeoutType +{ + TMPARAM_AFTER, + TMPARAM_AT, + TMPARAM_EVERY +} TimeoutType; + +typedef struct +{ + TimeoutId id; /* timeout to set */ + TimeoutType type; /* TMPARAM_AFTER or TMPARAM_AT */ + int delay_ms; /* only used for TMPARAM_AFTER/EVERY */ + TimestampTz fin_time; /* only used for TMPARAM_AT */ +} EnableTimeoutParams; + +/* + * Parameter structure for clearing multiple timeouts at once + */ +typedef struct +{ + TimeoutId id; /* timeout to clear */ + bool keep_indicator; /* keep the indicator flag? */ +} DisableTimeoutParams; + +/* timeout setup */ +extern void InitializeTimeouts(void); +extern TimeoutId RegisterTimeout(TimeoutId id, timeout_handler_proc handler); +extern void reschedule_timeouts(void); + +/* timeout operation */ +extern void enable_timeout_after(TimeoutId id, int delay_ms); +extern void enable_timeout_every(TimeoutId id, TimestampTz fin_time, + int delay_ms); +extern void enable_timeout_at(TimeoutId id, TimestampTz fin_time); +extern void enable_timeouts(const EnableTimeoutParams *timeouts, int count); +extern void disable_timeout(TimeoutId id, bool keep_indicator); +extern void disable_timeouts(const DisableTimeoutParams *timeouts, int count); +extern void disable_all_timeouts(bool keep_indicators); + +/* accessors */ +extern bool get_timeout_active(TimeoutId id); +extern bool get_timeout_indicator(TimeoutId id, bool reset_indicator); +extern TimestampTz get_timeout_start_time(TimeoutId id); +extern TimestampTz get_timeout_finish_time(TimeoutId id); + +#endif /* TIMEOUT_H */ diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h new file mode 100644 index 0000000..edf3a97 --- /dev/null +++ b/src/include/utils/timestamp.h @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Definitions for the SQL "timestamp" and "interval" types. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/timestamp.h + * + *------------------------------------------------------------------------- + */ +#ifndef TIMESTAMP_H +#define TIMESTAMP_H + +#include "datatype/timestamp.h" +#include "fmgr.h" +#include "pgtime.h" + + +/* + * Macros for fmgr-callable functions. + * + * For Timestamp, we make use of the same support routines as for int64. + * Therefore Timestamp is pass-by-reference if and only if int64 is! + */ +#define DatumGetTimestamp(X) ((Timestamp) DatumGetInt64(X)) +#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X)) +#define DatumGetIntervalP(X) ((Interval *) DatumGetPointer(X)) + +#define TimestampGetDatum(X) Int64GetDatum(X) +#define TimestampTzGetDatum(X) Int64GetDatum(X) +#define IntervalPGetDatum(X) PointerGetDatum(X) + +#define PG_GETARG_TIMESTAMP(n) DatumGetTimestamp(PG_GETARG_DATUM(n)) +#define PG_GETARG_TIMESTAMPTZ(n) DatumGetTimestampTz(PG_GETARG_DATUM(n)) +#define PG_GETARG_INTERVAL_P(n) DatumGetIntervalP(PG_GETARG_DATUM(n)) + +#define PG_RETURN_TIMESTAMP(x) return TimestampGetDatum(x) +#define PG_RETURN_TIMESTAMPTZ(x) return TimestampTzGetDatum(x) +#define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x) + + +#define TIMESTAMP_MASK(b) (1 << (b)) +#define INTERVAL_MASK(b) (1 << (b)) + +/* Macros to handle packing and unpacking the typmod field for intervals */ +#define INTERVAL_FULL_RANGE (0x7FFF) +#define INTERVAL_RANGE_MASK (0x7FFF) +#define INTERVAL_FULL_PRECISION (0xFFFF) +#define INTERVAL_PRECISION_MASK (0xFFFF) +#define INTERVAL_TYPMOD(p,r) ((((r) & INTERVAL_RANGE_MASK) << 16) | ((p) & INTERVAL_PRECISION_MASK)) +#define INTERVAL_PRECISION(t) ((t) & INTERVAL_PRECISION_MASK) +#define INTERVAL_RANGE(t) (((t) >> 16) & INTERVAL_RANGE_MASK) + +#define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) * (int64) 1000)) + + +/* Set at postmaster start */ +extern PGDLLIMPORT TimestampTz PgStartTime; + +/* Set at configuration reload */ +extern PGDLLIMPORT TimestampTz PgReloadTime; + + +/* Internal routines (not fmgr-callable) */ + +extern int32 anytimestamp_typmod_check(bool istz, int32 typmod); + +extern TimestampTz GetCurrentTimestamp(void); +extern TimestampTz GetSQLCurrentTimestamp(int32 typmod); +extern Timestamp GetSQLLocalTimestamp(int32 typmod); +extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, + long *secs, int *microsecs); +extern long TimestampDifferenceMilliseconds(TimestampTz start_time, + TimestampTz stop_time); +extern bool TimestampDifferenceExceeds(TimestampTz start_time, + TimestampTz stop_time, + int msec); + +extern TimestampTz time_t_to_timestamptz(pg_time_t tm); +extern pg_time_t timestamptz_to_time_t(TimestampTz t); + +extern const char *timestamptz_to_str(TimestampTz t); + +extern int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *dt); +extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, + fsec_t *fsec, const char **tzn, pg_tz *attimezone); +extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec); + +extern void interval2itm(Interval span, struct pg_itm *itm); +extern int itm2interval(struct pg_itm *itm, Interval *span); +extern int itmin2interval(struct pg_itm_in *itm_in, Interval *span); + +extern Timestamp SetEpochTimestamp(void); +extern void GetEpochTime(struct pg_tm *tm); + +extern int timestamp_cmp_internal(Timestamp dt1, Timestamp dt2); + +/* timestamp comparison works for timestamptz also */ +#define timestamptz_cmp_internal(dt1,dt2) timestamp_cmp_internal(dt1, dt2) + +extern TimestampTz timestamp2timestamptz_opt_overflow(Timestamp timestamp, + int *overflow); +extern int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal, + TimestampTz dt2); + +extern int isoweek2j(int year, int week); +extern void isoweek2date(int woy, int *year, int *mon, int *mday); +extern void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday); +extern int date2isoweek(int year, int mon, int mday); +extern int date2isoyear(int year, int mon, int mday); +extern int date2isoyearday(int year, int mon, int mday); + +extern bool TimestampTimestampTzRequiresRewrite(void); + +#endif /* TIMESTAMP_H */ diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h new file mode 100644 index 0000000..a2eaeab --- /dev/null +++ b/src/include/utils/tuplesort.h @@ -0,0 +1,291 @@ +/*------------------------------------------------------------------------- + * + * tuplesort.h + * Generalized tuple sorting routines. + * + * This module handles sorting of heap tuples, index tuples, or single + * Datums (and could easily support other kinds of sortable objects, + * if necessary). It works efficiently for both small and large amounts + * of data. Small amounts are sorted in-memory using qsort(). Large + * amounts are sorted using temporary files and a standard external sort + * algorithm. Parallel sorts use a variant of this external sort + * algorithm, and are typically only used for large amounts of data. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/tuplesort.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPLESORT_H +#define TUPLESORT_H + +#include "access/itup.h" +#include "executor/tuptable.h" +#include "storage/dsm.h" +#include "utils/relcache.h" + + +/* + * Tuplesortstate and Sharedsort are opaque types whose details are not + * known outside tuplesort.c. + */ +typedef struct Tuplesortstate Tuplesortstate; +typedef struct Sharedsort Sharedsort; + +/* + * Tuplesort parallel coordination state, allocated by each participant in + * local memory. Participant caller initializes everything. See usage notes + * below. + */ +typedef struct SortCoordinateData +{ + /* Worker process? If not, must be leader. */ + bool isWorker; + + /* + * Leader-process-passed number of participants known launched (workers + * set this to -1). Includes state within leader needed for it to + * participate as a worker, if any. + */ + int nParticipants; + + /* Private opaque state (points to shared memory) */ + Sharedsort *sharedsort; +} SortCoordinateData; + +typedef struct SortCoordinateData *SortCoordinate; + +/* + * Data structures for reporting sort statistics. Note that + * TuplesortInstrumentation can't contain any pointers because we + * sometimes put it in shared memory. + * + * The parallel-sort infrastructure relies on having a zero TuplesortMethod + * to indicate that a worker never did anything, so we assign zero to + * SORT_TYPE_STILL_IN_PROGRESS. The other values of this enum can be + * OR'ed together to represent a situation where different workers used + * different methods, so we need a separate bit for each one. Keep the + * NUM_TUPLESORTMETHODS constant in sync with the number of bits! + */ +typedef enum +{ + SORT_TYPE_STILL_IN_PROGRESS = 0, + SORT_TYPE_TOP_N_HEAPSORT = 1 << 0, + SORT_TYPE_QUICKSORT = 1 << 1, + SORT_TYPE_EXTERNAL_SORT = 1 << 2, + SORT_TYPE_EXTERNAL_MERGE = 1 << 3 +} TuplesortMethod; + +#define NUM_TUPLESORTMETHODS 4 + +typedef enum +{ + SORT_SPACE_TYPE_DISK, + SORT_SPACE_TYPE_MEMORY +} TuplesortSpaceType; + +/* Bitwise option flags for tuple sorts */ +#define TUPLESORT_NONE 0 + +/* specifies whether non-sequential access to the sort result is required */ +#define TUPLESORT_RANDOMACCESS (1 << 0) + +/* specifies if the tuplesort is able to support bounded sorts */ +#define TUPLESORT_ALLOWBOUNDED (1 << 1) + +typedef struct TuplesortInstrumentation +{ + TuplesortMethod sortMethod; /* sort algorithm used */ + TuplesortSpaceType spaceType; /* type of space spaceUsed represents */ + int64 spaceUsed; /* space consumption, in kB */ +} TuplesortInstrumentation; + + +/* + * We provide multiple interfaces to what is essentially the same code, + * since different callers have different data to be sorted and want to + * specify the sort key information differently. There are two APIs for + * sorting HeapTuples and two more for sorting IndexTuples. Yet another + * API supports sorting bare Datums. + * + * Serial sort callers should pass NULL for their coordinate argument. + * + * The "heap" API actually stores/sorts MinimalTuples, which means it doesn't + * preserve the system columns (tuple identity and transaction visibility + * info). The sort keys are specified by column numbers within the tuples + * and sort operator OIDs. We save some cycles by passing and returning the + * tuples in TupleTableSlots, rather than forming actual HeapTuples (which'd + * have to be converted to MinimalTuples). This API works well for sorts + * executed as parts of plan trees. + * + * The "cluster" API stores/sorts full HeapTuples including all visibility + * info. The sort keys are specified by reference to a btree index that is + * defined on the relation to be sorted. Note that putheaptuple/getheaptuple + * go with this API, not the "begin_heap" one! + * + * The "index_btree" API stores/sorts IndexTuples (preserving all their + * header fields). The sort keys are specified by a btree index definition. + * + * The "index_hash" API is similar to index_btree, but the tuples are + * actually sorted by their hash codes not the raw data. + * + * Parallel sort callers are required to coordinate multiple tuplesort states + * in a leader process and one or more worker processes. The leader process + * must launch workers, and have each perform an independent "partial" + * tuplesort, typically fed by the parallel heap interface. The leader later + * produces the final output (internally, it merges runs output by workers). + * + * Callers must do the following to perform a sort in parallel using multiple + * worker processes: + * + * 1. Request tuplesort-private shared memory for n workers. Use + * tuplesort_estimate_shared() to get the required size. + * 2. Have leader process initialize allocated shared memory using + * tuplesort_initialize_shared(). Launch workers. + * 3. Initialize a coordinate argument within both the leader process, and + * for each worker process. This has a pointer to the shared + * tuplesort-private structure, as well as some caller-initialized fields. + * Leader's coordinate argument reliably indicates number of workers + * launched (this is unused by workers). + * 4. Begin a tuplesort using some appropriate tuplesort_begin* routine, + * (passing the coordinate argument) within each worker. The workMem + * arguments need not be identical. All other arguments should match + * exactly, though. + * 5. tuplesort_attach_shared() should be called by all workers. Feed tuples + * to each worker, and call tuplesort_performsort() within each when input + * is exhausted. + * 6. Call tuplesort_end() in each worker process. Worker processes can shut + * down once tuplesort_end() returns. + * 7. Begin a tuplesort in the leader using the same tuplesort_begin* + * routine, passing a leader-appropriate coordinate argument (this can + * happen as early as during step 3, actually, since we only need to know + * the number of workers successfully launched). The leader must now wait + * for workers to finish. Caller must use own mechanism for ensuring that + * next step isn't reached until all workers have called and returned from + * tuplesort_performsort(). (Note that it's okay if workers have already + * also called tuplesort_end() by then.) + * 8. Call tuplesort_performsort() in leader. Consume output using the + * appropriate tuplesort_get* routine. Leader can skip this step if + * tuplesort turns out to be unnecessary. + * 9. Call tuplesort_end() in leader. + * + * This division of labor assumes nothing about how input tuples are produced, + * but does require that caller combine the state of multiple tuplesorts for + * any purpose other than producing the final output. For example, callers + * must consider that tuplesort_get_stats() reports on only one worker's role + * in a sort (or the leader's role), and not statistics for the sort as a + * whole. + * + * Note that callers may use the leader process to sort runs as if it was an + * independent worker process (prior to the process performing a leader sort + * to produce the final sorted output). Doing so only requires a second + * "partial" tuplesort within the leader process, initialized like that of a + * worker process. The steps above don't touch on this directly. The only + * difference is that the tuplesort_attach_shared() call is never needed within + * leader process, because the backend as a whole holds the shared fileset + * reference. A worker Tuplesortstate in leader is expected to do exactly the + * same amount of total initial processing work as a worker process + * Tuplesortstate, since the leader process has nothing else to do before + * workers finish. + * + * Note that only a very small amount of memory will be allocated prior to + * the leader state first consuming input, and that workers will free the + * vast majority of their memory upon returning from tuplesort_performsort(). + * Callers can rely on this to arrange for memory to be used in a way that + * respects a workMem-style budget across an entire parallel sort operation. + * + * Callers are responsible for parallel safety in general. However, they + * can at least rely on there being no parallel safety hazards within + * tuplesort, because tuplesort thinks of the sort as several independent + * sorts whose results are combined. Since, in general, the behavior of + * sort operators is immutable, caller need only worry about the parallel + * safety of whatever the process is through which input tuples are + * generated (typically, caller uses a parallel heap scan). + */ + +extern Tuplesortstate *tuplesort_begin_heap(TupleDesc tupDesc, + int nkeys, AttrNumber *attNums, + Oid *sortOperators, Oid *sortCollations, + bool *nullsFirstFlags, + int workMem, SortCoordinate coordinate, + int sortopt); +extern Tuplesortstate *tuplesort_begin_cluster(TupleDesc tupDesc, + Relation indexRel, int workMem, + SortCoordinate coordinate, + int sortopt); +extern Tuplesortstate *tuplesort_begin_index_btree(Relation heapRel, + Relation indexRel, + bool enforceUnique, + bool uniqueNullsNotDistinct, + int workMem, SortCoordinate coordinate, + int sortopt); +extern Tuplesortstate *tuplesort_begin_index_hash(Relation heapRel, + Relation indexRel, + uint32 high_mask, + uint32 low_mask, + uint32 max_buckets, + int workMem, SortCoordinate coordinate, + int sortopt); +extern Tuplesortstate *tuplesort_begin_index_gist(Relation heapRel, + Relation indexRel, + int workMem, SortCoordinate coordinate, + int sortopt); +extern Tuplesortstate *tuplesort_begin_datum(Oid datumType, + Oid sortOperator, Oid sortCollation, + bool nullsFirstFlag, + int workMem, SortCoordinate coordinate, + int sortopt); + +extern void tuplesort_set_bound(Tuplesortstate *state, int64 bound); +extern bool tuplesort_used_bound(Tuplesortstate *state); + +extern void tuplesort_puttupleslot(Tuplesortstate *state, + TupleTableSlot *slot); +extern void tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup); +extern void tuplesort_putindextuplevalues(Tuplesortstate *state, + Relation rel, ItemPointer self, + Datum *values, bool *isnull); +extern void tuplesort_putdatum(Tuplesortstate *state, Datum val, + bool isNull); + +extern void tuplesort_performsort(Tuplesortstate *state); + +extern bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, + bool copy, TupleTableSlot *slot, Datum *abbrev); +extern HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward); +extern IndexTuple tuplesort_getindextuple(Tuplesortstate *state, bool forward); +extern bool tuplesort_getdatum(Tuplesortstate *state, bool forward, + Datum *val, bool *isNull, Datum *abbrev); + +extern bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, + bool forward); + +extern void tuplesort_end(Tuplesortstate *state); + +extern void tuplesort_reset(Tuplesortstate *state); + +extern void tuplesort_get_stats(Tuplesortstate *state, + TuplesortInstrumentation *stats); +extern const char *tuplesort_method_name(TuplesortMethod m); +extern const char *tuplesort_space_type_name(TuplesortSpaceType t); + +extern int tuplesort_merge_order(int64 allowedMem); + +extern Size tuplesort_estimate_shared(int nworkers); +extern void tuplesort_initialize_shared(Sharedsort *shared, int nWorkers, + dsm_segment *seg); +extern void tuplesort_attach_shared(Sharedsort *shared, dsm_segment *seg); + +/* + * These routines may only be called if TUPLESORT_RANDOMACCESS was specified + * during tuplesort_begin_*. Additionally backwards scan in gettuple/getdatum + * also require TUPLESORT_RANDOMACCESS. Note that parallel sorts do not + * support random access. + */ +extern void tuplesort_rescan(Tuplesortstate *state); +extern void tuplesort_markpos(Tuplesortstate *state); +extern void tuplesort_restorepos(Tuplesortstate *state); + +#endif /* TUPLESORT_H */ diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h new file mode 100644 index 0000000..01716fb --- /dev/null +++ b/src/include/utils/tuplestore.h @@ -0,0 +1,91 @@ +/*------------------------------------------------------------------------- + * + * tuplestore.h + * Generalized routines for temporary tuple storage. + * + * This module handles temporary storage of tuples for purposes such + * as Materialize nodes, hashjoin batch files, etc. It is essentially + * a dumbed-down version of tuplesort.c; it does no sorting of tuples + * but can only store and regurgitate a sequence of tuples. However, + * because no sort is required, it is allowed to start reading the sequence + * before it has all been written. This is particularly useful for cursors, + * because it allows random access within the already-scanned portion of + * a query without having to process the underlying scan to completion. + * Also, it is possible to support multiple independent read pointers. + * + * A temporary file is used to handle the data if it exceeds the + * space limit specified by the caller. + * + * Beginning in Postgres 8.2, what is stored is just MinimalTuples; + * callers cannot expect valid system columns in regurgitated tuples. + * Also, we have changed the API to return tuples in TupleTableSlots, + * so that there is a check to prevent attempted access to system columns. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/tuplestore.h + * + *------------------------------------------------------------------------- + */ +#ifndef TUPLESTORE_H +#define TUPLESTORE_H + +#include "executor/tuptable.h" + + +/* Tuplestorestate is an opaque type whose details are not known outside + * tuplestore.c. + */ +typedef struct Tuplestorestate Tuplestorestate; + +/* + * Currently we only need to store MinimalTuples, but it would be easy + * to support the same behavior for IndexTuples and/or bare Datums. + */ + +extern Tuplestorestate *tuplestore_begin_heap(bool randomAccess, + bool interXact, + int maxKBytes); + +extern void tuplestore_set_eflags(Tuplestorestate *state, int eflags); + +extern void tuplestore_puttupleslot(Tuplestorestate *state, + TupleTableSlot *slot); +extern void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple); +extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, + Datum *values, bool *isnull); + +/* Backwards compatibility macro */ +#define tuplestore_donestoring(state) ((void) 0) + +extern int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags); + +extern void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr); + +extern void tuplestore_copy_read_pointer(Tuplestorestate *state, + int srcptr, int destptr); + +extern void tuplestore_trim(Tuplestorestate *state); + +extern bool tuplestore_in_memory(Tuplestorestate *state); + +extern bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, + bool copy, TupleTableSlot *slot); + +extern bool tuplestore_advance(Tuplestorestate *state, bool forward); + +extern bool tuplestore_skiptuples(Tuplestorestate *state, + int64 ntuples, bool forward); + +extern int64 tuplestore_tuple_count(Tuplestorestate *state); + +extern bool tuplestore_ateof(Tuplestorestate *state); + +extern void tuplestore_rescan(Tuplestorestate *state); + +extern void tuplestore_clear(Tuplestorestate *state); + +extern void tuplestore_end(Tuplestorestate *state); + +#endif /* TUPLESTORE_H */ diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h new file mode 100644 index 0000000..431ad7f --- /dev/null +++ b/src/include/utils/typcache.h @@ -0,0 +1,209 @@ +/*------------------------------------------------------------------------- + * + * typcache.h + * Type cache definitions. + * + * The type cache exists to speed lookup of certain information about data + * types that is not directly available from a type's pg_type row. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/typcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef TYPCACHE_H +#define TYPCACHE_H + +#include "access/tupdesc.h" +#include "fmgr.h" +#include "storage/dsm.h" +#include "utils/dsa.h" + + +/* DomainConstraintCache is an opaque struct known only within typcache.c */ +typedef struct DomainConstraintCache DomainConstraintCache; + +/* TypeCacheEnumData is an opaque struct known only within typcache.c */ +struct TypeCacheEnumData; + +typedef struct TypeCacheEntry +{ + /* typeId is the hash lookup key and MUST BE FIRST */ + Oid type_id; /* OID of the data type */ + + uint32 type_id_hash; /* hashed value of the OID */ + + /* some subsidiary information copied from the pg_type row */ + int16 typlen; + bool typbyval; + char typalign; + char typstorage; + char typtype; + Oid typrelid; + Oid typsubscript; + Oid typelem; + Oid typcollation; + + /* + * Information obtained from opfamily entries + * + * These will be InvalidOid if no match could be found, or if the + * information hasn't yet been requested. Also note that for array and + * composite types, typcache.c checks that the contained types are + * comparable or hashable before allowing eq_opr etc to become set. + */ + Oid btree_opf; /* the default btree opclass' family */ + Oid btree_opintype; /* the default btree opclass' opcintype */ + Oid hash_opf; /* the default hash opclass' family */ + Oid hash_opintype; /* the default hash opclass' opcintype */ + Oid eq_opr; /* the equality operator */ + Oid lt_opr; /* the less-than operator */ + Oid gt_opr; /* the greater-than operator */ + Oid cmp_proc; /* the btree comparison function */ + Oid hash_proc; /* the hash calculation function */ + Oid hash_extended_proc; /* the extended hash calculation function */ + + /* + * Pre-set-up fmgr call info for the equality operator, the btree + * comparison function, and the hash calculation function. These are kept + * in the type cache to avoid problems with memory leaks in repeated calls + * to functions such as array_eq, array_cmp, hash_array. There is not + * currently a need to maintain call info for the lt_opr or gt_opr. + */ + FmgrInfo eq_opr_finfo; + FmgrInfo cmp_proc_finfo; + FmgrInfo hash_proc_finfo; + FmgrInfo hash_extended_proc_finfo; + + /* + * Tuple descriptor if it's a composite type (row type). NULL if not + * composite or information hasn't yet been requested. (NOTE: this is a + * reference-counted tupledesc.) + * + * To simplify caching dependent info, tupDesc_identifier is an identifier + * for this tupledesc that is unique for the life of the process, and + * changes anytime the tupledesc does. Zero if not yet determined. + */ + TupleDesc tupDesc; + uint64 tupDesc_identifier; + + /* + * Fields computed when TYPECACHE_RANGE_INFO is requested. Zeroes if not + * a range type or information hasn't yet been requested. Note that + * rng_cmp_proc_finfo could be different from the element type's default + * btree comparison function. + */ + struct TypeCacheEntry *rngelemtype; /* range's element type */ + Oid rng_collation; /* collation for comparisons, if any */ + FmgrInfo rng_cmp_proc_finfo; /* comparison function */ + FmgrInfo rng_canonical_finfo; /* canonicalization function, if any */ + FmgrInfo rng_subdiff_finfo; /* difference function, if any */ + + /* + * Fields computed when TYPECACHE_MULTIRANGE_INFO is required. + */ + struct TypeCacheEntry *rngtype; /* multirange's range underlying type */ + + /* + * Domain's base type and typmod if it's a domain type. Zeroes if not + * domain, or if information hasn't been requested. + */ + Oid domainBaseType; + int32 domainBaseTypmod; + + /* + * Domain constraint data if it's a domain type. NULL if not domain, or + * if domain has no constraints, or if information hasn't been requested. + */ + DomainConstraintCache *domainData; + + /* Private data, for internal use of typcache.c only */ + int flags; /* flags about what we've computed */ + + /* + * Private information about an enum type. NULL if not enum or + * information hasn't been requested. + */ + struct TypeCacheEnumData *enumData; + + /* We also maintain a list of all known domain-type cache entries */ + struct TypeCacheEntry *nextDomain; +} TypeCacheEntry; + +/* Bit flags to indicate which fields a given caller needs to have set */ +#define TYPECACHE_EQ_OPR 0x00001 +#define TYPECACHE_LT_OPR 0x00002 +#define TYPECACHE_GT_OPR 0x00004 +#define TYPECACHE_CMP_PROC 0x00008 +#define TYPECACHE_HASH_PROC 0x00010 +#define TYPECACHE_EQ_OPR_FINFO 0x00020 +#define TYPECACHE_CMP_PROC_FINFO 0x00040 +#define TYPECACHE_HASH_PROC_FINFO 0x00080 +#define TYPECACHE_TUPDESC 0x00100 +#define TYPECACHE_BTREE_OPFAMILY 0x00200 +#define TYPECACHE_HASH_OPFAMILY 0x00400 +#define TYPECACHE_RANGE_INFO 0x00800 +#define TYPECACHE_DOMAIN_BASE_INFO 0x01000 +#define TYPECACHE_DOMAIN_CONSTR_INFO 0x02000 +#define TYPECACHE_HASH_EXTENDED_PROC 0x04000 +#define TYPECACHE_HASH_EXTENDED_PROC_FINFO 0x08000 +#define TYPECACHE_MULTIRANGE_INFO 0x10000 + +/* This value will not equal any valid tupledesc identifier, nor 0 */ +#define INVALID_TUPLEDESC_IDENTIFIER ((uint64) 1) + +/* + * Callers wishing to maintain a long-lived reference to a domain's constraint + * set must store it in one of these. Use InitDomainConstraintRef() and + * UpdateDomainConstraintRef() to manage it. Note: DomainConstraintState is + * considered an executable expression type, so it's defined in execnodes.h. + */ +typedef struct DomainConstraintRef +{ + List *constraints; /* list of DomainConstraintState nodes */ + MemoryContext refctx; /* context holding DomainConstraintRef */ + TypeCacheEntry *tcache; /* typcache entry for domain type */ + bool need_exprstate; /* does caller need check_exprstate? */ + + /* Management data --- treat these fields as private to typcache.c */ + DomainConstraintCache *dcc; /* current constraints, or NULL if none */ + MemoryContextCallback callback; /* used to release refcount when done */ +} DomainConstraintRef; + +typedef struct SharedRecordTypmodRegistry SharedRecordTypmodRegistry; + +extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags); + +extern void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, + MemoryContext refctx, bool need_exprstate); + +extern void UpdateDomainConstraintRef(DomainConstraintRef *ref); + +extern bool DomainHasConstraints(Oid type_id); + +extern TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod); + +extern TupleDesc lookup_rowtype_tupdesc_noerror(Oid type_id, int32 typmod, + bool noError); + +extern TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod); + +extern TupleDesc lookup_rowtype_tupdesc_domain(Oid type_id, int32 typmod, + bool noError); + +extern void assign_record_type_typmod(TupleDesc tupDesc); + +extern uint64 assign_record_type_identifier(Oid type_id, int32 typmod); + +extern int compare_values_of_enum(TypeCacheEntry *tcache, Oid arg1, Oid arg2); + +extern size_t SharedRecordTypmodRegistryEstimate(void); + +extern void SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *, + dsm_segment *segment, dsa_area *area); + +extern void SharedRecordTypmodRegistryAttach(SharedRecordTypmodRegistry *); + +#endif /* TYPCACHE_H */ diff --git a/src/include/utils/tzparser.h b/src/include/utils/tzparser.h new file mode 100644 index 0000000..015b177 --- /dev/null +++ b/src/include/utils/tzparser.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * tzparser.h + * Timezone offset file parsing definitions. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/tzparser.h + * + *------------------------------------------------------------------------- + */ +#ifndef TZPARSER_H +#define TZPARSER_H + +#include "utils/datetime.h" + +/* + * The result of parsing a timezone configuration file is an array of + * these structs, in order by abbrev. We export this because datetime.c + * needs it. + */ +typedef struct tzEntry +{ + /* the actual data */ + char *abbrev; /* TZ abbreviation (downcased) */ + char *zone; /* zone name if dynamic abbrev, else NULL */ + /* for a dynamic abbreviation, offset/is_dst are not used */ + int offset; /* offset in seconds from UTC */ + bool is_dst; /* true if a DST abbreviation */ + /* source information (for error messages) */ + int lineno; + const char *filename; +} tzEntry; + + +extern TimeZoneAbbrevTable *load_tzoffsets(const char *filename); + +#endif /* TZPARSER_H */ diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h new file mode 100644 index 0000000..0029da4 --- /dev/null +++ b/src/include/utils/uuid.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * uuid.h + * Header file for the "uuid" ADT. In C, we use the name pg_uuid_t, + * to avoid conflicts with any uuid_t type that might be defined by + * the system headers. + * + * Copyright (c) 2007-2022, PostgreSQL Global Development Group + * + * src/include/utils/uuid.h + * + *------------------------------------------------------------------------- + */ +#ifndef UUID_H +#define UUID_H + +/* uuid size in bytes */ +#define UUID_LEN 16 + +typedef struct pg_uuid_t +{ + unsigned char data[UUID_LEN]; +} pg_uuid_t; + +/* fmgr interface macros */ +#define UUIDPGetDatum(X) PointerGetDatum(X) +#define PG_RETURN_UUID_P(X) return UUIDPGetDatum(X) +#define DatumGetUUIDP(X) ((pg_uuid_t *) DatumGetPointer(X)) +#define PG_GETARG_UUID_P(X) DatumGetUUIDP(PG_GETARG_DATUM(X)) + +#endif /* UUID_H */ diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h new file mode 100644 index 0000000..039ba86 --- /dev/null +++ b/src/include/utils/varbit.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- + * + * varbit.h + * Functions for the SQL datatypes BIT() and BIT VARYING(). + * + * Code originally contributed by Adriaan Joubert. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/varbit.h + * + *------------------------------------------------------------------------- + */ +#ifndef VARBIT_H +#define VARBIT_H + +#include <limits.h> + +#include "fmgr.h" + +/* + * Modeled on struct varlena from postgres.h, but data type is bits8. + * + * Caution: if bit_len is not a multiple of BITS_PER_BYTE, the low-order + * bits of the last byte of bit_dat[] are unused and MUST be zeroes. + * (This allows bit_cmp() to not bother masking the last byte.) + * Also, there should not be any excess bytes counted in the header length. + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int32 bit_len; /* number of valid bits */ + bits8 bit_dat[FLEXIBLE_ARRAY_MEMBER]; /* bit string, most sig. byte + * first */ +} VarBit; + +/* + * fmgr interface macros + * + * BIT and BIT VARYING are toastable varlena types. They are the same + * as far as representation goes, so we just have one set of macros. + */ +#define DatumGetVarBitP(X) ((VarBit *) PG_DETOAST_DATUM(X)) +#define DatumGetVarBitPCopy(X) ((VarBit *) PG_DETOAST_DATUM_COPY(X)) +#define VarBitPGetDatum(X) PointerGetDatum(X) +#define PG_GETARG_VARBIT_P(n) DatumGetVarBitP(PG_GETARG_DATUM(n)) +#define PG_GETARG_VARBIT_P_COPY(n) DatumGetVarBitPCopy(PG_GETARG_DATUM(n)) +#define PG_RETURN_VARBIT_P(x) return VarBitPGetDatum(x) + +/* Header overhead *in addition to* VARHDRSZ */ +#define VARBITHDRSZ sizeof(int32) +/* Number of bits in this bit string */ +#define VARBITLEN(PTR) (((VarBit *) (PTR))->bit_len) +/* Pointer to the first byte containing bit string data */ +#define VARBITS(PTR) (((VarBit *) (PTR))->bit_dat) +/* Number of bytes in the data section of a bit string */ +#define VARBITBYTES(PTR) (VARSIZE(PTR) - VARHDRSZ - VARBITHDRSZ) +/* Padding of the bit string at the end (in bits) */ +#define VARBITPAD(PTR) (VARBITBYTES(PTR)*BITS_PER_BYTE - VARBITLEN(PTR)) +/* Number of bytes needed to store a bit string of a given length */ +#define VARBITTOTALLEN(BITLEN) (((BITLEN) + BITS_PER_BYTE-1)/BITS_PER_BYTE + \ + VARHDRSZ + VARBITHDRSZ) +/* + * Maximum number of bits. Several code sites assume no overflow from + * computing bitlen + X; VARBITTOTALLEN() has the largest such X. + */ +#define VARBITMAXLEN (INT_MAX - BITS_PER_BYTE + 1) +/* pointer beyond the end of the bit string (like end() in STL containers) */ +#define VARBITEND(PTR) (((bits8 *) (PTR)) + VARSIZE(PTR)) +/* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */ +#define BITMASK 0xFF + +#endif diff --git a/src/include/utils/varlena.h b/src/include/utils/varlena.h new file mode 100644 index 0000000..c45208a --- /dev/null +++ b/src/include/utils/varlena.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------- + * + * varlena.h + * Functions for the variable-length built-in types. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/varlena.h + * + *------------------------------------------------------------------------- + */ +#ifndef VARLENA_H +#define VARLENA_H + +#include "nodes/pg_list.h" +#include "utils/sortsupport.h" + +extern int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid); +extern void varstr_sortsupport(SortSupport ssup, Oid typid, Oid collid); +extern int varstr_levenshtein(const char *source, int slen, + const char *target, int tlen, + int ins_c, int del_c, int sub_c, + bool trusted); +extern int varstr_levenshtein_less_equal(const char *source, int slen, + const char *target, int tlen, + int ins_c, int del_c, int sub_c, + int max_d, bool trusted); +extern List *textToQualifiedNameList(text *textval); +extern bool SplitIdentifierString(char *rawstring, char separator, + List **namelist); +extern bool SplitDirectoriesString(char *rawstring, char separator, + List **namelist); +extern bool SplitGUCList(char *rawstring, char separator, + List **namelist); +extern text *replace_text_regexp(text *src_text, text *pattern_text, + text *replace_text, + int cflags, Oid collation, + int search_start, int n); + +#endif diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h new file mode 100644 index 0000000..b578e2e --- /dev/null +++ b/src/include/utils/wait_event.h @@ -0,0 +1,289 @@ +/*------------------------------------------------------------------------- + * wait_event.h + * Definitions related to wait event reporting + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * src/include/utils/wait_event.h + * ---------- + */ +#ifndef WAIT_EVENT_H +#define WAIT_EVENT_H + + +/* ---------- + * Wait Classes + * ---------- + */ +#define PG_WAIT_LWLOCK 0x01000000U +#define PG_WAIT_LOCK 0x03000000U +#define PG_WAIT_BUFFER_PIN 0x04000000U +#define PG_WAIT_ACTIVITY 0x05000000U +#define PG_WAIT_CLIENT 0x06000000U +#define PG_WAIT_EXTENSION 0x07000000U +#define PG_WAIT_IPC 0x08000000U +#define PG_WAIT_TIMEOUT 0x09000000U +#define PG_WAIT_IO 0x0A000000U + +/* ---------- + * Wait Events - Activity + * + * Use this category when a process is waiting because it has no work to do, + * unless the "Client" or "Timeout" category describes the situation better. + * Typically, this should only be used for background processes. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_ARCHIVER_MAIN = PG_WAIT_ACTIVITY, + WAIT_EVENT_AUTOVACUUM_MAIN, + WAIT_EVENT_BGWRITER_HIBERNATE, + WAIT_EVENT_BGWRITER_MAIN, + WAIT_EVENT_CHECKPOINTER_MAIN, + WAIT_EVENT_LOGICAL_APPLY_MAIN, + WAIT_EVENT_LOGICAL_LAUNCHER_MAIN, + WAIT_EVENT_RECOVERY_WAL_STREAM, + WAIT_EVENT_SYSLOGGER_MAIN, + WAIT_EVENT_WAL_RECEIVER_MAIN, + WAIT_EVENT_WAL_SENDER_MAIN, + WAIT_EVENT_WAL_WRITER_MAIN +} WaitEventActivity; + +/* ---------- + * Wait Events - Client + * + * Use this category when a process is waiting to send data to or receive data + * from the frontend process to which it is connected. This is never used for + * a background process, which has no client connection. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_CLIENT_READ = PG_WAIT_CLIENT, + WAIT_EVENT_CLIENT_WRITE, + WAIT_EVENT_GSS_OPEN_SERVER, + WAIT_EVENT_LIBPQWALRECEIVER_CONNECT, + WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE, + WAIT_EVENT_SSL_OPEN_SERVER, + WAIT_EVENT_WAL_SENDER_WAIT_WAL, + WAIT_EVENT_WAL_SENDER_WRITE_DATA, +} WaitEventClient; + +/* ---------- + * Wait Events - IPC + * + * Use this category when a process cannot complete the work it is doing because + * it is waiting for a notification from another process. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_APPEND_READY = PG_WAIT_IPC, + WAIT_EVENT_ARCHIVE_CLEANUP_COMMAND, + WAIT_EVENT_ARCHIVE_COMMAND, + WAIT_EVENT_BACKEND_TERMINATION, + WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE, + WAIT_EVENT_BGWORKER_SHUTDOWN, + WAIT_EVENT_BGWORKER_STARTUP, + WAIT_EVENT_BTREE_PAGE, + WAIT_EVENT_BUFFER_IO, + WAIT_EVENT_CHECKPOINT_DONE, + WAIT_EVENT_CHECKPOINT_START, + WAIT_EVENT_EXECUTE_GATHER, + WAIT_EVENT_HASH_BATCH_ALLOCATE, + WAIT_EVENT_HASH_BATCH_ELECT, + WAIT_EVENT_HASH_BATCH_LOAD, + WAIT_EVENT_HASH_BUILD_ALLOCATE, + WAIT_EVENT_HASH_BUILD_ELECT, + WAIT_EVENT_HASH_BUILD_HASH_INNER, + WAIT_EVENT_HASH_BUILD_HASH_OUTER, + WAIT_EVENT_HASH_GROW_BATCHES_ALLOCATE, + WAIT_EVENT_HASH_GROW_BATCHES_DECIDE, + WAIT_EVENT_HASH_GROW_BATCHES_ELECT, + WAIT_EVENT_HASH_GROW_BATCHES_FINISH, + WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION, + WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATE, + WAIT_EVENT_HASH_GROW_BUCKETS_ELECT, + WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT, + WAIT_EVENT_LOGICAL_SYNC_DATA, + WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE, + WAIT_EVENT_MQ_INTERNAL, + WAIT_EVENT_MQ_PUT_MESSAGE, + WAIT_EVENT_MQ_RECEIVE, + WAIT_EVENT_MQ_SEND, + WAIT_EVENT_PARALLEL_BITMAP_SCAN, + WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN, + WAIT_EVENT_PARALLEL_FINISH, + WAIT_EVENT_PROCARRAY_GROUP_UPDATE, + WAIT_EVENT_PROC_SIGNAL_BARRIER, + WAIT_EVENT_PROMOTE, + WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT, + WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE, + WAIT_EVENT_RECOVERY_END_COMMAND, + WAIT_EVENT_RECOVERY_PAUSE, + WAIT_EVENT_REPLICATION_ORIGIN_DROP, + WAIT_EVENT_REPLICATION_SLOT_DROP, + WAIT_EVENT_RESTORE_COMMAND, + WAIT_EVENT_SAFE_SNAPSHOT, + WAIT_EVENT_SYNC_REP, + WAIT_EVENT_WAL_RECEIVER_EXIT, + WAIT_EVENT_WAL_RECEIVER_WAIT_START, + WAIT_EVENT_XACT_GROUP_UPDATE +} WaitEventIPC; + +/* ---------- + * Wait Events - Timeout + * + * Use this category when a process is waiting for a timeout to expire. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_BASE_BACKUP_THROTTLE = PG_WAIT_TIMEOUT, + WAIT_EVENT_CHECKPOINT_WRITE_DELAY, + WAIT_EVENT_PG_SLEEP, + WAIT_EVENT_RECOVERY_APPLY_DELAY, + WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL, + WAIT_EVENT_REGISTER_SYNC_REQUEST, + WAIT_EVENT_VACUUM_DELAY, + WAIT_EVENT_VACUUM_TRUNCATE +} WaitEventTimeout; + +/* ---------- + * Wait Events - IO + * + * Use this category when a process is waiting for a IO. + * ---------- + */ +typedef enum +{ + WAIT_EVENT_BASEBACKUP_READ = PG_WAIT_IO, + WAIT_EVENT_BASEBACKUP_SYNC, + WAIT_EVENT_BASEBACKUP_WRITE, + WAIT_EVENT_BUFFILE_READ, + WAIT_EVENT_BUFFILE_WRITE, + WAIT_EVENT_BUFFILE_TRUNCATE, + WAIT_EVENT_CONTROL_FILE_READ, + WAIT_EVENT_CONTROL_FILE_SYNC, + WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE, + WAIT_EVENT_CONTROL_FILE_WRITE, + WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE, + WAIT_EVENT_COPY_FILE_READ, + WAIT_EVENT_COPY_FILE_WRITE, + WAIT_EVENT_DATA_FILE_EXTEND, + WAIT_EVENT_DATA_FILE_FLUSH, + WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC, + WAIT_EVENT_DATA_FILE_PREFETCH, + WAIT_EVENT_DATA_FILE_READ, + WAIT_EVENT_DATA_FILE_SYNC, + WAIT_EVENT_DATA_FILE_TRUNCATE, + WAIT_EVENT_DATA_FILE_WRITE, + WAIT_EVENT_DSM_FILL_ZERO_WRITE, + WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ, + WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC, + WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE, + WAIT_EVENT_LOCK_FILE_CREATE_READ, + WAIT_EVENT_LOCK_FILE_CREATE_SYNC, + WAIT_EVENT_LOCK_FILE_CREATE_WRITE, + WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ, + WAIT_EVENT_LOGICAL_REWRITE_CHECKPOINT_SYNC, + WAIT_EVENT_LOGICAL_REWRITE_MAPPING_SYNC, + WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE, + WAIT_EVENT_LOGICAL_REWRITE_SYNC, + WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE, + WAIT_EVENT_LOGICAL_REWRITE_WRITE, + WAIT_EVENT_RELATION_MAP_READ, + WAIT_EVENT_RELATION_MAP_SYNC, + WAIT_EVENT_RELATION_MAP_WRITE, + WAIT_EVENT_REORDER_BUFFER_READ, + WAIT_EVENT_REORDER_BUFFER_WRITE, + WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ, + WAIT_EVENT_REPLICATION_SLOT_READ, + WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC, + WAIT_EVENT_REPLICATION_SLOT_SYNC, + WAIT_EVENT_REPLICATION_SLOT_WRITE, + WAIT_EVENT_SLRU_FLUSH_SYNC, + WAIT_EVENT_SLRU_READ, + WAIT_EVENT_SLRU_SYNC, + WAIT_EVENT_SLRU_WRITE, + WAIT_EVENT_SNAPBUILD_READ, + WAIT_EVENT_SNAPBUILD_SYNC, + WAIT_EVENT_SNAPBUILD_WRITE, + WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC, + WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE, + WAIT_EVENT_TIMELINE_HISTORY_READ, + WAIT_EVENT_TIMELINE_HISTORY_SYNC, + WAIT_EVENT_TIMELINE_HISTORY_WRITE, + WAIT_EVENT_TWOPHASE_FILE_READ, + WAIT_EVENT_TWOPHASE_FILE_SYNC, + WAIT_EVENT_TWOPHASE_FILE_WRITE, + WAIT_EVENT_VERSION_FILE_WRITE, + WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ, + WAIT_EVENT_WAL_BOOTSTRAP_SYNC, + WAIT_EVENT_WAL_BOOTSTRAP_WRITE, + WAIT_EVENT_WAL_COPY_READ, + WAIT_EVENT_WAL_COPY_SYNC, + WAIT_EVENT_WAL_COPY_WRITE, + WAIT_EVENT_WAL_INIT_SYNC, + WAIT_EVENT_WAL_INIT_WRITE, + WAIT_EVENT_WAL_READ, + WAIT_EVENT_WAL_SYNC, + WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN, + WAIT_EVENT_WAL_WRITE +} WaitEventIO; + + +extern const char *pgstat_get_wait_event(uint32 wait_event_info); +extern const char *pgstat_get_wait_event_type(uint32 wait_event_info); +static inline void pgstat_report_wait_start(uint32 wait_event_info); +static inline void pgstat_report_wait_end(void); +extern void pgstat_set_wait_event_storage(uint32 *wait_event_info); +extern void pgstat_reset_wait_event_storage(void); + +extern PGDLLIMPORT uint32 *my_wait_event_info; + + +/* ---------- + * pgstat_report_wait_start() - + * + * Called from places where server process needs to wait. This is called + * to report wait event information. The wait information is stored + * as 4-bytes where first byte represents the wait event class (type of + * wait, for different types of wait, refer WaitClass) and the next + * 3-bytes represent the actual wait event. Currently 2-bytes are used + * for wait event which is sufficient for current usage, 1-byte is + * reserved for future usage. + * + * Historically we used to make this reporting conditional on + * pgstat_track_activities, but the check for that seems to add more cost + * than it saves. + * + * my_wait_event_info initially points to local memory, making it safe to + * call this before MyProc has been initialized. + * ---------- + */ +static inline void +pgstat_report_wait_start(uint32 wait_event_info) +{ + /* + * Since this is a four-byte field which is always read and written as + * four-bytes, updates are atomic. + */ + *(volatile uint32 *) my_wait_event_info = wait_event_info; +} + +/* ---------- + * pgstat_report_wait_end() - + * + * Called to report end of a wait. + * ---------- + */ +static inline void +pgstat_report_wait_end(void) +{ + /* see pgstat_report_wait_start() */ + *(volatile uint32 *) my_wait_event_info = 0; +} + + +#endif /* WAIT_EVENT_H */ diff --git a/src/include/utils/xid8.h b/src/include/utils/xid8.h new file mode 100644 index 0000000..b702fc1 --- /dev/null +++ b/src/include/utils/xid8.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * xid8.h + * Header file for the "xid8" ADT. + * + * Copyright (c) 2020-2022, PostgreSQL Global Development Group + * + * src/include/utils/xid8.h + * + *------------------------------------------------------------------------- + */ +#ifndef XID8_H +#define XID8_H + +#include "access/transam.h" + +#define DatumGetFullTransactionId(X) (FullTransactionIdFromU64(DatumGetUInt64(X))) +#define FullTransactionIdGetDatum(X) (UInt64GetDatum(U64FromFullTransactionId(X))) +#define PG_GETARG_FULLTRANSACTIONID(X) DatumGetFullTransactionId(PG_GETARG_DATUM(X)) +#define PG_RETURN_FULLTRANSACTIONID(X) return FullTransactionIdGetDatum(X) + +#endif /* XID8_H */ diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h new file mode 100644 index 0000000..6620a62 --- /dev/null +++ b/src/include/utils/xml.h @@ -0,0 +1,84 @@ +/*------------------------------------------------------------------------- + * + * xml.h + * Declarations for XML data type support. + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/xml.h + * + *------------------------------------------------------------------------- + */ + +#ifndef XML_H +#define XML_H + +#include "executor/tablefunc.h" +#include "fmgr.h" +#include "nodes/execnodes.h" +#include "nodes/primnodes.h" + +typedef struct varlena xmltype; + +typedef enum +{ + XML_STANDALONE_YES, + XML_STANDALONE_NO, + XML_STANDALONE_NO_VALUE, + XML_STANDALONE_OMITTED +} XmlStandaloneType; + +typedef enum +{ + XMLBINARY_BASE64, + XMLBINARY_HEX +} XmlBinaryType; + +typedef enum +{ + PG_XML_STRICTNESS_LEGACY, /* ignore errors unless function result + * indicates error condition */ + PG_XML_STRICTNESS_WELLFORMED, /* ignore non-parser messages */ + PG_XML_STRICTNESS_ALL /* report all notices/warnings/errors */ +} PgXmlStrictness; + +/* struct PgXmlErrorContext is private to xml.c */ +typedef struct PgXmlErrorContext PgXmlErrorContext; + +#define DatumGetXmlP(X) ((xmltype *) PG_DETOAST_DATUM(X)) +#define XmlPGetDatum(X) PointerGetDatum(X) + +#define PG_GETARG_XML_P(n) DatumGetXmlP(PG_GETARG_DATUM(n)) +#define PG_RETURN_XML_P(x) PG_RETURN_POINTER(x) + +extern void pg_xml_init_library(void); +extern PgXmlErrorContext *pg_xml_init(PgXmlStrictness strictness); +extern void pg_xml_done(PgXmlErrorContext *errcxt, bool isError); +extern bool pg_xml_error_occurred(PgXmlErrorContext *errcxt); +extern void xml_ereport(PgXmlErrorContext *errcxt, int level, int sqlcode, + const char *msg); + +extern xmltype *xmlconcat(List *args); +extern xmltype *xmlelement(XmlExpr *xexpr, + Datum *named_argvalue, bool *named_argnull, + Datum *argvalue, bool *argnull); +extern xmltype *xmlparse(text *data, XmlOptionType xmloption, bool preserve_whitespace); +extern xmltype *xmlpi(const char *target, text *arg, bool arg_is_null, bool *result_is_null); +extern xmltype *xmlroot(xmltype *data, text *version, int standalone); +extern bool xml_is_document(xmltype *arg); +extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg); +extern char *escape_xml(const char *str); + +extern char *map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period); +extern char *map_xml_name_to_sql_identifier(const char *name); +extern char *map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings); + +extern PGDLLIMPORT int xmlbinary; /* XmlBinaryType, but int for guc enum */ + +extern PGDLLIMPORT int xmloption; /* XmlOptionType, but int for guc enum */ + +extern PGDLLIMPORT const TableFuncRoutine XmlTableRoutine; + +#endif /* XML_H */ diff --git a/src/include/windowapi.h b/src/include/windowapi.h new file mode 100644 index 0000000..5a620a2 --- /dev/null +++ b/src/include/windowapi.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * windowapi.h + * API for window functions to extract data from their window + * + * A window function does not receive its arguments in the normal way + * (and therefore the concept of strictness is irrelevant). Instead it + * receives a "WindowObject", which it can fetch with PG_WINDOW_OBJECT() + * (note V1 calling convention must be used). Correct call context can + * be tested with WindowObjectIsValid(). Although argument values are + * not passed, the call is correctly set up so that PG_NARGS() can be + * used and argument type information can be obtained with + * get_fn_expr_argtype(), get_fn_expr_arg_stable(), etc. + * + * Operations on the WindowObject allow the window function to find out + * the current row number, total number of rows in the partition, etc + * and to evaluate its argument expression(s) at various rows in the + * window partition. See the header comments for each WindowObject API + * function in nodeWindowAgg.c for details. + * + * + * Portions Copyright (c) 2000-2022, PostgreSQL Global Development Group + * + * src/include/windowapi.h + * + *------------------------------------------------------------------------- + */ +#ifndef WINDOWAPI_H +#define WINDOWAPI_H + +/* values of "seektype" */ +#define WINDOW_SEEK_CURRENT 0 +#define WINDOW_SEEK_HEAD 1 +#define WINDOW_SEEK_TAIL 2 + +/* this struct is private in nodeWindowAgg.c */ +typedef struct WindowObjectData *WindowObject; + +#define PG_WINDOW_OBJECT() ((WindowObject) fcinfo->context) + +#define WindowObjectIsValid(winobj) \ + ((winobj) != NULL && IsA(winobj, WindowObjectData)) + +extern void *WinGetPartitionLocalMemory(WindowObject winobj, Size sz); + +extern int64 WinGetCurrentPosition(WindowObject winobj); +extern int64 WinGetPartitionRowCount(WindowObject winobj); + +extern void WinSetMarkPosition(WindowObject winobj, int64 markpos); + +extern bool WinRowsArePeers(WindowObject winobj, int64 pos1, int64 pos2); + +extern Datum WinGetFuncArgInPartition(WindowObject winobj, int argno, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout); + +extern Datum WinGetFuncArgInFrame(WindowObject winobj, int argno, + int relpos, int seektype, bool set_mark, + bool *isnull, bool *isout); + +extern Datum WinGetFuncArgCurrent(WindowObject winobj, int argno, + bool *isnull); + +#endif /* WINDOWAPI_H */ |