diff options
Diffstat (limited to 'src/include/utils')
96 files changed, 14746 insertions, 0 deletions
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..aba1afa --- /dev/null +++ b/src/include/utils/acl.h @@ -0,0 +1,278 @@ +/*------------------------------------------------------------------------- + * + * acl.h + * Definition of (and support for) access control list data structures. + * + * + * Portions Copyright (c) 1996-2023, 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 32 bits of the ai_privs field of an AclItem are the grant option + * bits, and the lower 32 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 & 0xFFFFFFFF) +#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 32) & 0xFFFFFFFF) +#define ACLITEM_GET_RIGHTS(item) ((item).ai_privs) + +#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0xFFFFFFFF) << 32) +#define ACL_OPTION_TO_PRIVS(privs) (((AclMode) (privs) >> 32) & 0xFFFFFFFF) + +#define ACLITEM_SET_PRIVS(item,privs) \ + ((item).ai_privs = ((item).ai_privs & ~((AclMode) 0xFFFFFFFF)) | \ + ((AclMode) (privs) & 0xFFFFFFFF)) +#define ACLITEM_SET_GOPTIONS(item,goptions) \ + ((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0xFFFFFFFF) << 32)) | \ + (((AclMode) (goptions) & 0xFFFFFFFF) << 32)) +#define ACLITEM_SET_RIGHTS(item,rights) \ + ((item).ai_privs = (AclMode) (rights)) + +#define ACLITEM_SET_PRIVS_GOPTIONS(item,privs,goptions) \ + ((item).ai_privs = ((AclMode) (privs) & 0xFFFFFFFF) | \ + (((AclMode) (goptions) & 0xFFFFFFFF) << 32)) + + +#define ACLITEM_ALL_PRIV_BITS ((AclMode) 0xFFFFFFFF) +#define ACLITEM_ALL_GOPTION_BITS ((AclMode) 0xFFFFFFFF << 32) + +/* + * 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 member_can_set_role(Oid member, Oid role); +extern void check_can_set_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 Oid select_best_admin(Oid member, Oid role); +extern Oid get_role_oid(const char *rolname, bool missing_ok); +extern Oid get_role_oid_or_public(const char *rolname); +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_class_aclmask(Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how); + +/* generic function */ +extern AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode); + +/* special cases */ +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_parameter_aclcheck(const char *name, Oid roleid, + AclMode mode); +extern AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, + AclMode mode, Snapshot snapshot); + +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 object_ownercheck(Oid classid, Oid objectid, 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..55af624 --- /dev/null +++ b/src/include/utils/aclchk_internal.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * aclchk_internal.h + * + * Portions Copyright (c) 1996-2023, 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..e6c8d88 --- /dev/null +++ b/src/include/utils/array.h @@ -0,0 +1,482 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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_array_builtin(Datum *elems, int nelems, Oid elmtype); +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 void deconstruct_array_builtin(ArrayType *array, + Oid elmtype, + 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 *initArrayResultWithSize(Oid element_type, + MemoryContext rcontext, + bool subcontext, int initsize); +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 int ArrayGetNItemsSafe(int ndim, const int *dims, + struct Node *escontext); +extern void ArrayCheckBounds(int ndim, const int *dims, const int *lb); +extern bool ArrayCheckBoundsSafe(int ndim, const int *dims, const int *lb, + struct Node *escontext); +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..fd267d5 --- /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-2023, 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..7df024d --- /dev/null +++ b/src/include/utils/ascii.h @@ -0,0 +1,84 @@ +/*----------------------------------------------------------------------- + * ascii.h + * + * Portions Copyright (c) 1999-2023, PostgreSQL Global Development Group + * + * src/include/utils/ascii.h + * + *----------------------------------------------------------------------- + */ + +#ifndef _ASCII_H_ +#define _ASCII_H_ + +#include "port/simd.h" + +extern void ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz); + +/* + * 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 the chunk size (8 or 16). + */ +static inline bool +is_valid_ascii(const unsigned char *s, int len) +{ + const unsigned char *const s_end = s + len; + Vector8 chunk; + Vector8 highbit_cum = vector8_broadcast(0); +#ifdef USE_NO_SIMD + Vector8 zero_cum = vector8_broadcast(0x80); +#endif + + Assert(len % sizeof(chunk) == 0); + + while (s < s_end) + { + vector8_load(&chunk, s); + + /* Capture any zero bytes in this chunk. */ +#ifdef USE_NO_SIMD + + /* + * 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 + vector8_broadcast(0x7F)); +#else + + /* + * Set all bits in each lane of the highbit accumulator where input + * bytes are zero. + */ + highbit_cum = vector8_or(highbit_cum, + vector8_eq(chunk, vector8_broadcast(0))); +#endif + + /* Capture all set bits in this chunk. */ + highbit_cum = vector8_or(highbit_cum, chunk); + + s += sizeof(chunk); + } + + /* Check if any high bits in the high bit accumulator got set. */ + if (vector8_is_highbit_set(highbit_cum)) + return false; + +#ifdef USE_NO_SIMD + /* Check if any high bits in the zero accumulator got cleared. */ + if (zero_cum != vector8_broadcast(0x80)) + return false; +#endif + + return true; +} + +#endif /* _ASCII_H_ */ diff --git a/src/include/utils/attoptcache.h b/src/include/utils/attoptcache.h new file mode 100644 index 0000000..e4119b6 --- /dev/null +++ b/src/include/utils/attoptcache.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * attoptcache.h + * Attribute options cache. + * + * Portions Copyright (c) 1996-2023, 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 attrelid, 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..a84752a --- /dev/null +++ b/src/include/utils/backend_progress.h @@ -0,0 +1,45 @@ +/* ---------- + * 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-2023, 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_incr_param(int index, int64 incr); +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..d51c840 --- /dev/null +++ b/src/include/utils/backend_status.h @@ -0,0 +1,342 @@ +/* ---------- + * backend_status.h + * Definitions related to backend status reporting + * + * Copyright (c) 2001-2023, 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 "storage/backendid.h" +#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 */ + bool gss_delegation; /* If credentials delegated */ + +} 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 backend ID. For auxiliary processes, this will be set to a value + * greater than MaxBackends (since auxiliary processes do not have proper + * backend IDs). + */ + BackendId backend_id; + + /* + * 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; + + /* + * Number of cached subtransactions in the current session. + */ + int backend_subxact_count; + + /* + * The number of subtransactions in the current session which exceeded the + * cached subtransaction limit. + */ + bool backend_subxact_overflowed; +} 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_get_beentry_by_backend_id(BackendId beid); +extern LocalPgBackendStatus *pgstat_get_local_beentry_by_backend_id(BackendId beid); +extern LocalPgBackendStatus *pgstat_get_local_beentry_by_index(int idx); +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..2f8b46d --- /dev/null +++ b/src/include/utils/builtins.h @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------- + * + * builtins.h + * Declarations for operations on built-in types. + * + * + * Portions Copyright (c) 1996-2023, 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); +extern uint64 hex_decode_safe(const char *src, size_t len, char *dst, + Node *escontext); + +/* 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 int16 pg_strtoint16_safe(const char *s, Node *escontext); +extern int32 pg_strtoint32(const char *s); +extern int32 pg_strtoint32_safe(const char *s, Node *escontext); +extern int64 pg_strtoint64(const char *s); +extern int64 pg_strtoint64_safe(const char *s, Node *escontext); +extern uint32 uint32in_subr(const char *s, char **endloc, + const char *typname, Node *escontext); +extern uint64 uint64in_subr(const char *s, char **endloc, + const char *typname, Node *escontext); +extern int pg_itoa(int16 i, char *a); +extern int pg_ultoa_n(uint32 value, char *a); +extern int pg_ulltoa_n(uint64 value, char *a); +extern int pg_ltoa(int32 value, char *a); +extern int pg_lltoa(int64 value, 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..166dd03 --- /dev/null +++ b/src/include/utils/bytea.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * bytea.h + * Declarations for BYTEA data type support. + * + * + * Portions Copyright (c) 1996-2023, 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..55d45fa --- /dev/null +++ b/src/include/utils/cash.h @@ -0,0 +1,35 @@ +/* + * 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 */ +static inline Cash +DatumGetCash(Datum X) +{ + return DatumGetInt64(X); +} + +static inline Datum +CashGetDatum(Cash X) +{ + return 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..af0b341 --- /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-2023, 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..2b496ee --- /dev/null +++ b/src/include/utils/combocid.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * combocid.h + * Combo command ID support routines + * + * + * Portions Copyright (c) 1996-2023, 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/conffiles.h b/src/include/utils/conffiles.h new file mode 100644 index 0000000..e3868fb --- /dev/null +++ b/src/include/utils/conffiles.h @@ -0,0 +1,27 @@ +/*-------------------------------------------------------------------- + * conffiles.h + * + * Utilities related to configuration files. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/conffiles.h + * + *-------------------------------------------------------------------- + */ +#ifndef CONFFILES_H +#define CONFFILES_H + +/* recursion nesting depth for configuration files */ +#define CONF_FILE_START_DEPTH 0 +#define CONF_FILE_MAX_DEPTH 10 + +extern char *AbsoluteConfigLocation(const char *location, + const char *calling_file); +extern char **GetConfFilesInDir(const char *includedir, + const char *calling_file, + int elevel, int *num_filenames, + char **err_msg); + +#endif /* CONFFILES_H */ diff --git a/src/include/utils/date.h b/src/include/utils/date.h new file mode 100644 index 0000000..97e1a02 --- /dev/null +++ b/src/include/utils/date.h @@ -0,0 +1,118 @@ +/*------------------------------------------------------------------------- + * + * date.h + * Definitions for the SQL "date" and "time" types. + * + * + * Portions Copyright (c) 1996-2023, 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)) + +#define MAX_TIME_PRECISION 6 + +/* + * Functions 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! + */ +static inline DateADT +DatumGetDateADT(Datum X) +{ + return (DateADT) DatumGetInt32(X); +} + +static inline TimeADT +DatumGetTimeADT(Datum X) +{ + return (TimeADT) DatumGetInt64(X); +} + +static inline TimeTzADT * +DatumGetTimeTzADTP(Datum X) +{ + return (TimeTzADT *) DatumGetPointer(X); +} + +static inline Datum +DateADTGetDatum(DateADT X) +{ + return Int32GetDatum(X); +} + +static inline Datum +TimeADTGetDatum(TimeADT X) +{ + return Int64GetDatum(X); +} + +static inline Datum +TimeTzADTPGetDatum(const TimeTzADT *X) +{ + return 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..a871e32 --- /dev/null +++ b/src/include/utils/datetime.h @@ -0,0 +1,364 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 "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 suitable error report. For some of these codes, + * DateTimeParseError requires additional information, which is carried + * in struct DateTimeErrorExtra. + */ +#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) +#define DTERR_BAD_TIMEZONE (-6) +#define DTERR_BAD_ZONE_ABBREV (-7) + +typedef struct DateTimeErrorExtra +{ + /* Needed for DTERR_BAD_TIMEZONE and DTERR_BAD_ZONE_ABBREV: */ + const char *dtee_timezone; /* incorrect time zone name */ + /* Needed for DTERR_BAD_ZONE_ABBREV: */ + const char *dtee_abbrev; /* relevant time zone abbreviation */ +} DateTimeErrorExtra; + +/* Result codes for DecodeTimezoneName() */ +#define TZNAME_FIXED_OFFSET 0 +#define TZNAME_DYNTZ 1 +#define TZNAME_ZONE 2 + + +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, + DateTimeErrorExtra *extra); +extern int DecodeTimezone(const char *str, int *tzp); +extern int DecodeTimeOnly(char **field, int *ftype, int nf, + int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, + DateTimeErrorExtra *extra); +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, DateTimeErrorExtra *extra, + const char *str, const char *datatype, + struct Node *escontext); + +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, const char *lowtoken, + int *ftype, int *offset, pg_tz **tz, + DateTimeErrorExtra *extra); +extern int DecodeSpecial(int field, const char *lowtoken, int *val); +extern int DecodeUnits(int field, const char *lowtoken, int *val); + +extern int DecodeTimezoneName(const char *tzname, int *offset, pg_tz **tz); +extern pg_tz *DecodeTimezoneNameToTz(const char *tzname); + +extern int j2day(int date); + +extern struct Node *TemporalSimplify(int32 max_precis, struct Node *node); + +extern bool CheckDateTokenTables(void); + +extern TimeZoneAbbrevTable *ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, + int n); +extern void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl); + +extern bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, + struct Node *escontext); + +#endif /* DATETIME_H */ diff --git a/src/include/utils/datum.h b/src/include/utils/datum.h new file mode 100644 index 0000000..70a47f3 --- /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-2023, 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..3ce4ee3 --- /dev/null +++ b/src/include/utils/dsa.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------- + * + * dsa.h + * Dynamic shared memory areas. + * + * Portions Copyright (c) 1996-2023, 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; + +/* Sentinel value to use for invalid dsa_handles. */ +#define DSA_HANDLE_INVALID ((dsa_handle) DSM_HANDLE_INVALID) + + +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..866677a --- /dev/null +++ b/src/include/utils/dynahash.h @@ -0,0 +1,20 @@ +/*------------------------------------------------------------------------- + * + * dynahash.h + * POSTGRES dynahash.h file definitions + * + * + * Portions Copyright (c) 1996-2023, 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..0292e88 --- /dev/null +++ b/src/include/utils/elog.h @@ -0,0 +1,545 @@ +/*------------------------------------------------------------------------- + * + * elog.h + * POSTGRES error reporting/logging definitions. + * + * + * Portions Copyright (c) 1996-2023, 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> + +#include "lib/stringinfo.h" + +/* We cannot include nodes.h yet, so forward-declare struct Node */ +struct Node; + + +/* 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__, __func__); \ + 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__, __func__); \ + 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 reporting "soft" errors that don't require a full transaction + * abort to clean up. This is to be used in this way: + * errsave(context, + * errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + * errmsg("invalid input syntax for type %s: \"%s\"", + * "boolean", in_str), + * ... other errxxx() fields as needed ...); + * + * "context" is a node pointer or NULL, and the remaining auxiliary calls + * provide the same error details as in ereport(). If context is not a + * pointer to an ErrorSaveContext node, then errsave(context, ...) + * behaves identically to ereport(ERROR, ...). If context is a pointer + * to an ErrorSaveContext node, then the information provided by the + * auxiliary calls is stored in the context node and control returns + * normally. The caller of errsave() must then do any required cleanup + * and return control back to its caller. That caller must check the + * ErrorSaveContext node to see whether an error occurred before + * it can trust the function's result to be meaningful. + * + * errsave_domain() allows a message domain to be specified; it is + * precisely analogous to ereport_domain(). + *---------- + */ +#define errsave_domain(context, domain, ...) \ + do { \ + struct Node *context_ = (context); \ + pg_prevent_errno_in_scope(); \ + if (errsave_start(context_, domain)) \ + __VA_ARGS__, errsave_finish(context_, __FILE__, __LINE__, __func__); \ + } while(0) + +#define errsave(context, ...) \ + errsave_domain(context, TEXTDOMAIN, __VA_ARGS__) + +/* + * "ereturn(context, dummy_value, ...);" is exactly the same as + * "errsave(context, ...); return dummy_value;". This saves a bit + * of typing in the common case where a function has no cleanup + * actions to take after reporting a soft error. "dummy_value" + * can be empty if the function returns void. + */ +#define ereturn_domain(context, dummy_value, domain, ...) \ + do { \ + errsave_domain(context, domain, __VA_ARGS__); \ + return dummy_value; \ + } while(0) + +#define ereturn(context, dummy_value, ...) \ + ereturn_domain(context, dummy_value, TEXTDOMAIN, __VA_ARGS__) + +extern bool errsave_start(struct Node *context, const char *domain); +extern void errsave_finish(struct Node *context, + const char *filename, int lineno, + const char *funcname); + + +/* 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. + * + * Each of these macros accepts an optional argument which can be specified + * to apply a suffix to the variables declared within the macros. This suffix + * can be used to avoid the compiler emitting warnings about shadowed + * variables when compiling with -Wshadow in situations where nested PG_TRY() + * statements are required. The optional suffix may contain any character + * that's allowed in a variable name. The suffix, if specified, must be the + * same within each component macro of the given PG_TRY() statement. + *---------- + */ +#define PG_TRY(...) \ + do { \ + sigjmp_buf *_save_exception_stack##__VA_ARGS__ = PG_exception_stack; \ + ErrorContextCallback *_save_context_stack##__VA_ARGS__ = error_context_stack; \ + sigjmp_buf _local_sigjmp_buf##__VA_ARGS__; \ + bool _do_rethrow##__VA_ARGS__ = false; \ + if (sigsetjmp(_local_sigjmp_buf##__VA_ARGS__, 0) == 0) \ + { \ + PG_exception_stack = &_local_sigjmp_buf##__VA_ARGS__ + +#define PG_CATCH(...) \ + } \ + else \ + { \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__ + +#define PG_FINALLY(...) \ + } \ + else \ + _do_rethrow##__VA_ARGS__ = true; \ + { \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__ + +#define PG_END_TRY(...) \ + } \ + if (_do_rethrow##__VA_ARGS__) \ + PG_RE_THROW(); \ + PG_exception_stack = _save_exception_stack##__VA_ARGS__; \ + error_context_stack = _save_context_stack##__VA_ARGS__; \ + } 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 log_status_format(StringInfo buf, const char *format, + ErrorData *edata); +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); + +/* + * 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..d340026 --- /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-2023, 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..a77bb7e --- /dev/null +++ b/src/include/utils/expandeddatum.h @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 + +#include "varatt.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.) + */ + +static inline Datum +EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr) +{ + return PointerGetDatum(eohptr->eoh_rw_ptr); +} + +static inline Datum +EOHPGetRODatum(const struct ExpandedObjectHeader *eohptr) +{ + return 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..7e7c114 --- /dev/null +++ b/src/include/utils/expandedrecord.h @@ -0,0 +1,241 @@ +/*------------------------------------------------------------------------- + * + * expandedrecord.h + * Declarations for composite expanded objects. + * + * Portions Copyright (c) 1996-2023, 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 functions and macros for expanded record objects */ +static inline Datum +ExpandedRecordGetDatum(const ExpandedRecordHeader *erh) +{ + return EOHPGetRWDatum(&erh->hdr); +} + +static inline Datum +ExpandedRecordGetRODatum(const ExpandedRecordHeader *erh) +{ + return EOHPGetRODatum(&erh->hdr); +} + +#define PG_GETARG_EXPANDED_RECORD(n) DatumGetExpandedRecord(PG_GETARG_DATUM(n)) +#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..7529899 --- /dev/null +++ b/src/include/utils/float.h @@ -0,0 +1,357 @@ +/*------------------------------------------------------------------------- + * + * float.h + * Definitions for the built-in floating-point types + * + * Portions Copyright (c) 1996-2023, 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> + +/* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */ +#ifndef M_PI +#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, + struct Node *escontext); +extern float4 float4in_internal(char *num, char **endptr_p, + const char *type_name, const char *orig_string, + struct Node *escontext); +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..838ffe3 --- /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-2023, 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..0cad3a2 --- /dev/null +++ b/src/include/utils/formatting.h @@ -0,0 +1,33 @@ +/* ----------------------------------------------------------------------- + * formatting.h + * + * src/include/utils/formatting.h + * + * + * Portions Copyright (c) 1999-2023, 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, + struct Node *escontext); + +#endif diff --git a/src/include/utils/freepage.h b/src/include/utils/freepage.h new file mode 100644 index 0000000..8d1ebb4 --- /dev/null +++ b/src/include/utils/freepage.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + * + * freepage.h + * Management of page-organized free memory. + * + * Portions Copyright (c) 1996-2023, 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..d176f58 --- /dev/null +++ b/src/include/utils/geo_decls.h @@ -0,0 +1,285 @@ +/*------------------------------------------------------------------------- + * + * geo_decls.h - Declarations for various 2D constructs. + * + * + * Portions Copyright (c) 1996-2023, 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 functions + * + * Path and Polygon are toastable varlena types, the others are just + * fixed-size pass-by-reference types. + */ + +static inline Point * +DatumGetPointP(Datum X) +{ + return (Point *) DatumGetPointer(X); +} +static inline Datum +PointPGetDatum(const Point *X) +{ + return PointerGetDatum(X); +} +#define PG_GETARG_POINT_P(n) DatumGetPointP(PG_GETARG_DATUM(n)) +#define PG_RETURN_POINT_P(x) return PointPGetDatum(x) + +static inline LSEG * +DatumGetLsegP(Datum X) +{ + return (LSEG *) DatumGetPointer(X); +} +static inline Datum +LsegPGetDatum(const LSEG *X) +{ + return PointerGetDatum(X); +} +#define PG_GETARG_LSEG_P(n) DatumGetLsegP(PG_GETARG_DATUM(n)) +#define PG_RETURN_LSEG_P(x) return LsegPGetDatum(x) + +static inline PATH * +DatumGetPathP(Datum X) +{ + return (PATH *) PG_DETOAST_DATUM(X); +} +static inline PATH * +DatumGetPathPCopy(Datum X) +{ + return (PATH *) PG_DETOAST_DATUM_COPY(X); +} +static inline Datum +PathPGetDatum(const PATH *X) +{ + return 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) + +static inline LINE * +DatumGetLineP(Datum X) +{ + return (LINE *) DatumGetPointer(X); +} +static inline Datum +LinePGetDatum(const LINE *X) +{ + return PointerGetDatum(X); +} +#define PG_GETARG_LINE_P(n) DatumGetLineP(PG_GETARG_DATUM(n)) +#define PG_RETURN_LINE_P(x) return LinePGetDatum(x) + +static inline BOX * +DatumGetBoxP(Datum X) +{ + return (BOX *) DatumGetPointer(X); +} +static inline Datum +BoxPGetDatum(const BOX *X) +{ + return PointerGetDatum(X); +} +#define PG_GETARG_BOX_P(n) DatumGetBoxP(PG_GETARG_DATUM(n)) +#define PG_RETURN_BOX_P(x) return BoxPGetDatum(x) + +static inline POLYGON * +DatumGetPolygonP(Datum X) +{ + return (POLYGON *) PG_DETOAST_DATUM(X); +} +static inline POLYGON * +DatumGetPolygonPCopy(Datum X) +{ + return (POLYGON *) PG_DETOAST_DATUM_COPY(X); +} +static inline Datum +PolygonPGetDatum(const POLYGON *X) +{ + return 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) + +static inline CIRCLE * +DatumGetCircleP(Datum X) +{ + return (CIRCLE *) DatumGetPointer(X); +} +static inline Datum +CirclePGetDatum(const CIRCLE *X) +{ + return 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..d5253c7 --- /dev/null +++ b/src/include/utils/guc.h @@ -0,0 +1,442 @@ +/*-------------------------------------------------------------------- + * guc.h + * + * External declarations pertaining to Grand Unified Configuration. + * + * Copyright (c) 2000-2023, 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. Note that these don't appear + * on disk, so we can reassign their values freely. + */ +#define GUC_LIST_INPUT 0x000001 /* input can be list format */ +#define GUC_LIST_QUOTE 0x000002 /* double-quote list elements */ +#define GUC_NO_SHOW_ALL 0x000004 /* exclude from SHOW ALL */ +#define GUC_NO_RESET 0x000008 /* disallow RESET and SAVE */ +#define GUC_NO_RESET_ALL 0x000010 /* exclude from RESET ALL */ +#define GUC_EXPLAIN 0x000020 /* include in EXPLAIN */ +#define GUC_REPORT 0x000040 /* auto-report changes to client */ +#define GUC_NOT_IN_SAMPLE 0x000080 /* not in postgresql.conf.sample */ +#define GUC_DISALLOW_IN_FILE 0x000100 /* can't set in postgresql.conf */ +#define GUC_CUSTOM_PLACEHOLDER 0x000200 /* placeholder for custom variable */ +#define GUC_SUPERUSER_ONLY 0x000400 /* show only to superusers */ +#define GUC_IS_NAME 0x000800 /* limit string to NAMEDATALEN-1 */ +#define GUC_NOT_WHILE_SEC_REST 0x001000 /* can't set if security restricted */ +#define GUC_DISALLOW_IN_AUTO_FILE \ + 0x002000 /* can't set in PG_AUTOCONF_FILENAME */ +#define GUC_RUNTIME_COMPUTED 0x004000 /* delay processing in 'postgres -C' */ + +#define GUC_UNIT_KB 0x01000000 /* value is in kilobytes */ +#define GUC_UNIT_BLOCKS 0x02000000 /* value is in blocks */ +#define GUC_UNIT_XBLOCKS 0x03000000 /* value is in xlog blocks */ +#define GUC_UNIT_MB 0x04000000 /* value is in megabytes */ +#define GUC_UNIT_BYTE 0x05000000 /* value is in bytes */ +#define GUC_UNIT_MEMORY 0x0F000000 /* mask for size-related units */ + +#define GUC_UNIT_MS 0x10000000 /* value is in milliseconds */ +#define GUC_UNIT_S 0x20000000 /* value is in seconds */ +#define GUC_UNIT_MIN 0x30000000 /* value is in minutes */ +#define GUC_UNIT_TIME 0x70000000 /* mask for time-related units */ + +#define GUC_UNIT (GUC_UNIT_MEMORY | GUC_UNIT_TIME) + + +/* GUC vars that are actually defined in guc_tables.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 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) pg_attribute_nonnull(1, 4); + +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) pg_attribute_nonnull(1, 4); + +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) pg_attribute_nonnull(1, 4); + +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) pg_attribute_nonnull(1, 4); + +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) pg_attribute_nonnull(1, 4); + +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 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 const char *get_config_unit_name(int flags); +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 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); + +extern void *guc_malloc(int elevel, size_t size); +extern pg_nodiscard void *guc_realloc(int elevel, void *old, size_t size); +extern char *guc_strdup(int elevel, const char *src); +extern void guc_free(void *ptr); + +#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); + +/* Functions exported by guc_funcs.c */ +extern void ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel); +extern char *ExtractSetVariableArgs(VariableSetStmt *stmt); +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); + +/* 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 + +#endif /* GUC_H */ diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h new file mode 100644 index 0000000..952293a --- /dev/null +++ b/src/include/utils/guc_hooks.h @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------------- + * + * guc_hooks.h + * Declarations of per-variable callback functions used by GUC. + * + * These functions are scattered throughout the system, but we + * declare them all here to avoid having to propagate guc.h into + * a lot of unrelated header files. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * src/include/utils/guc_hooks.h + * + *------------------------------------------------------------------------- + */ +#ifndef GUC_HOOKS_H +#define GUC_HOOKS_H 1 + +#include "utils/guc.h" + +/* + * See guc.h for the typedefs that these hook functions should match + * (GucBoolCheckHook and so on). + * + * Please keep the declarations in order by GUC variable name. + */ + +extern bool check_application_name(char **newval, void **extra, + GucSource source); +extern void assign_application_name(const char *newval, void *extra); +extern const char *show_archive_command(void); +extern bool check_autovacuum_max_workers(int *newval, void **extra, + GucSource source); +extern bool check_autovacuum_work_mem(int *newval, void **extra, + GucSource source); +extern bool check_vacuum_buffer_usage_limit(int *newval, void **extra, + GucSource source); +extern bool check_backtrace_functions(char **newval, void **extra, + GucSource source); +extern void assign_backtrace_functions(const char *newval, void *extra); +extern bool check_bonjour(bool *newval, void **extra, GucSource source); +extern bool check_canonical_path(char **newval, void **extra, GucSource source); +extern void assign_checkpoint_completion_target(double newval, void *extra); +extern bool check_client_connection_check_interval(int *newval, void **extra, + GucSource source); +extern bool check_client_encoding(char **newval, void **extra, GucSource source); +extern void assign_client_encoding(const char *newval, void *extra); +extern bool check_cluster_name(char **newval, void **extra, GucSource source); +extern const char *show_data_directory_mode(void); +extern bool check_datestyle(char **newval, void **extra, GucSource source); +extern void assign_datestyle(const char *newval, void *extra); +extern bool check_debug_io_direct(char **newval, void **extra, GucSource source); +extern void assign_debug_io_direct(const char *newval, void *extra); +extern bool check_default_table_access_method(char **newval, void **extra, + GucSource source); +extern bool check_default_tablespace(char **newval, void **extra, + GucSource source); +extern bool check_default_text_search_config(char **newval, void **extra, GucSource source); +extern void assign_default_text_search_config(const char *newval, void *extra); +extern bool check_default_with_oids(bool *newval, void **extra, + GucSource source); +extern bool check_effective_io_concurrency(int *newval, void **extra, + GucSource source); +extern bool check_huge_page_size(int *newval, void **extra, GucSource source); +extern const char *show_in_hot_standby(void); +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_log_destination(char **newval, void **extra, + GucSource source); +extern void assign_log_destination(const char *newval, void *extra); +extern const char *show_log_file_mode(void); +extern bool check_log_stats(bool *newval, void **extra, GucSource source); +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_maintenance_io_concurrency(int *newval, void **extra, + GucSource source); +extern void assign_maintenance_io_concurrency(int newval, void *extra); +extern bool check_max_connections(int *newval, void **extra, GucSource source); +extern bool check_max_wal_senders(int *newval, void **extra, GucSource source); +extern void assign_max_wal_size(int newval, void *extra); +extern bool check_max_worker_processes(int *newval, void **extra, + GucSource source); +extern bool check_max_stack_depth(int *newval, void **extra, GucSource source); +extern void assign_max_stack_depth(int newval, void *extra); +extern bool check_primary_slot_name(char **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_recovery_prefetch(int *new_value, void **extra, + GucSource source); +extern void assign_recovery_prefetch(int new_value, void *extra); +extern bool check_recovery_target(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target(const char *newval, void *extra); +extern bool check_recovery_target_lsn(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target_lsn(const char *newval, void *extra); +extern bool check_recovery_target_name(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target_name(const char *newval, void *extra); +extern bool check_recovery_target_time(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target_time(const char *newval, void *extra); +extern bool check_recovery_target_timeline(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target_timeline(const char *newval, void *extra); +extern bool check_recovery_target_xid(char **newval, void **extra, + GucSource source); +extern void assign_recovery_target_xid(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); +extern bool check_search_path(char **newval, void **extra, GucSource source); +extern void assign_search_path(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 void assign_session_replication_role(int newval, void *extra); +extern void assign_stats_fetch_consistency(int newval, void *extra); +extern bool check_ssl(bool *newval, void **extra, GucSource source); +extern bool check_stage_log_stats(bool *newval, void **extra, GucSource source); +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); +extern void assign_syslog_facility(int newval, void *extra); +extern void assign_syslog_ident(const char *newval, void *extra); +extern void assign_tcp_keepalives_count(int newval, void *extra); +extern const char *show_tcp_keepalives_count(void); +extern void assign_tcp_keepalives_idle(int newval, void *extra); +extern const char *show_tcp_keepalives_idle(void); +extern void assign_tcp_keepalives_interval(int newval, void *extra); +extern const char *show_tcp_keepalives_interval(void); +extern void assign_tcp_user_timeout(int newval, void *extra); +extern const char *show_tcp_user_timeout(void); +extern bool check_temp_buffers(int *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); +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_timezone_abbreviations(char **newval, void **extra, + GucSource source); +extern void assign_timezone_abbreviations(const char *newval, void *extra); +extern bool check_transaction_deferrable(bool *newval, void **extra, GucSource source); +extern bool check_transaction_isolation(int *newval, void **extra, GucSource source); +extern bool check_transaction_read_only(bool *newval, void **extra, GucSource source); +extern const char *show_unix_socket_permissions(void); +extern bool check_wal_buffers(int *newval, void **extra, GucSource source); +extern bool check_wal_consistency_checking(char **newval, void **extra, + GucSource source); +extern void assign_wal_consistency_checking(const char *newval, void *extra); +extern void assign_xlog_sync_method(int new_sync_method, void *extra); + +#endif /* GUC_HOOKS_H */ diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h new file mode 100644 index 0000000..ab880ca --- /dev/null +++ b/src/include/utils/guc_tables.h @@ -0,0 +1,322 @@ +/*------------------------------------------------------------------------- + * + * guc_tables.h + * Declarations of tables used by GUC. + * + * See src/backend/utils/misc/README for design notes. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * src/include/utils/guc_tables.h + * + *------------------------------------------------------------------------- + */ +#ifndef GUC_TABLES_H +#define GUC_TABLES_H 1 + +#include "lib/ilist.h" +#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_TCP, + 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). + * + * Variables that are currently of active interest for maintenance + * operations are linked into various lists using the xxx_link fields. + * The link fields are unused/garbage in variables not currently having + * the specified properties. + * + * 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 */ + dlist_node nondef_link; /* list link for variables that have source + * different from PGC_S_DEFAULT */ + slist_node stack_link; /* list link for variables that have non-NULL + * stack */ + slist_node report_link; /* list link for variables that have the + * GUC_NEEDS_REPORT bit set in status */ + 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[]; + +/* data arrays defining all the built-in GUC variables */ +extern PGDLLIMPORT struct config_bool ConfigureNamesBool[]; +extern PGDLLIMPORT struct config_int ConfigureNamesInt[]; +extern PGDLLIMPORT struct config_real ConfigureNamesReal[]; +extern PGDLLIMPORT struct config_string ConfigureNamesString[]; +extern PGDLLIMPORT struct config_enum ConfigureNamesEnum[]; + +/* lookup GUC variables, returning config_generic pointers */ +extern struct config_generic *find_option(const char *name, + bool create_placeholders, + bool skip_errors, + int elevel); +extern struct config_generic **get_explain_guc_options(int *num); + +/* get string value of variable */ +extern char *ShowGUCOption(struct config_generic *record, bool use_units); + +/* get whether or not the GUC variable is visible to current user */ +extern bool ConfigOptionIsVisible(struct config_generic *conf); + +/* get the current set of variables */ +extern struct config_generic **get_guc_variables(int *num_vars); + +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 char *config_enum_get_options(struct config_enum *record, + const char *prefix, + const char *suffix, + const char *separator); + +#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..e9bc417 --- /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-2023, 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..bc3d5ef --- /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-2023, 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..f081a1a --- /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-2023, 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..96d9f6a --- /dev/null +++ b/src/include/utils/inet.h @@ -0,0 +1,184 @@ +/*------------------------------------------------------------------------- + * + * inet.h + * Declarations for operations on INET datatypes. + * + * + * Portions Copyright (c) 1996-2023, 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 did not have the appropriate address family (like + * inet6 addresses when AF_INET6 wasn't present) but didn'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 + */ +static inline inet * +DatumGetInetPP(Datum X) +{ + return (inet *) PG_DETOAST_DATUM_PACKED(X); +} + +static inline Datum +InetPGetDatum(const inet *X) +{ + return PointerGetDatum(X); +} + +#define PG_GETARG_INET_PP(n) DatumGetInetPP(PG_GETARG_DATUM(n)) +#define PG_RETURN_INET_P(x) return InetPGetDatum(x) + +/* obsolescent variants */ +static inline inet * +DatumGetInetP(Datum X) +{ + return (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 */ +static inline macaddr * +DatumGetMacaddrP(Datum X) +{ + return (macaddr *) DatumGetPointer(X); +} + +static inline Datum +MacaddrPGetDatum(const macaddr *X) +{ + return 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 */ +static inline macaddr8 * +DatumGetMacaddr8P(Datum X) +{ + return (macaddr8 *) DatumGetPointer(X); +} + +static inline Datum +Macaddr8PGetDatum(const macaddr8 *X) +{ + return 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..14b4eac --- /dev/null +++ b/src/include/utils/inval.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- + * + * inval.h + * POSTGRES cache invalidation dispatcher definitions. + * + * + * Portions Copyright (c) 1996-2023, 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/relfilelocator.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(RelFileLocatorBackend rlocator); + +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..35a9a55 --- /dev/null +++ b/src/include/utils/json.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * json.h + * Declarations for JSON data type support. + * + * Portions Copyright (c) 1996-2023, 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); +extern bool to_json_is_immutable(Oid typoid); +extern Datum json_build_object_worker(int nargs, Datum *args, bool *nulls, + Oid *types, bool absent_on_null, + bool unique_keys); +extern Datum json_build_array_worker(int nargs, Datum *args, bool *nulls, + Oid *types, bool absent_on_null); +extern bool json_validate(text *json, bool check_unique_keys, bool throw_error); + +#endif /* JSON_H */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h new file mode 100644 index 0000000..649a164 --- /dev/null +++ b/src/include/utils/jsonb.h @@ -0,0 +1,439 @@ +/*------------------------------------------------------------------------- + * + * jsonb.h + * Declarations for jsonb data type support. + * + * Copyright (c) 1996-2023, 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 */ + +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; + bool unique_keys; /* Check object key uniqueness */ + bool skip_nulls; /* Skip null object fields */ +} 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; + + +/* Convenience macros */ +static inline Jsonb * +DatumGetJsonbP(Datum d) +{ + return (Jsonb *) PG_DETOAST_DATUM(d); +} + +static inline Jsonb * +DatumGetJsonbPCopy(Datum d) +{ + return (Jsonb *) PG_DETOAST_DATUM_COPY(d); +} + +static inline Datum +JsonbPGetDatum(const Jsonb *p) +{ + return 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) + +/* 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 *container, + uint32 flags, + JsonbValue *key); +extern JsonbValue *getKeyJsonValueFromContainer(JsonbContainer *container, + const char *keyVal, int keyLen, + JsonbValue *res); +extern JsonbValue *getIthJsonbValueFromContainer(JsonbContainer *container, + 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 *val); + +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); +extern bool to_jsonb_is_immutable(Oid typoid); +extern Datum jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, + Oid *types, bool absent_on_null, + bool unique_keys); +extern Datum jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, + Oid *types, bool absent_on_null); + +#endif /* __JSONB_H__ */ diff --git a/src/include/utils/jsonfuncs.h b/src/include/utils/jsonfuncs.h new file mode 100644 index 0000000..a85203d --- /dev/null +++ b/src/include/utils/jsonfuncs.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------- + * + * jsonfuncs.h + * Functions to process JSON data types. + * + * Portions Copyright (c) 1996-2023, 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 errsave(escontext) on failure */ +extern bool pg_parse_json_or_errsave(JsonLexContext *lex, JsonSemAction *sem, + struct Node *escontext); + +#define pg_parse_json_or_ereport(lex, sem) \ + (void) pg_parse_json_or_errsave(lex, sem, NULL) + +/* save an error during json lexing or parsing */ +extern void json_errsave_error(JsonParseErrorType error, JsonLexContext *lex, + struct Node *escontext); + +/* get first JSON token */ +extern JsonTokenType json_get_first_token(text *json, bool throw_error); + +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..f0181e0 --- /dev/null +++ b/src/include/utils/jsonpath.h @@ -0,0 +1,264 @@ +/*------------------------------------------------------------------------- + * + * jsonpath.h + * Definitions for jsonpath datatype + * + * Copyright (c) 2019-2023, 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)) + +static inline JsonPath * +DatumGetJsonPathP(Datum d) +{ + return (JsonPath *) PG_DETOAST_DATUM(d); +} + +static inline JsonPath * +DatumGetJsonPathPCopy(Datum d) +{ + return (JsonPath *) 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, + struct Node *escontext); + +extern bool jspConvertRegexFlags(uint32 xflags, int *result, + struct Node *escontext); + + +#endif diff --git a/src/include/utils/logtape.h b/src/include/utils/logtape.h new file mode 100644 index 0000000..5420a24 --- /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-2023, 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, const 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..4f5418b --- /dev/null +++ b/src/include/utils/lsyscache.h @@ -0,0 +1,212 @@ +/*------------------------------------------------------------------------- + * + * lsyscache.h + * Convenience routines for common queries in the system catalog cache. + * + * Portions Copyright (c) 1996-2023, 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); +extern Oid get_publication_oid(const char *pubname, bool missing_ok); +extern char *get_publication_name(Oid pubid, bool missing_ok); +extern Oid get_subscription_oid(const char *subname, bool missing_ok); +extern char *get_subscription_name(Oid subid, bool missing_ok); + +#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..804ed1f --- /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-2023, 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..21640d6 --- /dev/null +++ b/src/include/utils/memutils.h @@ -0,0 +1,185 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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) + +/* Must be less than SIZE_MAX */ +#define MaxAllocHugeSize (SIZE_MAX / 2) + +#define InvalidAllocSize SIZE_MAX + +#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 MemoryContext GetMemoryChunkContext(void *pointer); +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 + +/* Handy macro for copying and assigning context ID ... but note double eval */ +#define MemoryContextCopyAndSetIdentifier(cxt, id) \ + MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id)) + +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/memutils_internal.h b/src/include/utils/memutils_internal.h new file mode 100644 index 0000000..2d107bb --- /dev/null +++ b/src/include/utils/memutils_internal.h @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------- + * + * memutils_internal.h + * This file contains declarations for memory allocation utility + * functions for internal use. + * + * + * Portions Copyright (c) 2022-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/memutils_internal.h + * + *------------------------------------------------------------------------- + */ + +#ifndef MEMUTILS_INTERNAL_H +#define MEMUTILS_INTERNAL_H + +#include "utils/memutils.h" + +/* These functions implement the MemoryContext API for AllocSet context. */ +extern void *AllocSetAlloc(MemoryContext context, Size size); +extern void AllocSetFree(void *pointer); +extern void *AllocSetRealloc(void *pointer, Size size); +extern void AllocSetReset(MemoryContext context); +extern void AllocSetDelete(MemoryContext context); +extern MemoryContext AllocSetGetChunkContext(void *pointer); +extern Size AllocSetGetChunkSpace(void *pointer); +extern bool AllocSetIsEmpty(MemoryContext context); +extern void AllocSetStats(MemoryContext context, + MemoryStatsPrintFunc printfunc, void *passthru, + MemoryContextCounters *totals, + bool print_to_stderr); +#ifdef MEMORY_CONTEXT_CHECKING +extern void AllocSetCheck(MemoryContext context); +#endif + +/* These functions implement the MemoryContext API for Generation context. */ +extern void *GenerationAlloc(MemoryContext context, Size size); +extern void GenerationFree(void *pointer); +extern void *GenerationRealloc(void *pointer, Size size); +extern void GenerationReset(MemoryContext context); +extern void GenerationDelete(MemoryContext context); +extern MemoryContext GenerationGetChunkContext(void *pointer); +extern Size GenerationGetChunkSpace(void *pointer); +extern bool GenerationIsEmpty(MemoryContext context); +extern void GenerationStats(MemoryContext context, + MemoryStatsPrintFunc printfunc, void *passthru, + MemoryContextCounters *totals, + bool print_to_stderr); +#ifdef MEMORY_CONTEXT_CHECKING +extern void GenerationCheck(MemoryContext context); +#endif + + +/* These functions implement the MemoryContext API for Slab context. */ +extern void *SlabAlloc(MemoryContext context, Size size); +extern void SlabFree(void *pointer); +extern void *SlabRealloc(void *pointer, Size size); +extern void SlabReset(MemoryContext context); +extern void SlabDelete(MemoryContext context); +extern MemoryContext SlabGetChunkContext(void *pointer); +extern Size SlabGetChunkSpace(void *pointer); +extern bool SlabIsEmpty(MemoryContext context); +extern void SlabStats(MemoryContext context, + MemoryStatsPrintFunc printfunc, void *passthru, + MemoryContextCounters *totals, + bool print_to_stderr); +#ifdef MEMORY_CONTEXT_CHECKING +extern void SlabCheck(MemoryContext context); +#endif + +/* + * These functions support the implementation of palloc_aligned() and are not + * part of a fully-fledged MemoryContext type. + */ +extern void AlignedAllocFree(void *pointer); +extern void *AlignedAllocRealloc(void *pointer, Size size); +extern MemoryContext AlignedAllocGetChunkContext(void *pointer); +extern Size AlignedAllocGetChunkSpace(void *pointer); + +/* + * How many extra bytes do we need to request in order to ensure that we can + * align a pointer to 'alignto'. Since palloc'd pointers are already aligned + * to MAXIMUM_ALIGNOF we can subtract that amount. We also need to make sure + * there is enough space for the redirection MemoryChunk. + */ +#define PallocAlignedExtraBytes(alignto) \ + ((alignto) + (sizeof(MemoryChunk) - MAXIMUM_ALIGNOF)) + +/* + * MemoryContextMethodID + * A unique identifier for each MemoryContext implementation which + * indicates the index into the mcxt_methods[] array. See mcxt.c. + * + * For robust error detection, ensure that MemoryContextMethodID has a value + * for each possible bit-pattern of MEMORY_CONTEXT_METHODID_MASK, and make + * dummy entries for unused IDs in the mcxt_methods[] array. We also try + * to avoid using bit-patterns as valid IDs if they are likely to occur in + * garbage data, or if they could falsely match on chunks that are really from + * malloc not palloc. (We can't tell that for most malloc implementations, + * but it happens that glibc stores flag bits in the same place where we put + * the MemoryContextMethodID, so the possible values are predictable for it.) + */ +typedef enum MemoryContextMethodID +{ + MCTX_UNUSED1_ID, /* 000 occurs in never-used memory */ + MCTX_UNUSED2_ID, /* glibc malloc'd chunks usually match 001 */ + MCTX_UNUSED3_ID, /* glibc malloc'd chunks > 128kB match 010 */ + MCTX_ASET_ID, + MCTX_GENERATION_ID, + MCTX_SLAB_ID, + MCTX_ALIGNED_REDIRECT_ID, + MCTX_UNUSED4_ID /* 111 occurs in wipe_mem'd memory */ +} MemoryContextMethodID; + +/* + * The number of bits that 8-byte memory chunk headers can use to encode the + * MemoryContextMethodID. + */ +#define MEMORY_CONTEXT_METHODID_BITS 3 +#define MEMORY_CONTEXT_METHODID_MASK \ + ((((uint64) 1) << MEMORY_CONTEXT_METHODID_BITS) - 1) + +/* + * 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, + MemoryContextMethodID method_id, + MemoryContext parent, + const char *name); + +#endif /* MEMUTILS_INTERNAL_H */ diff --git a/src/include/utils/memutils_memorychunk.h b/src/include/utils/memutils_memorychunk.h new file mode 100644 index 0000000..ffa9113 --- /dev/null +++ b/src/include/utils/memutils_memorychunk.h @@ -0,0 +1,237 @@ +/*------------------------------------------------------------------------- + * + * memutils_memorychunk.h + * Here we define a struct named MemoryChunk which implementations of + * MemoryContexts may use as a header for chunks of memory they allocate. + * + * MemoryChunk provides a lightweight header that a MemoryContext can use to + * store a reference back to the block which the given chunk is allocated on + * and also an additional 30-bits to store another value such as the size of + * the allocated chunk. + * + * Although MemoryChunks are used by each of our MemoryContexts, future + * implementations may choose to implement their own method for storing chunk + * headers. The only requirement is that the header ends with an 8-byte value + * which the least significant 3-bits of are set to the MemoryContextMethodID + * of the given context. + * + * By default, a MemoryChunk is 8 bytes in size, however, when + * MEMORY_CONTEXT_CHECKING is defined the header becomes 16 bytes in size due + * to the additional requested_size field. The MemoryContext may use this + * field for whatever they wish, but it is intended to be used for additional + * checks which are only done in MEMORY_CONTEXT_CHECKING builds. + * + * The MemoryChunk contains a uint64 field named 'hdrmask'. This field is + * used to encode 4 separate pieces of information. Starting with the least + * significant bits of 'hdrmask', the bit space is reserved as follows: + * + * 1. 3-bits to indicate the MemoryContextMethodID as defined by + * MEMORY_CONTEXT_METHODID_MASK + * 2. 1-bit to denote an "external" chunk (see below) + * 3. 30-bits reserved for the MemoryContext to use for anything it + * requires. Most MemoryContext likely want to store the size of the + * chunk here. + * 4. 30-bits for the number of bytes that must be subtracted from the chunk + * to obtain the address of the block that the chunk is stored on. + * + * In some cases, for example when memory allocations become large, it's + * possible fields 3 and 4 above are not large enough to store the values + * required for the chunk. In this case, the MemoryContext can choose to mark + * the chunk as "external" by calling the MemoryChunkSetHdrMaskExternal() + * function. When this is done, fields 3 and 4 are unavailable for use by the + * MemoryContext and it's up to the MemoryContext itself to devise its own + * method for getting the reference to the block. + * + * Interface: + * + * MemoryChunkSetHdrMask: + * Used to set up a non-external MemoryChunk. + * + * MemoryChunkSetHdrMaskExternal: + * Used to set up an externally managed MemoryChunk. + * + * MemoryChunkIsExternal: + * Determine if the given MemoryChunk is externally managed, i.e. + * MemoryChunkSetHdrMaskExternal() was called on the chunk. + * + * MemoryChunkGetValue: + * For non-external chunks, return the stored 30-bit value as it was set + * in the call to MemoryChunkSetHdrMask(). + * + * MemoryChunkGetBlock: + * For non-external chunks, return a pointer to the block as it was set + * in the call to MemoryChunkSetHdrMask(). + * + * Also exports: + * MEMORYCHUNK_MAX_VALUE + * MEMORYCHUNK_MAX_BLOCKOFFSET + * PointerGetMemoryChunk + * MemoryChunkGetPointer + * + * Portions Copyright (c) 2022-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/memutils_memorychunk.h + * + *------------------------------------------------------------------------- + */ + +#ifndef MEMUTILS_MEMORYCHUNK_H +#define MEMUTILS_MEMORYCHUNK_H + +#include "utils/memutils_internal.h" + + /* + * The maximum allowed value that MemoryContexts can store in the value + * field. Must be 1 less than a power of 2. + */ +#define MEMORYCHUNK_MAX_VALUE UINT64CONST(0x3FFFFFFF) + +/* + * The maximum distance in bytes that a MemoryChunk can be offset from the + * block that is storing the chunk. Must be 1 less than a power of 2. + */ +#define MEMORYCHUNK_MAX_BLOCKOFFSET UINT64CONST(0x3FFFFFFF) + +/* define the least significant base-0 bit of each portion of the hdrmask */ +#define MEMORYCHUNK_EXTERNAL_BASEBIT MEMORY_CONTEXT_METHODID_BITS +#define MEMORYCHUNK_VALUE_BASEBIT (MEMORYCHUNK_EXTERNAL_BASEBIT + 1) +#define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 30) + +/* + * A magic number for storing in the free bits of an external chunk. This + * must mask out the bits used for storing the MemoryContextMethodID and the + * external bit. + */ +#define MEMORYCHUNK_MAGIC (UINT64CONST(0xB1A8DB858EB6EFBA) >> \ + MEMORYCHUNK_VALUE_BASEBIT << \ + MEMORYCHUNK_VALUE_BASEBIT) + +typedef struct MemoryChunk +{ +#ifdef MEMORY_CONTEXT_CHECKING + Size requested_size; +#endif + + /* bitfield for storing details about the chunk */ + uint64 hdrmask; /* must be last */ +} MemoryChunk; + +/* Get the MemoryChunk from the pointer */ +#define PointerGetMemoryChunk(p) \ + ((MemoryChunk *) ((char *) (p) - sizeof(MemoryChunk))) +/* Get the pointer from the MemoryChunk */ +#define MemoryChunkGetPointer(c) \ + ((void *) ((char *) (c) + sizeof(MemoryChunk))) + +/* private macros for making the inline functions below more simple */ +#define HdrMaskIsExternal(hdrmask) \ + ((hdrmask) & (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT)) +#define HdrMaskGetValue(hdrmask) \ + (((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE) + +/* + * We should have used up all the bits here, so the compiler is likely to + * optimize out the & MEMORYCHUNK_MAX_BLOCKOFFSET. + */ +#define HdrMaskBlockOffset(hdrmask) \ + (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_MAX_BLOCKOFFSET) + +/* For external chunks only, check the magic number matches */ +#define HdrMaskCheckMagic(hdrmask) \ + (MEMORYCHUNK_MAGIC == \ + ((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT << MEMORYCHUNK_VALUE_BASEBIT)) +/* + * MemoryChunkSetHdrMask + * Store the given 'block', 'chunk_size' and 'methodid' in the given + * MemoryChunk. + * + * The number of bytes between 'block' and 'chunk' must be <= + * MEMORYCHUNK_MAX_BLOCKOFFSET. + * 'value' must be <= MEMORYCHUNK_MAX_VALUE. + */ +static inline void +MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, + Size value, MemoryContextMethodID methodid) +{ + Size blockoffset = (char *) chunk - (char *) block; + + Assert((char *) chunk >= (char *) block); + Assert(blockoffset <= MEMORYCHUNK_MAX_BLOCKOFFSET); + Assert(value <= MEMORYCHUNK_MAX_VALUE); + Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK); + + chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) | + (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) | + methodid; +} + +/* + * MemoryChunkSetHdrMaskExternal + * Set 'chunk' as an externally managed chunk. Here we only record the + * MemoryContextMethodID and set the external chunk bit. + */ +static inline void +MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, + MemoryContextMethodID methodid) +{ + Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK); + + chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) | + methodid; +} + +/* + * MemoryChunkIsExternal + * Return true if 'chunk' is marked as external. + */ +static inline bool +MemoryChunkIsExternal(MemoryChunk *chunk) +{ + /* + * External chunks should always store MEMORYCHUNK_MAGIC in the upper + * portion of the hdrmask, check that nothing has stomped on that. + */ + Assert(!HdrMaskIsExternal(chunk->hdrmask) || + HdrMaskCheckMagic(chunk->hdrmask)); + + return HdrMaskIsExternal(chunk->hdrmask); +} + +/* + * MemoryChunkGetValue + * For non-external chunks, returns the value field as it was set in + * MemoryChunkSetHdrMask. + */ +static inline Size +MemoryChunkGetValue(MemoryChunk *chunk) +{ + Assert(!HdrMaskIsExternal(chunk->hdrmask)); + + return HdrMaskGetValue(chunk->hdrmask); +} + +/* + * MemoryChunkGetBlock + * For non-external chunks, returns the pointer to the block as was set + * in MemoryChunkSetHdrMask. + */ +static inline void * +MemoryChunkGetBlock(MemoryChunk *chunk) +{ + Assert(!HdrMaskIsExternal(chunk->hdrmask)); + + return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask)); +} + +/* cleanup all internal definitions */ +#undef MEMORYCHUNK_EXTERNAL_BASEBIT +#undef MEMORYCHUNK_VALUE_BASEBIT +#undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT +#undef MEMORYCHUNK_MAGIC +#undef HdrMaskIsExternal +#undef HdrMaskGetValue +#undef HdrMaskBlockOffset +#undef HdrMaskCheckMagic + +#endif /* MEMUTILS_MEMORYCHUNK_H */ diff --git a/src/include/utils/meson.build b/src/include/utils/meson.build new file mode 100644 index 0000000..c212c40 --- /dev/null +++ b/src/include/utils/meson.build @@ -0,0 +1,60 @@ +# Copyright (c) 2022-2023, PostgreSQL Global Development Group + +errcodes = custom_target('errcodes', + input: files('../../backend/utils/errcodes.txt'), + output: ['errcodes.h'], + command: [ + perl, files('../../backend/utils/generate-errcodes.pl'), + '--outfile', '@OUTPUT@', + '@INPUT@', + ], + install: true, + install_dir: dir_include_server / 'utils', +) +generated_headers += errcodes + +if dtrace.found() + probes_tmp = custom_target('probes.h.tmp', + input: files('../../backend/utils/probes.d'), + output: 'probes.h.tmp', + command: [dtrace, '-C', '-h', '-s', '@INPUT@', '-o', '@OUTPUT@'], + ) + probes = custom_target('probes.h', + input: probes_tmp, + output: 'probes.h', + capture: true, + command: [sed, '-f', files('../../backend/utils/postprocess_dtrace.sed'), '@INPUT@'], + install: true, + install_dir: dir_include_server / 'utils', + ) +else + probes = custom_target('probes.h', + input: files('../../backend/utils/probes.d'), + output: 'probes.h', + capture: true, + command: [sed, '-f', files('../../backend/utils/Gen_dummy_probes.sed'), '@INPUT@'], + install: true, + install_dir: dir_include_server / 'utils', + ) +endif + +generated_backend_headers += probes + +fmgrtab_output = ['fmgroids.h', 'fmgrprotos.h', 'fmgrtab.c'] +fmgrtab_target = custom_target('fmgrtab', + input: '../catalog/pg_proc.dat', + output : fmgrtab_output, + depend_files: catalog_pm, + command: [perl, '-I', '@SOURCE_ROOT@/src/backend/catalog/', files('../../backend/utils/Gen_fmgrtab.pl'), '--include-path=@SOURCE_ROOT@/src/include', '--output=@OUTDIR@', '@INPUT@'], + install: true, + install_dir: [dir_include_server / 'utils', dir_include_server / 'utils', false], +) + +generated_backend_headers += fmgrtab_target[0] +generated_backend_headers += fmgrtab_target[1] + +# autoconf generates the file there, ensure we get a conflict +generated_sources_ac += { + 'src/backend/utils': fmgrtab_output + ['errcodes.h', 'probes.h', 'fmgr-stamp'], + 'src/include/utils': ['header-stamp'], +} diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h new file mode 100644 index 0000000..7663d35 --- /dev/null +++ b/src/include/utils/multirangetypes.h @@ -0,0 +1,150 @@ +/*------------------------------------------------------------------------- + * + * multirangetypes.h + * Declarations for Postgres multirange types. + * + * + * Portions Copyright (c) 1996-2023, 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 functions for multirange type objects + */ +static inline MultirangeType * +DatumGetMultirangeTypeP(Datum X) +{ + return (MultirangeType *) PG_DETOAST_DATUM(X); +} + +static inline MultirangeType * +DatumGetMultirangeTypePCopy(Datum X) +{ + return (MultirangeType *) PG_DETOAST_DATUM_COPY(X); +} + +static inline Datum +MultirangeTypePGetDatum(const MultirangeType *X) +{ + return 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 val); +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 *multirange, + int32 *range_count, + RangeType ***ranges); +extern MultirangeType *make_multirange(Oid mltrngtypoid, + TypeCacheEntry *rangetyp, + 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..08e4f8c --- /dev/null +++ b/src/include/utils/numeric.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------- + * + * numeric.h + * Definitions for the exact numeric data type of Postgres + * + * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. + * + * Copyright (c) 1998-2023, 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 + */ + +static inline Numeric +DatumGetNumeric(Datum X) +{ + return (Numeric) PG_DETOAST_DATUM(X); +} + +static inline Numeric +DatumGetNumericCopy(Datum X) +{ + return (Numeric) PG_DETOAST_DATUM_COPY(X); +} + +static inline Datum +NumericGetDatum(Numeric X) +{ + return 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 *have_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..f1978a2 --- /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-2023, 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..d1146c1 --- /dev/null +++ b/src/include/utils/palloc.h @@ -0,0 +1,165 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 *MemoryContextAllocAligned(MemoryContext context, + Size size, Size alignto, int flags); + +extern void *palloc(Size size); +extern void *palloc0(Size size); +extern void *palloc_extended(Size size, int flags); +extern void *palloc_aligned(Size size, Size alignto, int flags); +extern pg_nodiscard void *repalloc(void *pointer, Size size); +extern pg_nodiscard void *repalloc_extended(void *pointer, + Size size, int flags); +extern pg_nodiscard void *repalloc0(void *pointer, Size oldsize, 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))) +#define repalloc0_array(pointer, type, oldcount, count) ((type *) repalloc0(pointer, sizeof(type) * (oldcount), 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..eb9bc4b --- /dev/null +++ b/src/include/utils/partcache.h @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------- + * + * partcache.h + * + * Copyright (c) 1996-2023, PostgreSQL Global Development Group + * + * src/include/utils/partcache.h + * + *------------------------------------------------------------------------- + */ +#ifndef PARTCACHE_H +#define PARTCACHE_H + +#include "access/attnum.h" +#include "fmgr.h" +#include "nodes/parsenodes.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 +{ + PartitionStrategy 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..a0369c6 --- /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-2023, 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..e2a7243 --- /dev/null +++ b/src/include/utils/pg_locale.h @@ -0,0 +1,135 @@ +/*----------------------------------------------------------------------- + * + * PostgreSQL locale utilities + * + * src/include/utils/pg_locale.h + * + * Copyright (c) 2002-2023, 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 + +#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; +extern PGDLLIMPORT int icu_validation_level; + +/* 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(int category, const char *locale, char **canonname); +extern char *pg_perm_setlocale(int category, const char *locale); + +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, + const char *icurules, + struct pg_locale_struct *resultp); + +extern bool pg_locale_deterministic(pg_locale_t locale); +extern pg_locale_t pg_newlocale_from_collation(Oid collid); + +extern char *get_collation_actual_version(char collprovider, const char *collcollate); +extern int pg_strcoll(const char *arg1, const char *arg2, pg_locale_t locale); +extern int pg_strncoll(const char *arg1, size_t len1, + const char *arg2, size_t len2, pg_locale_t locale); +extern bool pg_strxfrm_enabled(pg_locale_t locale); +extern size_t pg_strxfrm(char *dest, const char *src, size_t destsize, + pg_locale_t locale); +extern size_t pg_strnxfrm(char *dest, size_t destsize, const char *src, + size_t srclen, pg_locale_t locale); +extern bool pg_strxfrm_prefix_enabled(pg_locale_t locale); +extern size_t pg_strxfrm_prefix(char *dest, const char *src, size_t destsize, + pg_locale_t locale); +extern size_t pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src, + size_t srclen, pg_locale_t locale); + +extern void icu_validate_locale(const char *loc_str); +extern char *icu_language_tag(const char *loc_str, int elevel); + +#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 + +/* 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..7bda26b --- /dev/null +++ b/src/include/utils/pg_lsn.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * + * pg_lsn.h + * Declarations for operations on log sequence numbers (LSNs) of + * PostgreSQL. + * + * + * Portions Copyright (c) 1996-2023, 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" + +static inline XLogRecPtr +DatumGetLSN(Datum X) +{ + return (XLogRecPtr) DatumGetInt64(X); +} + +static inline Datum +LSNGetDatum(XLogRecPtr X) +{ + return 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..219ee67 --- /dev/null +++ b/src/include/utils/pg_rusage.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * pg_rusage.h + * header file for resource usage measurement support routines + * + * + * Portions Copyright (c) 1996-2023, 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/resource.h> +#include <sys/time.h> + + +/* 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..60fbf93 --- /dev/null +++ b/src/include/utils/pgstat_internal.h @@ -0,0 +1,814 @@ +/* ---------- + * 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-2023, 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 PgStatShared_*. + */ +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. + */ + dclist_head pending_drops; + + /* + * 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; + +/* Shared-memory ready PgStat_IO */ +typedef struct PgStatShared_IO +{ + /* + * locks[i] protects stats.stats[i]. locks[0] also protects + * stats.stat_reset_timestamp. + */ + LWLock locks[BACKEND_NUM_TYPES]; + PgStat_IO stats; +} PgStatShared_IO; + +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_IO io; + 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_IO io; + + 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_io.c + */ + +extern bool pgstat_flush_io(bool nowait); +extern void pgstat_io_reset_all_cb(TimestampTz ts); +extern void pgstat_io_snapshot_cb(void); + + +/* + * 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 *created_entry); +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_io.c + */ + +extern PGDLLIMPORT bool have_iostats; + + +/* + * 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) +{ + Assert(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; + + Assert(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..1393a53 --- /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-2023, 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..a443181 --- /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-2023, 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..aa08b1e --- /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-2023, 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..ff5a2b2 --- /dev/null +++ b/src/include/utils/ps_status.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * 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 + +/* disabled on Windows as the performance overhead can be significant */ +#ifdef WIN32 +#define DEFAULT_UPDATE_PROCESS_TITLE false +#else +#define DEFAULT_UPDATE_PROCESS_TITLE true +#endif + +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_suffix(const char *suffix); + +extern void set_ps_display_remove_suffix(void); + +extern void set_ps_display_with_len(const char *activity, size_t len); + +/* + * set_ps_display + * inlined to allow strlen to be evaluated during compilation when + * passing string constants. + */ +static inline void +set_ps_display(const char *activity) +{ + set_ps_display_with_len(activity, strlen(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..532219a --- /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-2023, 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/rangetypes.h b/src/include/utils/rangetypes.h new file mode 100644 index 0000000..6b420a8 --- /dev/null +++ b/src/include/utils/rangetypes.h @@ -0,0 +1,168 @@ +/*------------------------------------------------------------------------- + * + * rangetypes.h + * Declarations for Postgres range types. + * + * + * Portions Copyright (c) 1996-2023, 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 functions for range type objects + */ +static inline RangeType * +DatumGetRangeTypeP(Datum X) +{ + return (RangeType *) PG_DETOAST_DATUM(X); +} + +static inline RangeType * +DatumGetRangeTypePCopy(Datum X) +{ + return (RangeType *) PG_DETOAST_DATUM_COPY(X); +} + +static inline Datum +RangeTypePGetDatum(const RangeType *X) +{ + return 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, + struct Node *escontext); +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, + struct Node *escontext); +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 boundA, + RangeBound boundB); +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..a1f7c6b --- /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-2023, 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, Node *escontext); +extern char *format_procedure(Oid procedure_oid); +extern char *format_procedure_qualified(Oid procedure_oid); +extern void format_procedure_parts(Oid procedure_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..1426a35 --- /dev/null +++ b/src/include/utils/rel.h @@ -0,0 +1,712 @@ +/*------------------------------------------------------------------------- + * + * rel.h + * POSTGRES relation descriptor (a/k/a relcache entry) definitions. + * + * + * Portions Copyright (c) 1996-2023, 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/catalog.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/relfilelocator.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 +{ + RelFileLocator rd_locator; /* 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 storage was created before the + * current top transaction. (IndexStmt.oldNumber leads to the case of a new + * rel with an old rd_locator.) rd_firstRelfilelocatorSubid is the ID of the + * highest subtransaction an rd_locator change has survived into or zero if + * rd_locator matches the value it had at the start of the current top + * transaction. (Rolling back the subtransaction that + * rd_firstRelfilelocatorSubid denotes would restore rd_locator 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_newRelfilelocatorSubid is the ID of the highest subtransaction the + * most-recent relfilenumber 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 relfilenumbers 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_newRelfilelocatorSubid is now forgotten + * + * If every rd_*Subid field is zero, they are read-only outside + * relcache.c. Files that trigger rd_locator changes by updating + * pg_class.reltablespace and/or pg_class.relfilenode call + * RelationAssumeNewRelfilelocator() 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_newRelfilelocatorSubid; /* highest subxact changing + * rd_locator to current value */ + SubTransactionId rd_firstRelfilelocatorSubid; /* highest subxact + * changing rd_locator 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: */ + bool rd_attrsvalid; /* are bitmaps of attrs valid? */ + 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 */ + Bitmapset *rd_hotblockingattr; /* cols blocking HOT update */ + Bitmapset *rd_summarizedattr; /* cols indexed by summarizing indexes */ + + 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 +{ + pg_node_attr(no_equal, no_read, no_query_jumble) + + NodeTag type; + /* oid of the constraint itself */ + Oid conoid; + /* relation constrained by the foreign key */ + Oid conrelid; + /* relation referenced by the foreign key */ + Oid confrelid; + /* number of columns in the foreign key */ + int nkeys; + + /* + * these arrays each have nkeys valid entries: + */ + /* cols in referencing table */ + AttrNumber conkey[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys)); + /* cols in referenced table */ + AttrNumber confkey[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys)); + /* PK = FK operator OIDs */ + Oid conpfeqop[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys)); +} 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 relfilenumber map. Note multiple eval + * of argument! + */ +#define RelationIsMapped(relation) \ + (RELKIND_HAS_STORAGE((relation)->rd_rel->relkind) && \ + ((relation)->rd_rel->relfilenode == InvalidRelFileNumber)) + +#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_locator, rel->rd_backend)); + return rel->rd_smgr; +} + +/* + * RelationCloseSmgr + * Close the relation at the smgr level, if not already done. + */ +static inline void +RelationCloseSmgr(Relation relation) +{ + if (relation->rd_smgr != NULL) + smgrclose(relation->rd_smgr); + + /* smgrclose should unhook from owner pointer */ + Assert(relation->rd_smgr == NULL); +} +#endif /* !FRONTEND */ + +/* + * 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 + * RelFileLocator" in src/backend/access/transam/README. + */ +#define RelationNeedsWAL(relation) \ + (RelationIsPermanent(relation) && (XLogIsNeeded() || \ + (relation->rd_createSubid == InvalidSubTransactionId && \ + relation->rd_firstRelfilelocatorSubid == 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..3852464 --- /dev/null +++ b/src/include/utils/relcache.h @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------- + * + * relcache.h + * Relation descriptor cache definitions. + * + * + * Portions Copyright (c) 1996-2023, 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 "common/relpath.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 indexrel); +extern bytea **RelationGetIndexAttOptions(Relation relation, bool copy); + +/* + * Which set of columns to return by RelationGetIndexAttrBitmap. + */ +typedef enum IndexAttrBitmapKind +{ + INDEX_ATTR_BITMAP_KEY, + INDEX_ATTR_BITMAP_PRIMARY_KEY, + INDEX_ATTR_BITMAP_IDENTITY_KEY, + INDEX_ATTR_BITMAP_HOT_BLOCKING, + INDEX_ATTR_BITMAP_SUMMARIZED +} 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, + RelFileNumber relfilenumber, + Oid reltablespace, + bool shared_relation, + bool mapped_relation, + char relpersistence, + char relkind); + +/* + * Routines to manage assignment of new relfilenumber to a relation + */ +extern void RelationSetNewRelfilenumber(Relation relation, char persistence); +extern void RelationAssumeNewRelfilelocator(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/relfilenumbermap.h b/src/include/utils/relfilenumbermap.h new file mode 100644 index 0000000..d9b280d --- /dev/null +++ b/src/include/utils/relfilenumbermap.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * relfilenumbermap.h + * relfilenumber to oid mapping cache. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/relfilenumbermap.h + * + *------------------------------------------------------------------------- + */ +#ifndef RELFILENUMBERMAP_H +#define RELFILENUMBERMAP_H + +#include "common/relpath.h" + +extern Oid RelidByRelfilenumber(Oid reltablespace, + RelFileNumber relfilenumber); + +#endif /* RELFILENUMBERMAP_H */ diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h new file mode 100644 index 0000000..5c173bd --- /dev/null +++ b/src/include/utils/relmapper.h @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------- + * + * relmapper.h + * Catalog-to-filenumber mapping + * + * + * Portions Copyright (c) 1996-2023, 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 RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared); + +extern Oid RelationMapFilenumberToOid(RelFileNumber filenumber, bool shared); +extern RelFileNumber RelationMapOidToFilenumberForDatabase(char *dbpath, + Oid relationId); +extern void RelationMapCopy(Oid dbid, Oid tsid, char *srcdbpath, + char *dstdbpath); +extern void RelationMapUpdateMap(Oid relationId, RelFileNumber fileNumber, + 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..365cea1 --- /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-2023, 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..df9a2fb --- /dev/null +++ b/src/include/utils/reltrigger.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------- + * + * reltrigger.h + * POSTGRES relation trigger definitions. + * + * + * Portions Copyright (c) 1996-2023, 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..cd070b6 --- /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-2023, 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..ae58438 --- /dev/null +++ b/src/include/utils/resowner_private.h @@ -0,0 +1,117 @@ +/*------------------------------------------------------------------------- + * + * resowner_private.h + * POSTGRES resource owner private definitions. + * + * See utils/resowner/README for more info. + * + * + * Portions Copyright (c) 1996-2023, 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 IO-in-progress management */ +extern void ResourceOwnerEnlargeBufferIOs(ResourceOwner owner); +extern void ResourceOwnerRememberBufferIO(ResourceOwner owner, Buffer buffer); +extern void ResourceOwnerForgetBufferIO(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..1e95f83 --- /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-2023, 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..b006d9d --- /dev/null +++ b/src/include/utils/ruleutils.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * ruleutils.h + * Declarations for ruleutils.c + * + * Portions Copyright (c) 1996-2023, 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..e269448 --- /dev/null +++ b/src/include/utils/sampling.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * sampling.h + * definitions for sampling functions + * + * Portions Copyright (c) 1996-2023, 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..2f76c47 --- /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-2023, 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..c7075ad --- /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-2023, 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..980d37a --- /dev/null +++ b/src/include/utils/snapmgr.h @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + * + * snapmgr.h + * POSTGRES snapshot manager + * + * Portions Copyright (c) 1996-2023, 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 historic_snapshot, 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..583a667 --- /dev/null +++ b/src/include/utils/snapshot.h @@ -0,0 +1,219 @@ +/*------------------------------------------------------------------------- + * + * snapshot.h + * POSTGRES snapshot definition + * + * Portions Copyright (c) 1996-2023, 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..475ed1d --- /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-2023, 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 abbreviated 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..c6c754a --- /dev/null +++ b/src/include/utils/spccache.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------- + * + * spccache.h + * Tablespace cache. + * + * Portions Copyright (c) 1996-2023, 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..67ea6e4 --- /dev/null +++ b/src/include/utils/syscache.h @@ -0,0 +1,227 @@ +/*------------------------------------------------------------------------- + * + * syscache.h + * System catalog cache definitions. + * + * See also lsyscache.h, which provides convenience routines for + * common cache-lookup operations. + * + * Portions Copyright (c) 1996-2023, 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 Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, + AttrNumber attributeNumber); + +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..e561a1c --- /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-2023, 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..c4dd96c --- /dev/null +++ b/src/include/utils/timestamp.h @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------- + * + * timestamp.h + * Definitions for the SQL "timestamp" and "interval" types. + * + * Portions Copyright (c) 1996-2023, 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" + + +/* + * Functions 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! + */ +static inline Timestamp +DatumGetTimestamp(Datum X) +{ + return (Timestamp) DatumGetInt64(X); +} + +static inline TimestampTz +DatumGetTimestampTz(Datum X) +{ + return (TimestampTz) DatumGetInt64(X); +} + +static inline Interval * +DatumGetIntervalP(Datum X) +{ + return (Interval *) DatumGetPointer(X); +} + +static inline Datum +TimestampGetDatum(Timestamp X) +{ + return Int64GetDatum(X); +} + +static inline Datum +TimestampTzGetDatum(TimestampTz X) +{ + return Int64GetDatum(X); +} + +static inline Datum +IntervalPGetDatum(const Interval *X) +{ + return 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) + +/* Macros for doing timestamp arithmetic without assuming timestamp's units */ +#define TimestampTzPlusMilliseconds(tz,ms) ((tz) + ((ms) * (int64) 1000)) +#define TimestampTzPlusSeconds(tz,s) ((tz) + ((s) * (int64) 1000000)) + + +/* 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 *result); +extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, + fsec_t *fsec, const char **tzn, pg_tz *attimezone); +extern void dt2time(Timestamp jd, 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..af057b6 --- /dev/null +++ b/src/include/utils/tuplesort.h @@ -0,0 +1,445 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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/logtape.h" +#include "utils/relcache.h" +#include "utils/sortsupport.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; + +/* + * The objects we actually sort are SortTuple structs. These contain + * a pointer to the tuple proper (might be a MinimalTuple or IndexTuple), + * which is a separate palloc chunk --- we assume it is just one chunk and + * can be freed by a simple pfree() (except during merge, when we use a + * simple slab allocator). SortTuples also contain the tuple's first key + * column in Datum/nullflag format, and a source/input tape number that + * tracks which tape each heap element/slot belongs to during merging. + * + * Storing the first key column lets us save heap_getattr or index_getattr + * calls during tuple comparisons. We could extract and save all the key + * columns not just the first, but this would increase code complexity and + * overhead, and wouldn't actually save any comparison cycles in the common + * case where the first key determines the comparison result. Note that + * for a pass-by-reference datatype, datum1 points into the "tuple" storage. + * + * There is one special case: when the sort support infrastructure provides an + * "abbreviated key" representation, where the key is (typically) a pass by + * value proxy for a pass by reference type. In this case, the abbreviated key + * is stored in datum1 in place of the actual first key column. + * + * When sorting single Datums, the data value is represented directly by + * datum1/isnull1 for pass by value types (or null values). If the datatype is + * pass-by-reference and isnull1 is false, then "tuple" points to a separately + * palloc'd data value, otherwise "tuple" is NULL. The value of datum1 is then + * either the same pointer as "tuple", or is an abbreviated key value as + * described above. Accordingly, "tuple" is always used in preference to + * datum1 as the authoritative value for pass-by-reference cases. + */ +typedef struct +{ + void *tuple; /* the tuple itself */ + Datum datum1; /* value of first key column */ + bool isnull1; /* is first key column NULL? */ + int srctape; /* source tape number */ +} SortTuple; + +typedef int (*SortTupleComparator) (const SortTuple *a, const SortTuple *b, + Tuplesortstate *state); + +/* + * The public part of a Tuple sort operation state. This data structure + * contains the definition of sort-variant-specific interface methods and + * the part of Tuple sort operation state required by their implementations. + */ +typedef struct +{ + /* + * These function pointers decouple the routines that must know what kind + * of tuple we are sorting from the routines that don't need to know it. + * They are set up by the tuplesort_begin_xxx routines. + * + * Function to compare two tuples; result is per qsort() convention, ie: + * <0, 0, >0 according as a<b, a=b, a>b. The API must match + * qsort_arg_comparator. + */ + SortTupleComparator comparetup; + + /* + * Alter datum1 representation in the SortTuple's array back from the + * abbreviated key to the first column value. + */ + void (*removeabbrev) (Tuplesortstate *state, SortTuple *stups, + int count); + + /* + * Function to write a stored tuple onto tape. The representation of the + * tuple on tape need not be the same as it is in memory. + */ + void (*writetup) (Tuplesortstate *state, LogicalTape *tape, + SortTuple *stup); + + /* + * Function to read a stored tuple from tape back into memory. 'len' is + * the already-read length of the stored tuple. The tuple is allocated + * from the slab memory arena, or is palloc'd, see + * tuplesort_readtup_alloc(). + */ + void (*readtup) (Tuplesortstate *state, SortTuple *stup, + LogicalTape *tape, unsigned int len); + + /* + * Function to do some specific release of resources for the sort variant. + * In particular, this function should free everything stored in the "arg" + * field, which wouldn't be cleared on reset of the Tuple sort memory + * contexts. This can be NULL if nothing specific needs to be done. + */ + void (*freestate) (Tuplesortstate *state); + + /* + * The subsequent fields are used in the implementations of the functions + * above. + */ + MemoryContext maincontext; /* memory context for tuple sort metadata that + * persists across multiple batches */ + MemoryContext sortcontext; /* memory context holding most sort data */ + MemoryContext tuplecontext; /* sub-context of sortcontext for tuple data */ + + /* + * Whether SortTuple's datum1 and isnull1 members are maintained by the + * above routines. If not, some sort specializations are disabled. + */ + bool haveDatum1; + + /* + * The sortKeys variable is used by every case other than the hash index + * case; it is set by tuplesort_begin_xxx. tupDesc is only used by the + * MinimalTuple and CLUSTER routines, though. + */ + int nKeys; /* number of columns in sort key */ + SortSupport sortKeys; /* array of length nKeys */ + + /* + * This variable is shared by the single-key MinimalTuple case and the + * Datum case (which both use qsort_ssup()). Otherwise, it's NULL. The + * presence of a value in this field is also checked by various sort + * specialization functions as an optimization when comparing the leading + * key in a tiebreak situation to determine if there are any subsequent + * keys to sort on. + */ + SortSupport onlyKey; + + int sortopt; /* Bitmask of flags used to setup sort */ + + bool tuples; /* Can SortTuple.tuple ever be set? */ + + void *arg; /* Specific information for the sort variant */ +} TuplesortPublic; + +/* Sort parallel code from state for sort__start probes */ +#define PARALLEL_SORT(coordinate) (coordinate == NULL || \ + (coordinate)->sharedsort == NULL ? 0 : \ + (coordinate)->isWorker ? 1 : 2) + +#define TuplesortstateGetPublic(state) ((TuplesortPublic *) state) + +/* When using this macro, beware of double evaluation of len */ +#define LogicalTapeReadExact(tape, ptr, len) \ + do { \ + if (LogicalTapeRead(tape, ptr, len) != (size_t) (len)) \ + elog(ERROR, "unexpected end of data"); \ + } while(0) + +/* + * 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_common(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_puttuple_common(Tuplesortstate *state, + SortTuple *tuple, bool useAbbrev); +extern void tuplesort_performsort(Tuplesortstate *state); +extern bool tuplesort_gettuple_common(Tuplesortstate *state, bool forward, + SortTuple *stup); +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); + +extern void *tuplesort_readtup_alloc(Tuplesortstate *state, Size tuplen); + + +/* tuplesortvariants.c */ + +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_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 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, bool copy, + Datum *val, bool *isNull, Datum *abbrev); + + +#endif /* TUPLESORT_H */ diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h new file mode 100644 index 0000000..36424b8 --- /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-2023, 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..95f3a9e --- /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-2023, 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..760785b --- /dev/null +++ b/src/include/utils/tzparser.h @@ -0,0 +1,39 @@ +/*------------------------------------------------------------------------- + * + * tzparser.h + * Timezone offset file parsing definitions. + * + * Portions Copyright (c) 1996-2023, 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/usercontext.h b/src/include/utils/usercontext.h new file mode 100644 index 0000000..a8195c1 --- /dev/null +++ b/src/include/utils/usercontext.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * usercontext.h + * Convenience functions for running code as a different database user. + * + *------------------------------------------------------------------------- + */ +#ifndef USERCONTEXT_H +#define USERCONTEXT_H + +/* + * When temporarily changing to run as a different user, this structure + * holds the details needed to restore the original state. + */ +typedef struct UserContext +{ + Oid save_userid; + int save_sec_context; + int save_nestlevel; +} UserContext; + +/* Function prototypes. */ +extern void SwitchToUntrustedUser(Oid userid, UserContext *context); +extern void RestoreUserContext(UserContext *context); + +#endif /* USERCONTEXT_H */ diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h new file mode 100644 index 0000000..1117717 --- /dev/null +++ b/src/include/utils/uuid.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * 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-2023, 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 */ +static inline Datum +UUIDPGetDatum(const pg_uuid_t *X) +{ + return PointerGetDatum(X); +} + +#define PG_RETURN_UUID_P(X) return UUIDPGetDatum(X) + +static inline pg_uuid_t * +DatumGetUUIDP(Datum X) +{ + return (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..3bb7945 --- /dev/null +++ b/src/include/utils/varbit.h @@ -0,0 +1,89 @@ +/*------------------------------------------------------------------------- + * + * varbit.h + * Functions for the SQL datatypes BIT() and BIT VARYING(). + * + * Code originally contributed by Adriaan Joubert. + * + * Portions Copyright (c) 1996-2023, 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. + */ +static inline VarBit * +DatumGetVarBitP(Datum X) +{ + return (VarBit *) PG_DETOAST_DATUM(X); +} + +static inline VarBit * +DatumGetVarBitPCopy(Datum X) +{ + return (VarBit *) PG_DETOAST_DATUM_COPY(X); +} + +static inline Datum +VarBitPGetDatum(const VarBit *X) +{ + return 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..77f5b24 --- /dev/null +++ b/src/include/utils/varlena.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * varlena.h + * Functions for the variable-length built-in types. + * + * Portions Copyright (c) 1996-2023, 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); + +typedef struct ClosestMatchState +{ + const char *source; + int min_d; + int max_d; + const char *match; +} ClosestMatchState; + +extern void initClosestMatch(ClosestMatchState *state, const char *source, int max_d); +extern void updateClosestMatch(ClosestMatchState *state, const char *candidate); +extern const char *getClosestMatch(ClosestMatchState *state); + +#endif diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h new file mode 100644 index 0000000..2adc5df --- /dev/null +++ b/src/include/utils/wait_event.h @@ -0,0 +1,295 @@ +/*------------------------------------------------------------------------- + * wait_event.h + * Definitions related to wait event reporting + * + * Copyright (c) 2001-2023, 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_LOGICAL_PARALLEL_APPLY_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_DECIDE, + WAIT_EVENT_HASH_GROW_BATCHES_ELECT, + WAIT_EVENT_HASH_GROW_BATCHES_FINISH, + WAIT_EVENT_HASH_GROW_BATCHES_REALLOCATE, + WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION, + WAIT_EVENT_HASH_GROW_BUCKETS_ELECT, + WAIT_EVENT_HASH_GROW_BUCKETS_REALLOCATE, + WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT, + WAIT_EVENT_LOGICAL_APPLY_SEND_DATA, + WAIT_EVENT_LOGICAL_PARALLEL_APPLY_STATE_CHANGE, + 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_SPIN_DELAY, + 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_ALLOCATE, + 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_REPLACE, + 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, + WAIT_EVENT_VERSION_FILE_SYNC +} 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..2f5e14b --- /dev/null +++ b/src/include/utils/xid8.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + * + * xid8.h + * Header file for the "xid8" ADT. + * + * Copyright (c) 2020-2023, PostgreSQL Global Development Group + * + * src/include/utils/xid8.h + * + *------------------------------------------------------------------------- + */ +#ifndef XID8_H +#define XID8_H + +#include "access/transam.h" + +static inline FullTransactionId +DatumGetFullTransactionId(Datum X) +{ + return FullTransactionIdFromU64(DatumGetUInt64(X)); +} + +static inline Datum +FullTransactionIdGetDatum(FullTransactionId X) +{ + return 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..224f6d7 --- /dev/null +++ b/src/include/utils/xml.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * xml.h + * Declarations for XML data type support. + * + * + * Portions Copyright (c) 1996-2023, 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; + +static inline xmltype * +DatumGetXmlP(Datum X) +{ + return (xmltype *) PG_DETOAST_DATUM(X); +} + +static inline Datum +XmlPGetDatum(const xmltype *X) +{ + return 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_arg, 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_options(xmltype *data, XmlOptionType xmloption_arg, + bool indent); +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 */ |