summaryrefslogtreecommitdiffstats
path: root/src/include/nodes/subscripting.h
blob: 7bee44ca4b9a744472c7de644cca522f47b3dc68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*-------------------------------------------------------------------------
 *
 * subscripting.h
 *		API for generic type subscripting
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/subscripting.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef SUBSCRIPTING_H
#define SUBSCRIPTING_H

#include "nodes/primnodes.h"

/* Forward declarations, to avoid including other headers */
struct ParseState;
struct SubscriptingRefState;
struct SubscriptExecSteps;

/*
 * The SQL-visible function that defines a subscripting method is declared
 *		subscripting_function(internal) returns internal
 * but it actually is not passed any parameter.  It must return a pointer
 * to a "struct SubscriptRoutines" that provides pointers to the individual
 * subscript parsing and execution methods.  Typically the pointer will point
 * to a "static const" variable, but at need it can point to palloc'd space.
 * The type (after domain-flattening) of the head variable or expression
 * of a subscripting construct determines which subscripting function is
 * called for that construct.
 *
 * In addition to the method pointers, struct SubscriptRoutines includes
 * several bool flags that specify properties of the subscripting actions
 * this data type can perform:
 *
 * fetch_strict indicates that a fetch SubscriptRef is strict, i.e., returns
 * NULL if any input (either the container or any subscript) is NULL.
 *
 * fetch_leakproof indicates that a fetch SubscriptRef is leakproof, i.e.,
 * will not throw any data-value-dependent errors.  Typically this requires
 * silently returning NULL for invalid subscripts.
 *
 * store_leakproof similarly indicates whether an assignment SubscriptRef is
 * leakproof.  (It is common to prefer throwing errors for invalid subscripts
 * in assignments; that's fine, but it makes the operation not leakproof.
 * In current usage there is no advantage in making assignments leakproof.)
 *
 * There is no store_strict flag.  Such behavior would generally be
 * undesirable, since for example a null subscript in an assignment would
 * cause the entire container to become NULL.
 *
 * Regardless of these flags, all SubscriptRefs are expected to be immutable,
 * that is they must always give the same results for the same inputs.
 * They are expected to always be parallel-safe, as well.
 */

/*
 * The transform method is called during parse analysis of a subscripting
 * construct.  The SubscriptingRef node has been constructed, but some of
 * its fields still need to be filled in, and the subscript expression(s)
 * are still in raw form.  The transform method is responsible for doing
 * parse analysis of each subscript expression (using transformExpr),
 * coercing the subscripts to whatever type it needs, and building the
 * refupperindexpr and reflowerindexpr lists from those results.  The
 * reflowerindexpr list must be empty for an element operation, or the
 * same length as refupperindexpr for a slice operation.  Insert NULLs
 * (that is, an empty parse tree, not a null Const node) for any omitted
 * subscripts in a slice operation.  (Of course, if the transform method
 * does not care to support slicing, it can just throw an error if isSlice.)
 * See array_subscript_transform() for sample code.
 *
 * The transform method is also responsible for identifying the result type
 * of the subscripting operation.  At call, refcontainertype and reftypmod
 * describe the container type (this will be a base type not a domain), and
 * refelemtype is set to the container type's pg_type.typelem value.  The
 * transform method must set refrestype and reftypmod to describe the result
 * of subscripting.  For arrays, refrestype is set to refelemtype for an
 * element operation or refcontainertype for a slice, while reftypmod stays
 * the same in either case; but other types might use other rules.  The
 * transform method should ignore refcollid, as that's determined later on
 * during parsing.
 *
 * At call, refassgnexpr has not been filled in, so the SubscriptingRef node
 * always looks like a fetch; refrestype should be set as though for a
 * fetch, too.  (The isAssignment parameter is typically only useful if the
 * transform method wishes to throw an error for not supporting assignment.)
 * To complete processing of an assignment, the core parser will coerce the
 * element/slice source expression to the returned refrestype and reftypmod
 * before putting it into refassgnexpr.  It will then set refrestype and
 * reftypmod to again describe the container type, since that's what an
 * assignment must return.
 */
