postgresql/src/include/nodes/subscripting.h

168 lines
8.4 KiB
C

/*-------------------------------------------------------------------------
*
* subscripting.h
* API for generic type subscripting
*
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/nodes/subscripting.h
*
*-------------------------------------------------------------------------
*/
#ifndef SUBSCRIPTING_H
#define SUBSCRIPTING_H
#include "nodes/primnodes.h"
/* Forward declarations, to avoid including other headers */
struct ParseState;
struct SubscriptingRefState;
struct SubscriptExecSteps;
/*
* The SQL-visible function that defines a subscripting method is declared
* subscripting_function(internal) returns internal
* but it actually is not passed any parameter. It must return a pointer
* to a "struct SubscriptRoutines" that provides pointers to the individual
* subscript parsing and execution methods. Typically the pointer will point
* to a "static const" variable, but at need it can point to palloc'd space.
* The type (after domain-flattening) of the head variable or expression
* of a subscripting construct determines which subscripting function is
* called for that construct.
*
* In addition to the method pointers, struct SubscriptRoutines includes
* several bool flags that specify properties of the subscripting actions
* this data type can perform:
*
* fetch_strict indicates that a fetch SubscriptRef is strict, i.e., returns
* NULL if any input (either the container or any subscript) is NULL.
*
* fetch_leakproof indicates that a fetch SubscriptRef is leakproof, i.e.,
* will not throw any data-value-dependent errors. Typically this requires
* silently returning NULL for invalid subscripts.
*
* store_leakproof similarly indicates whether an assignment SubscriptRef is
* leakproof. (It is common to prefer throwing errors for invalid subscripts
* in assignments; that's fine, but it makes the operation not leakproof.
* In current usage there is no advantage in making assignments leakproof.)
*
* There is no store_strict flag. Such behavior would generally be
* undesirable, since for example a null subscript in an assignment would
* cause the entire container to become NULL.
*
* Regardless of these flags, all SubscriptRefs are expected to be immutable,
* that is they must always give the same results for the same inputs.
* They are expected to always be parallel-safe, as well.
*/
/*
* The transform method is called during parse analysis of a subscripting
* construct. The SubscriptingRef node has been constructed, but some of
* its fields still need to be filled in, and the subscript expression(s)
* are still in raw form. The transform method is responsible for doing
* parse analysis of each subscript expression (using transformExpr),
* coercing the subscripts to whatever type it needs, and building the
* refupperindexpr and reflowerindexpr lists from those results. The
* reflowerindexpr list must be empty for an element operation, or the
* same length as refupperindexpr for a slice operation. Insert NULLs
* (that is, an empty parse tree, not a null Const node) for any omitted
* subscripts in a slice operation. (Of course, if the transform method
* does not care to support slicing, it can just throw an error if isSlice.)
* See array_subscript_transform() for sample code.
*
* The transform method is also responsible for identifying the result type
* of the subscripting operation. At call, refcontainertype and reftypmod
* describe the container type (this will be a base type not a domain), and
* refelemtype is set to the container type's pg_type.typelem value. The
* transform method must set refrestype and reftypmod to describe the result
* of subscripting. For arrays, refrestype is set to refelemtype for an
* element operation or refcontainertype for a slice, while reftypmod stays
* the same in either case; but other types might use other rules. The
* transform method should ignore refcollid, as that's determined later on
* during parsing.
*
* At call, refassgnexpr has not been filled in, so the SubscriptingRef node
* always looks like a fetch; refrestype should be set as though for a
* fetch, too. (The isAssignment parameter is typically only useful if the
* transform method wishes to throw an error for not supporting assignment.)
* To complete processing of an assignment, the core parser will coerce the
* element/slice source expression to the returned refrestype and reftypmod
* before putting it into refassgnexpr. It will then set refrestype and
* reftypmod to again describe the container type, since that's what an
* assignment must return.
*/
typedef void (*SubscriptTransform) (SubscriptingRef *sbsref,
List *indirection,
struct ParseState *pstate,
bool isSlice,
bool isAssignment);
/*
* The exec_setup method is called during executor-startup compilation of a
* SubscriptingRef node in an expression. It must fill *methods with pointers
* to functions that can be called for execution of the node. Optionally,
* exec_setup can initialize sbsrefstate->workspace to point to some palloc'd
* workspace for execution. (Typically, such workspace is used to hold
* looked-up catalog data and/or provide space for the check_subscripts step
* to pass data forward to the other step functions.) See executor/execExpr.h
* for the definitions of these structs and other ones used in expression
* execution.
*
* The methods to be provided are:
*
* sbs_check_subscripts: examine the just-computed subscript values available
* in sbsrefstate's arrays, and possibly convert them into another form
* (stored in sbsrefstate->workspace). Return TRUE to continue with
* evaluation of the subscripting construct, or FALSE to skip it and return an
* overall NULL result. If this is a fetch and the data type's fetch_strict
* flag is true, then sbs_check_subscripts must return FALSE if there are any
* NULL subscripts. Otherwise it can choose to throw an error, or return
* FALSE, or let sbs_fetch or sbs_assign deal with the null subscripts.
*
* sbs_fetch: perform a subscripting fetch, using the container value in
* *op->resvalue and the subscripts from sbs_check_subscripts. If
* fetch_strict is true then all these inputs can be assumed non-NULL,
* otherwise sbs_fetch must check for null inputs. Place the result in
* *op->resvalue / *op->resnull.
*
* sbs_assign: perform a subscripting assignment, using the original
* container value in *op->resvalue / *op->resnull, the subscripts from
* sbs_check_subscripts, and the new element/slice value in
* sbsrefstate->replacevalue/replacenull. Any of these inputs might be NULL
* (unless sbs_check_subscripts rejected null subscripts). Place the result
* (an entire new container value) in *op->resvalue / *op->resnull.
*
* sbs_fetch_old: this is only used in cases where an element or slice
* assignment involves an assignment to a sub-field or sub-element
* (i.e., nested containers are involved). It must fetch the existing
* value of the target element or slice. This is exactly the same as
* sbs_fetch except that (a) it must cope with a NULL container, and
* with NULL subscripts if sbs_check_subscripts allows them (typically,
* returning NULL is good enough); and (b) the result must be placed in
* sbsrefstate->prevvalue/prevnull, without overwriting *op->resvalue.
*
* Subscripting implementations that do not support assignment need not
* provide sbs_assign or sbs_fetch_old methods. It might be reasonable
* to also omit sbs_check_subscripts, in which case the sbs_fetch method must
* combine the functionality of sbs_check_subscripts and sbs_fetch. (The
* main reason to have a separate sbs_check_subscripts method is so that
* sbs_fetch_old and sbs_assign need not duplicate subscript processing.)
* Set the relevant pointers to NULL for any omitted methods.
*/
typedef void (*SubscriptExecSetup) (const SubscriptingRef *sbsref,
struct SubscriptingRefState *sbsrefstate,
struct SubscriptExecSteps *methods);
/* Struct returned by the SQL-visible subscript handler function */
typedef struct SubscriptRoutines
{
SubscriptTransform transform; /* parse analysis function */
SubscriptExecSetup exec_setup; /* expression compilation function */
bool fetch_strict; /* is fetch SubscriptRef strict? */
bool fetch_leakproof; /* is fetch SubscriptRef leakproof? */
bool store_leakproof; /* is assignment SubscriptRef leakproof? */
} SubscriptRoutines;
#endif /* SUBSCRIPTING_H */