diff options
Diffstat (limited to 'src/backend/utils/fmgr/README')
-rw-r--r-- | src/backend/utils/fmgr/README | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/backend/utils/fmgr/README b/src/backend/utils/fmgr/README new file mode 100644 index 0000000..1e4c4b9 --- /dev/null +++ b/src/backend/utils/fmgr/README @@ -0,0 +1,331 @@ +src/backend/utils/fmgr/README + +Function Manager +================ + +[This file originally explained the transition from the V0 to the V1 +interface. Now it just explains some internals and rationale for the V1 +interface, while the V0 interface has been removed.] + +The V1 Function-Manager Interface +--------------------------------- + +The core of the design is data structures for representing the result of a +function lookup and for representing the parameters passed to a specific +function invocation. (We want to keep function lookup separate from +function call, since many parts of the system apply the same function over +and over; the lookup overhead should be paid once per query, not once per +tuple.) + + +When a function is looked up in pg_proc, the result is represented as + +typedef struct +{ + PGFunction fn_addr; /* pointer to function or handler to be called */ + Oid fn_oid; /* OID of function (NOT of handler, if any) */ + short fn_nargs; /* number of input args (0..FUNC_MAX_ARGS) */ + bool fn_strict; /* function is "strict" (NULL in => NULL out) */ + bool fn_retset; /* function returns a set (over multiple calls) */ + unsigned char fn_stats; /* collect stats if track_functions > this */ + void *fn_extra; /* extra space for use by handler */ + MemoryContext fn_mcxt; /* memory context to store fn_extra in */ + Node *fn_expr; /* expression parse tree for call, or NULL */ +} FmgrInfo; + +For an ordinary built-in function, fn_addr is just the address of the C +routine that implements the function. Otherwise it is the address of a +handler for the class of functions that includes the target function. +The handler can use the function OID and perhaps also the fn_extra slot +to find the specific code to execute. (fn_oid = InvalidOid can be used +to denote a not-yet-initialized FmgrInfo struct. fn_extra will always +be NULL when an FmgrInfo is first filled by the function lookup code, but +a function handler could set it to avoid making repeated lookups of its +own when the same FmgrInfo is used repeatedly during a query.) fn_nargs +is the number of arguments expected by the function, fn_strict is its +strictness flag, and fn_retset shows whether it returns a set; all of +these values come from the function's pg_proc entry. fn_stats is also +set up to control whether or not to track runtime statistics for calling +this function. + +If the function is being called as part of a SQL expression, fn_expr will +point to the expression parse tree for the function call; this can be used +to extract parse-time knowledge about the actual arguments. Note that this +field really is information about the arguments rather than information +about the function, but it's proven to be more convenient to keep it in +FmgrInfo than in FunctionCallInfoBaseData where it might more logically go. + + +During a call of a function, the following data structure is created +and passed to the function: + +typedef struct +{ + FmgrInfo *flinfo; /* ptr to lookup info used for this call */ + Node *context; /* pass info about context of call */ + Node *resultinfo; /* pass or return extra info about result */ + Oid fncollation; /* collation for function to use */ + bool isnull; /* function must set true if result is NULL */ + short nargs; /* # arguments actually passed */ + NullableDatum args[]; /* Arguments passed to function */ +} FunctionCallInfoBaseData; +typedef FunctionCallInfoBaseData* FunctionCallInfo; + +flinfo points to the lookup info used to make the call. Ordinary functions +will probably ignore this field, but function class handlers will need it +to find out the OID of the specific function being called. + +context is NULL for an "ordinary" function call, but may point to additional +info when the function is called in certain contexts. (For example, the +trigger manager will pass information about the current trigger event here.) +If context is used, it should point to some subtype of Node; the particular +kind of context is indicated by the node type field. (A callee should +always check the node type before assuming it knows what kind of context is +being passed.) fmgr itself puts no other restrictions on the use of this +field. + +resultinfo is NULL when calling any function from which a simple Datum +result is expected. It may point to some subtype of Node if the function +returns more than a Datum. (For example, resultinfo is used when calling a +function that returns a set, as discussed below.) Like the context field, +resultinfo is a hook for expansion; fmgr itself doesn't constrain the use +of the field. + +fncollation is the input collation derived by the parser, or InvalidOid +when there are no inputs of collatable types or they don't share a common +collation. This is effectively a hidden additional argument, which +collation-sensitive functions can use to determine their behavior. + +nargs and args[] hold the arguments being passed to the function. +Notice that all the arguments passed to a function (as well as its result +value) will now uniformly be of type Datum. As discussed below, callers +and callees should apply the standard Datum-to-and-from-whatever macros +to convert to the actual argument types of a particular function. The +value in args[i].value is unspecified when args[i].isnull is true. + +It is generally the responsibility of the caller to ensure that the +number of arguments passed matches what the callee is expecting; except +for callees that take a variable number of arguments, the callee will +typically ignore the nargs field and just grab values from args[]. + +The isnull field will be initialized to "false" before the call. On +return from the function, isnull is the null flag for the function result: +if it is true the function's result is NULL, regardless of the actual +function return value. Note that simple "strict" functions can ignore +both isnull and args[i].isnull, since they won't even get called when there +are any TRUE values in args[].isnull. + +FunctionCallInfo replaces FmgrValues plus a bunch of ad-hoc parameter +conventions, global variables (fmgr_pl_finfo and CurrentTriggerData at +least), and other uglinesses. + + +Callees, whether they be individual functions or function handlers, +shall always have this signature: + +Datum function (FunctionCallInfo fcinfo); + +which is represented by the typedef + +typedef Datum (*PGFunction) (FunctionCallInfo fcinfo); + +The function is responsible for setting fcinfo->isnull appropriately +as well as returning a result represented as a Datum. Note that since +all callees will now have exactly the same signature, and will be called +through a function pointer declared with exactly that signature, we +should have no portability or optimization problems. + + +Function Coding Conventions +--------------------------- + +Here are the proposed macros and coding conventions: + +The definition of an fmgr-callable function will always look like + +Datum +function_name(PG_FUNCTION_ARGS) +{ + ... +} + +"PG_FUNCTION_ARGS" just expands to "FunctionCallInfo fcinfo". The main +reason for using this macro is to make it easy for scripts to spot function +definitions. However, if we ever decide to change the calling convention +again, it might come in handy to have this macro in place. + +A nonstrict function is responsible for checking whether each individual +argument is null or not, which it can do with PG_ARGISNULL(n) (which is +just "fcinfo->args[n].isnull"). It should avoid trying to fetch the value +of any argument that is null. + +Both strict and nonstrict functions can return NULL, if needed, with + PG_RETURN_NULL(); +which expands to + { fcinfo->isnull = true; return (Datum) 0; } + +Argument values are ordinarily fetched using code like + int32 name = PG_GETARG_INT32(number); + +For float4, float8, and int8, the PG_GETARG macros will hide whether the +types are pass-by-value or pass-by-reference. For example, if float8 is +pass-by-reference then PG_GETARG_FLOAT8 expands to + (* (float8 *) DatumGetPointer(fcinfo->args[number].value)) +and would typically be called like this: + float8 arg = PG_GETARG_FLOAT8(0); +For what are now historical reasons, the float-related typedefs and macros +express the type width in bytes (4 or 8), whereas we prefer to label the +widths of integer types in bits. + +Non-null values are returned with a PG_RETURN_XXX macro of the appropriate +type. For example, PG_RETURN_INT32 expands to + return Int32GetDatum(x) +PG_RETURN_FLOAT4, PG_RETURN_FLOAT8, and PG_RETURN_INT64 hide whether their +data types are pass-by-value or pass-by-reference, by doing a palloc if +needed. + +fmgr.h will provide PG_GETARG and PG_RETURN macros for all the basic data +types. Modules or header files that define specialized SQL datatypes +(eg, timestamp) should define appropriate macros for those types, so that +functions manipulating the types can be coded in the standard style. + +For non-primitive data types (particularly variable-length types) it won't +be very practical to hide the pass-by-reference nature of the data type, +so the PG_GETARG and PG_RETURN macros for those types won't do much more +than DatumGetPointer/PointerGetDatum plus the appropriate typecast (but see +TOAST discussion, below). Functions returning such types will need to +palloc() their result space explicitly. I recommend naming the GETARG and +RETURN macros for such types to end in "_P", as a reminder that they +produce or take a pointer. For example, PG_GETARG_TEXT_P yields "text *". + +When a function needs to access fcinfo->flinfo or one of the other auxiliary +fields of FunctionCallInfo, it should just do it. I doubt that providing +syntactic-sugar macros for these cases is useful. + + +Support for TOAST-Able Data Types +--------------------------------- + +For TOAST-able data types, the PG_GETARG macro will deliver a de-TOASTed +data value. There might be a few cases where the still-toasted value is +wanted, but the vast majority of cases want the de-toasted result, so +that will be the default. To get the argument value without causing +de-toasting, use PG_GETARG_RAW_VARLENA_P(n). + +Some functions require a modifiable copy of their input values. In these +cases, it's silly to do an extra copy step if we copied the data anyway +to de-TOAST it. Therefore, each toastable datatype has an additional +fetch macro, for example PG_GETARG_TEXT_P_COPY(n), which delivers a +guaranteed-fresh copy, combining this with the detoasting step if possible. + +There is also a PG_FREE_IF_COPY(ptr,n) macro, which pfree's the given +pointer if and only if it is different from the original value of the n'th +argument. This can be used to free the de-toasted value of the n'th +argument, if it was actually de-toasted. Currently, doing this is not +necessary for the majority of functions because the core backend code +releases temporary space periodically, so that memory leaked in function +execution isn't a big problem. However, as of 7.1 memory leaks in +functions that are called by index searches will not be cleaned up until +end of transaction. Therefore, functions that are listed in pg_amop or +pg_amproc should be careful not to leak detoasted copies, and so these +functions do need to use PG_FREE_IF_COPY() for toastable inputs. + +A function should never try to re-TOAST its result value; it should just +deliver an untoasted result that's been palloc'd in the current memory +context. When and if the value is actually stored into a tuple, the +tuple toaster will decide whether toasting is needed. + + +Functions Accepting or Returning Sets +------------------------------------- + +If a function is marked in pg_proc as returning a set, then it is called +with fcinfo->resultinfo pointing to a node of type ReturnSetInfo. A +function that desires to return a set should raise an error "called in +context that does not accept a set result" if resultinfo is NULL or does +not point to a ReturnSetInfo node. + +There are currently two modes in which a function can return a set result: +value-per-call, or materialize. In value-per-call mode, the function returns +one value each time it is called, and finally reports "done" when it has no +more values to return. In materialize mode, the function's output set is +instantiated in a Tuplestore object; all the values are returned in one call. +Additional modes might be added in future. + +ReturnSetInfo contains a field "allowedModes" which is set (by the caller) +to a bitmask that's the OR of the modes the caller can support. The actual +mode used by the function is returned in another field "returnMode". For +backwards-compatibility reasons, returnMode is initialized to value-per-call +and need only be changed if the function wants to use a different mode. +The function should ereport() if it cannot use any of the modes the caller is +willing to support. + +Value-per-call mode works like this: ReturnSetInfo contains a field +"isDone", which should be set to one of these values: + + ExprSingleResult /* expression does not return a set */ + ExprMultipleResult /* this result is an element of a set */ + ExprEndResult /* there are no more elements in the set */ + +(the caller will initialize it to ExprSingleResult). If the function simply +returns a Datum without touching ReturnSetInfo, then the call is over and a +single-item set has been returned. To return a set, the function must set +isDone to ExprMultipleResult for each set element. After all elements have +been returned, the next call should set isDone to ExprEndResult and return a +null result. (Note it is possible to return an empty set by doing this on +the first call.) + +Value-per-call functions MUST NOT assume that they will be run to completion; +the executor might simply stop calling them, for example because of a LIMIT. +Therefore, it's unsafe to attempt to perform any resource cleanup in the +final call. It's usually not necessary to clean up memory, anyway. If it's +necessary to clean up other types of resources, such as file descriptors, +one can register a shutdown callback function in the ExprContext pointed to +by the ReturnSetInfo node. (But note that file descriptors are a limited +resource, so it's generally unwise to hold those open across calls; SRFs +that need file access are better written to do it in a single call using +Materialize mode.) + +Materialize mode works like this: the function creates a Tuplestore holding +the (possibly empty) result set, and returns it. There are no multiple calls. +The function must also return a TupleDesc that indicates the tuple structure. +The Tuplestore and TupleDesc should be created in the context +econtext->ecxt_per_query_memory (note this will *not* be the context the +function is called in). The function stores pointers to the Tuplestore and +TupleDesc into ReturnSetInfo, sets returnMode to indicate materialize mode, +and returns null. isDone is not used and should be left at ExprSingleResult. + +The Tuplestore must be created with randomAccess = true if +SFRM_Materialize_Random is set in allowedModes, but it can (and preferably +should) be created with randomAccess = false if not. Callers that can support +both ValuePerCall and Materialize mode will set SFRM_Materialize_Preferred, +or not, depending on which mode they prefer. + +If available, the expected tuple descriptor is passed in ReturnSetInfo; +in other contexts the expectedDesc field will be NULL. The function need +not pay attention to expectedDesc, but it may be useful in special cases. + +There is no support for functions accepting sets; instead, the function will +be called multiple times, once for each element of the input set. + + +Notes About Function Handlers +----------------------------- + +Handlers for classes of functions should find life much easier and +cleaner in this design. The OID of the called function is directly +reachable from the passed parameters; we don't need the global variable +fmgr_pl_finfo anymore. Also, by modifying fcinfo->flinfo->fn_extra, +the handler can cache lookup info to avoid repeat lookups when the same +function is invoked many times. (fn_extra can only be used as a hint, +since callers are not required to re-use an FmgrInfo struct. +But in performance-critical paths they normally will do so.) + +If the handler wants to allocate memory to hold fn_extra data, it should +NOT do so in CurrentMemoryContext, since the current context may well be +much shorter-lived than the context where the FmgrInfo is. Instead, +allocate the memory in context flinfo->fn_mcxt, or in a long-lived cache +context. fn_mcxt normally points at the context that was +CurrentMemoryContext at the time the FmgrInfo structure was created; +in any case it is required to be a context at least as long-lived as the +FmgrInfo itself. |