typedef void (*SubscriptTransform) (SubscriptingRef *sbsref,
									List *indirection,
									struct ParseState *pstate,
									bool isSlice,
									bool isAssignment);

/*
 * The exec_setup method is called during executor-startup compilation of a
 * SubscriptingRef node in an expression.  It must fill *methods with pointers
 * to functions that can be called for execution of the node.  Optionally,
 * exec_setup can initialize sbsrefstate->workspace to point to some palloc'd
 * workspace for execution.  (Typically, such workspace is used to hold
 * looked-up catalog data and/or provide space for the check_subscripts step
 * to pass data forward to the other step functions.)  See executor/execExpr.h
 * for the definitions of these structs and other ones used in expression
 * execution.
 *
 * The methods to be provided are:
 *
 * sbs_check_subscripts: examine the just-computed subscript values available
 * in sbsrefstate's arrays, and possibly convert them into another form
 * (stored in sbsrefstate->workspace).  Return TRUE to continue with
 * evaluation of the subscripting construct, or FALSE to skip it and return an
 * overall NULL result.  If this is a fetch and the data type's fetch_strict
 * flag is true, then sbs_check_subscripts must return FALSE if there are any
 * NULL subscripts.  Otherwise it can choose to throw an error, or return
 * FALSE, or let sbs_fetch or sbs_assign deal with the null subscripts.
 *
 * sbs_fetch: perform a subscripting fetch, using the container value in
 * *op->resvalue and the subscripts from sbs_check_subscripts.  If
 * fetch_strict is true then all these inputs can be assumed non-NULL,
 * otherwise sbs_fetch must check for null inputs.  Place the result in
 * *op->resvalue / *op->resnull.
 *
 * sbs_assign: perform a subscripting assignment, using the original
 * container value in *op->resvalue / *op->resnull, the subscripts from
 * sbs_check_subscripts, and the new element/slice value in
 * sbsrefstate->replacevalue/replacenull.  Any of these inputs might be NULL
 * (unless sbs_check_subscripts rejected null subscripts).  Place the result
 * (an entire new container value) in *op->resvalue / *op->resnull.
 *
 * sbs_fetch_old: this is only used in cases where an element or slice
 * assignment involves an assignment to a sub-field or sub-element
 * (i.e., nested containers are involved).  It must fetch the existing
 * value of the target element or slice.  This is exactly the same as
 * sbs_fetch except that (a) it must cope with a NULL container, and
 * with NULL subscripts if sbs_check_subscripts allows them (typically,
 * returning NULL is good enough); and (b) the result must be placed in
 * sbsrefstate->prevvalue/prevnull, without overwriting *op->resvalue.
 *
 * Subscripting implementations that do not support assignment need not
 * provide sbs_assign or sbs_fetch_old methods.  It might be reasonable
 * to also omit sbs_check_subscripts, in which case the sbs_fetch method must
 * combine the functionality of sbs_check_subscripts and sbs_fetch.  (The
 * main reason to have a separate sbs_check_subscripts method is so that
 * sbs_fetch_old and sbs_assign need not duplicate subscript processing.)
 * Set the relevant pointers to NULL for any omitted methods.
 */
typedef void (*SubscriptExecSetup) (const SubscriptingRef *sbsref,
									struct SubscriptingRefState *sbsrefstate,
									struct SubscriptExecSteps *methods);

/* Struct returned by the SQL-visible subscript handler function */
typedef struct SubscriptRoutines
{
	SubscriptTransform transform;	/* parse analysis function */
	SubscriptExecSetup exec_setup;	/* expression compilation function */
	bool		fetch_strict;	/* is fetch SubscriptRef strict? */
	bool		fetch_leakproof;	/* is fetch SubscriptRef leakproof? */
	bool		store_leakproof;	/* is assignment SubscriptRef leakproof? */
} SubscriptRoutines;

#endif							/* SUBSCRIPTING_H */