From b2c4071299e02ed96d48d3c8e776de2fab36f88c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 13 Sep 2004 20:10:13 +0000 Subject: [PATCH] Redesign query-snapshot timing so that volatile functions in READ COMMITTED mode see a fresh snapshot for each command in the function, rather than using the latest interactive command's snapshot. Also, suppress fresh snapshots as well as CommandCounterIncrement inside STABLE and IMMUTABLE functions, instead using the snapshot taken for the most closely nested regular query. (This behavior is only sane for read-only functions, so the patch also enforces that such functions contain only SELECT commands.) As per my proposal of 6-Sep-2004; I note that I floated essentially the same proposal on 19-Jun-2002, but that discussion tailed off without any action. Since 8.0 seems like the right place to be taking possibly nontrivial backwards compatibility hits, let's get it done now. --- contrib/tablefunc/tablefunc.c | 8 +- contrib/tsearch2/ts_stat.c | 2 +- doc/src/sgml/plpython.sgml | 4 +- doc/src/sgml/ref/create_function.sgml | 8 +- doc/src/sgml/release.sgml | 42 +- doc/src/sgml/spi.sgml | 416 ++++++++++++++---- doc/src/sgml/xfunc.sgml | 146 ++++++- src/backend/access/transam/xact.c | 12 +- src/backend/commands/cluster.c | 6 +- src/backend/commands/copy.c | 7 +- src/backend/commands/explain.c | 12 +- src/backend/commands/indexcmds.c | 6 +- src/backend/commands/portalcmds.c | 4 +- src/backend/commands/prepare.c | 8 +- src/backend/commands/vacuum.c | 10 +- src/backend/executor/execMain.c | 47 +- src/backend/executor/functions.c | 277 +++++++----- src/backend/executor/spi.c | 478 ++++++++++++--------- src/backend/tcop/fastpath.c | 7 +- src/backend/tcop/postgres.c | 11 +- src/backend/tcop/pquery.c | 93 +++- src/backend/tcop/utility.c | 93 +++- src/backend/utils/adt/ri_triggers.c | 58 ++- src/backend/utils/adt/ruleutils.c | 6 +- src/backend/utils/time/tqual.c | 138 +++--- src/include/executor/execdesc.h | 6 +- src/include/executor/executor.h | 5 +- src/include/executor/spi.h | 18 +- src/include/tcop/pquery.h | 11 +- src/include/tcop/utility.h | 6 +- src/include/utils/tqual.h | 17 +- src/pl/plperl/plperl.c | 153 +++++-- src/pl/plperl/spi_internal.c | 85 +--- src/pl/plperl/spi_internal.h | 1 + src/pl/plpgsql/src/pl_comp.c | 5 +- src/pl/plpgsql/src/pl_exec.c | 52 ++- src/pl/plpgsql/src/plpgsql.h | 5 +- src/pl/plpython/plpython.c | 50 ++- src/pl/tcl/pltcl.c | 110 +++-- src/test/regress/expected/transactions.out | 78 ++++ src/test/regress/sql/transactions.sql | 43 ++ 41 files changed, 1737 insertions(+), 807 deletions(-) diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 212be222cbd12..063773e91ba77 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -386,7 +386,7 @@ crosstab(PG_FUNCTION_ARGS) elog(ERROR, "crosstab: SPI_connect returned %d", ret); /* Retrieve the desired rows */ - ret = SPI_exec(sql, 0); + ret = SPI_execute(sql, true, 0); proc = SPI_processed; /* Check for qualifying tuples */ @@ -777,7 +777,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx) elog(ERROR, "load_categories_hash: SPI_connect returned %d", ret); /* Retrieve the category name rows */ - ret = SPI_exec(cats_sql, 0); + ret = SPI_execute(cats_sql, true, 0); num_categories = proc = SPI_processed; /* Check for qualifying tuples */ @@ -855,7 +855,7 @@ get_crosstab_tuplestore(char *sql, elog(ERROR, "get_crosstab_tuplestore: SPI_connect returned %d", ret); /* Now retrieve the crosstab source rows */ - ret = SPI_exec(sql, 0); + ret = SPI_execute(sql, true, 0); proc = SPI_processed; /* Check for qualifying tuples */ @@ -1376,7 +1376,7 @@ build_tuplestore_recursively(char *key_fld, } /* Retrieve the desired rows */ - ret = SPI_exec(sql->data, 0); + ret = SPI_execute(sql->data, true, 0); proc = SPI_processed; /* Check for qualifying tuples */ diff --git a/contrib/tsearch2/ts_stat.c b/contrib/tsearch2/ts_stat.c index 2e6a98197e31d..badf1d2b01ece 100644 --- a/contrib/tsearch2/ts_stat.c +++ b/contrib/tsearch2/ts_stat.c @@ -446,7 +446,7 @@ ts_stat_sql(text *txt, text *ws) /* internal error */ elog(ERROR, "SPI_prepare('%s') returns NULL", query); - if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL)) == NULL) + if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, false)) == NULL) /* internal error */ elog(ERROR, "SPI_cursor_open('%s') returns NULL", query); diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml index a19b4a3585dd0..6655219d3e68d 100644 --- a/doc/src/sgml/plpython.sgml +++ b/doc/src/sgml/plpython.sgml @@ -1,4 +1,4 @@ - + PL/Python - Python Procedural Language @@ -175,7 +175,7 @@ def __plpython_procedure_myfunc_23456(): row number and column name. It has these additional methods: nrows which returns the number of rows returned by the query, and status which is the - SPI_exec() return value. The result object + SPI_execute() return value. The result object can be modified. diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 2c43fe9b4600f..1a8f5e41d8e03 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ @@ -172,7 +172,7 @@ CREATE [ OR REPLACE ] FUNCTION name These attributes inform the system whether it is safe to replace multiple evaluations of the function with a single evaluation, for run-time optimization. At most one choice - should be specified. If none of these appear, + may be specified. If none of these appear, VOLATILE is the default assumption. @@ -206,6 +206,10 @@ CREATE [ OR REPLACE ] FUNCTION name to prevent calls from being optimized away; an example is setval(). + + + For additional details see . + diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index ddf93a04ff996..1d91953a0aa19 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ @@ -337,6 +337,26 @@ $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.295 2004/09/10 18:39:54 tgl Exp + + + In READ COMMITTED serialization mode, volatile functions + now see the results of concurrent transactions committed up to the + beginning of each statement within the function, rather than up to the + beginning of the interactive command that called the function. + + + + + + Functions declared STABLE or IMMUTABLE always + use the snapshot of the calling query, and therefore do not see the + effects of actions taken after the calling query starts, whether in + their own transaction or other transactions. Such a function must be + read-only, too, meaning that it cannot use any SQL commands other than + SELECT. + + + Non-deferred AFTER triggers are now fired immediately after completion @@ -1434,6 +1454,26 @@ $PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.295 2004/09/10 18:39:54 tgl Exp Server-Side Language Changes + + + In READ COMMITTED serialization mode, volatile functions + now see the results of concurrent transactions committed up to the + beginning of each statement within the function, rather than up to the + beginning of the interactive command that called the function. + + + + + + Functions declared STABLE or IMMUTABLE always + use the snapshot of the calling query, and therefore do not see the + effects of actions taken after the calling query starts, whether in + their own transaction or other transactions. Such a function must be + read-only, too, meaning that it cannot use any SQL commands other than + SELECT. + + + Non-deferred AFTER triggers are now fired immediately after completion diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 4018c2e3e1ba6..a5a832d2e73bd 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1,5 +1,5 @@ @@ -206,7 +206,7 @@ int SPI_finish(void) SPI_push - pushes SPI stack to allow recursive SPI calls + pushes SPI stack to allow recursive SPI usage SPI_push @@ -221,8 +221,24 @@ void SPI_push(void) Description - SPI_push pushes a new environment on to the - SPI call stack, allowing recursive calls to use a new environment. + SPI_push should be called before executing another + procedure that might itself wish to use SPI. + After SPI_push, SPI is no longer in a + connected state, and SPI function calls will be rejected unless + a fresh SPI_connect is done. This ensures a clean + separation between your procedure's SPI state and that of another procedure + you call. After the other procedure returns, call + SPI_pop to restore access to your own SPI state. + + + + Note that SPI_execute and related functions + automatically do the equivalent of SPI_push before + passing control back to the SQL execution engine, so it is not necessary + for you to worry about this when using those functions. + Only when you are directly calling arbitrary code that might contain + SPI_connect calls do you need to issue + SPI_push and SPI_pop. @@ -237,7 +253,7 @@ void SPI_push(void) SPI_pop - pops SPI stack to allow recursive SPI calls + pops SPI stack to return from recursive SPI usage SPI_pop @@ -253,7 +269,7 @@ void SPI_pop(void) SPI_pop pops the previous environment from the - SPI call stack. For use when returning from recursive SPI calls. + SPI call stack. See SPI_push. @@ -261,21 +277,21 @@ void SPI_pop(void) - + - SPI_exec + SPI_execute - SPI_exec + SPI_execute execute a command - SPI_exec + SPI_execute -int SPI_exec(const char * command, int count) +int SPI_execute(const char * command, bool read_only, int count) @@ -283,27 +299,65 @@ int SPI_exec(const char * command, int countDescription - SPI_exec executes the specified SQL command - for count rows. + SPI_execute executes the specified SQL command + for count rows. If read_only + is true, the command must be read-only, and execution overhead + is somewhat reduced. + + + + This function may only be called from a connected procedure. - This function should only be called from a connected procedure. If - count is zero then it executes the command + If count is zero then the command is executed for all rows that it applies to. If count is greater than 0, then the number of rows for which the command will be executed is restricted (much like a LIMIT clause). For example, -SPI_exec("INSERT INTO tab SELECT * FROM tab", 5); +SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5); will allow at most 5 rows to be inserted into the table. - You may pass multiple commands in one string, and the command may - be rewritten by rules. SPI_exec returns the - result for the command executed last. + You may pass multiple commands in one string, and the commands may + be rewritten by rules. SPI_execute returns the + result for the command executed last. The count + limit applies to each command separately, but it is not applied to + hidden commands generated by rules. + + + + When read_only is false, + SPI_execute increments the command + counter and computes a new snapshot before executing each + command in the string. The snapshot does not actually change if the + current transaction isolation level is SERIALIZABLE, but in + READ COMMITTED mode the snapshot update allows each command to + see the results of newly committed transactions from other sessions. + This is essential for consistent behavior when the commands are modifying + the database. + + + + When read_only is true, + SPI_execute does not update either the snapshot + or the command counter, and it allows only plain SELECT + commands to appear in the command string. The commands are executed + using the snapshot previously established for the surrounding query. + This execution mode is somewhat faster than the read/write mode due + to eliminating per-command overhead. It also allows genuinely + stable functions to be built: since successive executions + will all use the same snapshot, there will be no change in the results. + + + + It is generally unwise to mix read-only and read-write commands within + a single function using SPI; that could result in very confusing behavior, + since the read-only queries would not see the results of any database + updates done by the read-write queries. @@ -311,7 +365,7 @@ SPI_exec("INSERT INTO tab SELECT * FROM tab", 5); is returned in the global variable SPI_processed (unless the return value of the function is SPI_OK_UTILITY). If the return value of the - function is SPI_OK_SELECT then you may the use + function is SPI_OK_SELECT then you may use the global pointer SPITupleTable *SPI_tuptable to access the result rows. @@ -330,7 +384,7 @@ typedef struct } SPITupleTable; vals is an array of pointers to rows. (The number - of valid entries is given by SPI_processed). + of valid entries is given by SPI_processed.) tupdesc is a row descriptor which you may pass to SPI functions dealing with rows. tuptabcxt, alloced, and free are internal @@ -358,6 +412,15 @@ typedef struct + + bool read_only + + + true for read-only execution + + + + int count @@ -504,14 +567,15 @@ typedef struct Notes - The functions SPI_exec, - SPI_execp, and - SPI_prepare change both + The functions SPI_execute, + SPI_exec, + SPI_execute_plan, and + SPI_execp change both SPI_processed and SPI_tuptable (just the pointer, not the contents of the structure). Save these two global variables into local - procedure variables if you need to access the result of - SPI_exec or SPI_execp + procedure variables if you need to access the result table of + SPI_execute or a related function across later calls. @@ -519,6 +583,70 @@ typedef struct + + + SPI_exec + + + + SPI_exec + execute a read/write command + + + SPI_exec + + + +int SPI_exec(const char * command, int count) + + + + + Description + + + SPI_exec is the same as + SPI_execute, with the latter's + read_only parameter always taken as + false. + + + + + Arguments + + + + const char * command + + + string containing command to execute + + + + + + int count + + + maximum number of rows to process or return + + + + + + + + Return Value + + + See SPI_execute. + + + + + + SPI_prepare @@ -551,14 +679,14 @@ void * SPI_prepare(const char * command, int n may be advantageous to perform the planning only once. SPI_prepare converts a command string into an execution plan that can be executed repeatedly using - SPI_execp. + SPI_execute_plan. A prepared command can be generalized by writing parameters ($1, $2, etc.) in place of what would be constants in a normal command. The actual values of the parameters - are then specified when SPI_execp is called. + are then specified when SPI_execute_plan is called. This allows the prepared command to be used over a wider range of situations than would be possible without parameters. @@ -610,10 +738,10 @@ void * SPI_prepare(const char * command, int n Return Value - SPI_prepare returns non-null pointer to an - execution plan. On error, NULL will be returned. - In both cases, SPI_result will be set analogous - to the value returned by SPI_exec, except that + SPI_prepare returns a non-null pointer to an + execution plan. On error, NULL will be returned, + and SPI_result will be set to one of the same + error codes used by SPI_execute, except that it is set to SPI_ERROR_ARGUMENT if command is NULL, or if nargs is less than 0, or if nargs is @@ -642,7 +770,7 @@ void * SPI_prepare(const char * command, int n SPI_getargcount - returns the number of arguments needed when executing a plan + returns the number of arguments needed by a plan prepared by SPI_prepare @@ -659,7 +787,7 @@ int SPI_getargcount(void * plan) SPI_getargcount returns the number of arguments needed - when executing a plan prepared by SPI_prepare. + to execute a plan prepared by SPI_prepare. @@ -681,7 +809,7 @@ int SPI_getargcount(void * plan) Return Value - The expected argument count for the plan or + The expected argument count for the plan, or SPI_ERROR_ARGUMENT if the plan is NULL @@ -697,8 +825,8 @@ int SPI_getargcount(void * plan) SPI_getargtypeid - returns the expected typeid for the specified argument when - executing a plan prepared by SPI_prepare + returns the expected typeid for the specified argument of + a plan prepared by SPI_prepare SPI_getargtypeid @@ -714,7 +842,7 @@ Oid SPI_getargtypeid(void * plan, int argIndex SPI_getargtypeid returns the Oid representing the type - id for argument at argIndex in a plan prepared by + id for the argIndex'th argument of a plan prepared by SPI_prepare. First argument is at index zero. @@ -746,11 +874,11 @@ Oid SPI_getargtypeid(void * plan, int argIndex Return Value - The type id of the argument at the given index or - SPI_ERROR_ARGUMENT if the plan is + The type id of the argument at the given index, or + SPI_ERROR_ARGUMENT if the plan is NULL or argIndex is less than 0 or - not less than the number of arguments declared for the plan - + not less than the number of arguments declared for the + plan @@ -765,8 +893,8 @@ Oid SPI_getargtypeid(void * plan, int argIndex SPI_is_cursor_plan returns true if a plan - prepared by SPI_prepare can be passed - as an argument to SPI_cursor_open + prepared by SPI_prepare can be used with + SPI_cursor_open SPI_is_cursor_plan @@ -784,7 +912,7 @@ bool SPI_is_cursor_plan(void * plan) SPI_is_cursor_plan returns true if a plan prepared by SPI_prepare can be passed as an argument to SPI_cursor_open and - false if that is not the case. The criteria is that the + false if that is not the case. The criteria are that the plan represents one single command and that this command is a SELECT without an INTO clause. @@ -819,21 +947,22 @@ bool SPI_is_cursor_plan(void * plan) - + - SPI_execp + SPI_execute_plan - SPI_execp + SPI_execute_plan executes a plan prepared by SPI_prepare - SPI_execp + SPI_execute_plan -int SPI_execp(void * plan, Datum * values, const char * nulls, int count) +int SPI_execute_plan(void * plan, Datum * values, const char * nulls, + bool read_only, int count) @@ -841,9 +970,10 @@ int SPI_execp(void * plan, Datum * valuesDescription - SPI_execp executes a plan prepared by - SPI_prepare. tcount - has the same interpretation as in SPI_exec. + SPI_execute_plan executes a plan prepared by + SPI_prepare. read_only and + count have the same interpretation as in + SPI_execute. @@ -861,10 +991,11 @@ int SPI_execp(void * plan, Datum * values - Datum *values + Datum * values - actual parameter values + An array of actual parameter values. Must have same length as the + plan's number of arguments. @@ -873,7 +1004,8 @@ int SPI_execp(void * plan, Datum * valuesconst char * nulls - An array describing which parameters are null. + An array describing which parameters are null. Must have same length as + the plan's number of arguments. n indicates a null value (entry in values will be ignored); a space indicates a nonnull value (entry in values is valid). @@ -881,17 +1013,26 @@ int SPI_execp(void * plan, Datum * values If nulls is NULL then - SPI_execp assumes that no parameters are + SPI_execute_plan assumes that no parameters are null. + + bool read_only + + + true for read-only execution + + + + int count - number of row for which plan is to be executed + maximum number of rows to process or return @@ -902,8 +1043,8 @@ int SPI_execp(void * plan, Datum * valuesReturn Value - The return value is the same as for SPI_exec - or one of the following: + The return value is the same as for SPI_execute, + with the following additional possible error (negative) results: @@ -931,7 +1072,7 @@ int SPI_execp(void * plan, Datum * values SPI_processed and SPI_tuptable are set as in - SPI_exec if successful. + SPI_execute if successful. @@ -941,7 +1082,106 @@ int SPI_execp(void * plan, Datum * values If one of the objects (a table, function, etc.) referenced by the prepared plan is dropped during the session then the result of - SPI_execp for this plan will be unpredictable. + SPI_execute_plan for this plan will be unpredictable. + + + + + + + + + SPI_execp + + + + SPI_execp + executes a plan in read/write mode + + + SPI_execp + + + +int SPI_execp(void * plan, Datum * values, const char * nulls, int count) + + + + + Description + + + SPI_execp is the same as + SPI_execute_plan, with the latter's + read_only parameter always taken as + false. + + + + + Arguments + + + + void * plan + + + execution plan (returned by SPI_prepare) + + + + + + Datum * values + + + An array of actual parameter values. Must have same length as the + plan's number of arguments. + + + + + + const char * nulls + + + An array describing which parameters are null. Must have same length as + the plan's number of arguments. + n indicates a null value (entry in + values will be ignored); a space indicates a + nonnull value (entry in values is valid). + + + + If nulls is NULL then + SPI_execp assumes that no parameters are + null. + + + + + + int count + + + maximum number of rows to process or return + + + + + + + + Return Value + + + See SPI_execute_plan. + + + + SPI_processed and + SPI_tuptable are set as in + SPI_execute if successful. @@ -962,7 +1202,9 @@ int SPI_execp(void * plan, Datum * values -Portal SPI_cursor_open(const char * name, void * plan, Datum * values, const char * nulls) +Portal SPI_cursor_open(const char * name, void * plan, + Datum * values, const char * nulls, + bool read_only) @@ -972,7 +1214,9 @@ Portal SPI_cursor_open(const char * name, void * SPI_cursor_open sets up a cursor (internally, a portal) that will execute a plan prepared by - SPI_prepare. + SPI_prepare. The parameters have the same + meanings as the corresponding parameters to + SPI_execute_plan. @@ -1013,22 +1257,36 @@ Portal SPI_cursor_open(const char * name, void * Datum * values - actual parameter values + An array of actual parameter values. Must have same length as the + plan's number of arguments. - const char *nulls + const char * nulls - An array describing which parameters are null values. + An array describing which parameters are null. Must have same length as + the plan's number of arguments. n indicates a null value (entry in values will be ignored); a space indicates a - nonnull value (entry in values is valid). If - nulls is NULL then - SPI_cursor_open assumes that no parameters - are null. + nonnull value (entry in values is valid). + + + + If nulls is NULL then + SPI_cursor_open assumes that no parameters are + null. + + + + + + bool read_only + + + true for read-only execution @@ -1168,7 +1426,7 @@ void SPI_cursor_fetch(Portal portal, bool forw SPI_processed and SPI_tuptable are set as in - SPI_exec if successful. + SPI_execute if successful. @@ -1320,7 +1578,7 @@ void * SPI_saveplan(void * plan) your procedure in the current session. You may save the pointer returned in a local variable. Always check if this pointer is NULL or not either when preparing a plan or using - an already prepared plan in SPI_execp. + an already prepared plan in SPI_execute_plan. @@ -1374,7 +1632,7 @@ void * SPI_saveplan(void * plan) If one of the objects (a table, function, etc.) referenced by the prepared plan is dropped during the session then the results of - SPI_execp for this plan will be unpredictable. + SPI_execute_plan for this plan will be unpredictable. @@ -1386,7 +1644,7 @@ void * SPI_saveplan(void * plan) The functions described here provide an interface for extracting - information from result sets returned by SPI_exec and + information from result sets returned by SPI_execute and other SPI functions. @@ -2360,7 +2618,8 @@ HeapTuple SPI_modifytuple(Relation rel, HeapTuple const char * Nulls - which new values are null, if any (see SPI_execp for the format) + which new values are null, if any (see + SPI_execute_plan for the format) @@ -2466,7 +2725,8 @@ void SPI_freetuple(HeapTuple row) SPI_freetuptable - free a row set created by SPI_exec or a similar function + free a row set created by SPI_execute or a similar + function SPI_freetuptable @@ -2483,7 +2743,7 @@ void SPI_freetuptable(SPITupleTable * tuptable) SPI_freetuptable frees a row set created by a prior SPI command execution function, such as - SPI_exec. Therefore, this function is usually called + SPI_execute. Therefore, this function is usually called with the global variable SPI_tupletable as argument. diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 684da2a37499e..70a00ae032ac4 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1,5 +1,5 @@ @@ -2404,14 +2404,6 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray number of arguments, up to a finite maximum number. - - A function may also have the same name as an attribute. (Recall - that attribute(table) is equivalent to - table.attribute.) In the case that there is an - ambiguity between a function on a complex type and an attribute of - the complex type, the attribute will always be used. - - When creating a family of overloaded functions, one should be careful not to create ambiguities. For instance, given the @@ -2427,6 +2419,18 @@ CREATE FUNCTION test(smallint, double precision) RETURNS ... relies on this behavior. + + A function that takes a single argument of a composite type should + generally not have the same name as any attribute (field) of that type. + Recall that attribute(table) is considered equivalent + to table.attribute. In the case that there is an + ambiguity between a function on a composite type and an attribute of + the composite type, the attribute will always be used. It is possible + to override that choice by schema-qualifying the function name + (that is, schema.func(table)) but it's better to + avoid the problem by not choosing conflicting names. + + When overloading C-language functions, there is an additional constraint: The C name of each function in the family of @@ -2437,7 +2441,7 @@ CREATE FUNCTION test(smallint, double precision) RETURNS ... (usually the internal one). The alternative form of the AS clause for the SQL CREATE FUNCTION command decouples the SQL function name from - the function name in the C source code. E.g., + the function name in the C source code. For instance, CREATE FUNCTION test(int) RETURNS int AS 'filename', 'test_1arg' @@ -2450,6 +2454,128 @@ CREATE FUNCTION test(int, int) RETURNS int + + Function Volatility Categories + + + volatility + functions + + + + Every function has a volatility classification, with + the possibilities being VOLATILE, STABLE, or + IMMUTABLE. VOLATILE is the default if the + CREATE FUNCTION command does not specify a category. + The volatility category is a promise to the optimizer about the behavior + of the function: + + + + + A VOLATILE function can do anything, including modifying + the database. It can return different results on successive calls with + the same arguments. The optimizer makes no assumptions about the + behavior of such functions. A query using a volatile function will + re-evaluate the function at every row where its value is needed. + + + + + A STABLE function cannot modify the database and is + guaranteed to return the same results given the same arguments + for all calls within a single surrounding query. This category + allows the optimizer to optimize away multiple calls of the function + within a single query. In particular, it is safe to use an expression + containing such a function in an indexscan condition. (Since an + indexscan will evaluate the comparison value only once, not once at + each row, it is not valid to use a VOLATILE function in + an indexscan condition.) + + + + + An IMMUTABLE function cannot modify the database and is + guaranteed to return the same results given the same arguments forever. + This category allows the optimizer to pre-evaluate the function when + a query calls it with constant arguments. For example, a query like + SELECT ... WHERE x = 2 + 2 can be simplified on sight to + SELECT ... WHERE x = 4, because the function underlying + the integer addition operator is marked IMMUTABLE. + + + + + + + For best optimization results, you should label your functions with the + strictest volatility category that is valid for them. + + + + Any function with side-effects must be labeled + VOLATILE, so that calls to it cannot be optimized away. + Even a function with no side-effects needs to be labeled + VOLATILE if its value can change within a single query; + some examples are random(), currval(), + timeofday(). + + + + There is relatively little difference between STABLE and + IMMUTABLE categories when considering simple interactive + queries that are planned and immediately executed: it doesn't matter + a lot whether a function is executed once during planning or once during + query execution startup. But there is a big difference if the plan is + saved and reused later. Labeling a function IMMUTABLE when + it really isn't may allow it to be prematurely folded to a constant during + planning, resulting in a stale value being re-used during subsequent uses + of the plan. This is a hazard when using prepared statements or when + using function languages that cache plans (such as + PL/pgSQL). + + + + Because of the snapshotting behavior of MVCC (see ) + a function containing only SELECT commands can safely be + marked STABLE, even if it selects from tables that might be + undergoing modifications by concurrent queries. + PostgreSQL will execute a STABLE + function using the snapshot established for the calling query, and so it + will see a fixed view of the database throughout that query. + Also note + that the current_timestamp family of functions qualify + as stable, since their values do not change within a transaction. + + + + The same snapshotting behavior is used for SELECT commands + within IMMUTABLE functions. It is generally unwise to select + from database tables within an IMMUTABLE function at all, + since the immutability will be broken if the table contents ever change. + However, PostgreSQL does not enforce that you + do not do that. + + + + A common error is to label a function IMMUTABLE when its + results depend on a configuration parameter. For example, a function + that manipulates timestamps might well have results that depend on the + setting. For safety, such functions should + be labeled STABLE instead. + + + + + Before PostgreSQL release 8.0, the requirement + that STABLE and IMMUTABLE functions cannot modify + the database was not enforced by the system. Release 8.0 enforces it + by requiring SQL functions and procedural language functions of these + categories to contain no SQL commands other than SELECT. + + + +