From fce4ab7fecb402b80e25dc0957ce862cfed7edc5 Mon Sep 17 00:00:00 2001 From: Tatsuo Ishii Date: Thu, 30 Jul 2020 15:25:16 +0900 Subject: [PATCH 1/4] check writing function using volatility --- src/utils/pool_select_walker.c | 90 +++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/src/utils/pool_select_walker.c b/src/utils/pool_select_walker.c index c53cc4f8..3bb5c439 100644 --- a/src/utils/pool_select_walker.c +++ b/src/utils/pool_select_walker.c @@ -3,7 +3,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2019 PgPool Global Development Group + * Copyright (c) 2003-2020 PgPool Global Development Group * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby @@ -31,6 +31,15 @@ #include "rewrite/pool_timestamp.h" #include "protocol/pool_pg_utils.h" +/* + * Possible argument (property) values for function_volatile_property + */ +typedef enum { + FUNC_VOLATILE, + FUNC_STABLE, + FUNC_IMMUTABLE +} FUNC_VOLATILE_PROPERTY; + static bool function_call_walker(Node *node, void *context); static bool system_catalog_walker(Node *node, void *context); static bool is_system_catalog(char *table_name); @@ -43,6 +52,7 @@ static bool is_immutable_function(char *fname); static bool select_table_walker(Node *node, void *context); static bool non_immutable_function_call_walker(Node *node, void *context); static char *strip_quote(char *str); +static bool function_volatile_property(char *fname, FUNC_VOLATILE_PROPERTY property); /* * Return true if this SELECT has function calls *and* supposed to @@ -362,6 +372,21 @@ function_call_walker(Node *node, void *context) } } + /* + * If both white_function_list and black_function_list is empty, + * check volatile property of the function in the system catalog. + */ + if (pool_config->num_white_function_list == 0 && + pool_config->num_black_function_list == 0) + { + if (function_volatile_property(fname, FUNC_VOLATILE)) + { + ctx->has_function_call = true; + return false; + } + return raw_expression_tree_walker(node, function_call_walker, context); + } + /* * Check white list if any. */ @@ -1027,18 +1052,29 @@ non_immutable_function_call_walker(Node *node, void *context) */ static bool is_immutable_function(char *fname) +{ + return function_volatile_property(fname, FUNC_IMMUTABLE); +} + +/* + * Check volatile property of function specified by the name. + * If the function property is match with "property" argument, returns true. + * Note that "fname" can be schema qualified. + */ +static +bool function_volatile_property(char *fname, FUNC_VOLATILE_PROPERTY property) { /* - * Query to know if the function is IMMUTABLE + * Query to know if function's volatile property. */ -#define IS_STABLE_FUNCTION_QUERY "SELECT count(*) FROM pg_catalog.pg_proc AS p, pg_catalog.pg_namespace AS n WHERE p.proname %s '%s' AND n.oid = p.pronamespace AND n.nspname = '%s' AND p.provolatile = 'i'" +#define VOLATILE_FUNCTION_QUERY "/*FORMATTED*/ SELECT count(*) FROM pg_catalog.pg_proc AS p, pg_catalog.pg_namespace AS n WHERE p.proname = '%s' AND n.oid = p.pronamespace AND n.nspname %s '%s' AND p.provolatile = '%c'" bool result; char query[1024]; char *rawstring = NULL; - char *key_str = NULL; List *names = NIL; POOL_CONNECTION_POOL *backend; static POOL_RELCACHE *relcache; + char prop_volatile; /* We need a modifiable copy of the input string. */ rawstring = pstrdup(fname); @@ -1056,33 +1092,49 @@ is_immutable_function(char *fname) return false; } + /* + * Get volatile property character. + */ + switch (property) + { + case FUNC_STABLE: + prop_volatile = 's'; + break; + + case FUNC_IMMUTABLE: + prop_volatile = 'i'; + break; + + default: + prop_volatile = 'v'; + break; + } + /* with schema qualification */ if(list_length(names) == 2) { - key_str = fname; if(!relcache) { - snprintf(query, sizeof(query), IS_STABLE_FUNCTION_QUERY, - "=", (char *) lsecond(names), (char *) linitial(names)); + snprintf(query, sizeof(query), VOLATILE_FUNCTION_QUERY, (char *) llast(names), + "=", (char *) linitial(names), prop_volatile); } else { - snprintf(relcache->sql, sizeof(relcache->sql), IS_STABLE_FUNCTION_QUERY, - "=", (char *) lsecond(names), (char *) linitial(names)); + snprintf(relcache->sql, sizeof(relcache->sql), VOLATILE_FUNCTION_QUERY, (char *) llast(names), + "=", (char *) linitial(names), prop_volatile); } } else { - key_str = (char *) llast(names); if(!relcache) { - snprintf(query, sizeof(query), IS_STABLE_FUNCTION_QUERY, - "~", ".*", (char *) llast(names)); + snprintf(query, sizeof(query), VOLATILE_FUNCTION_QUERY, (char *) llast(names), + "~", ".*", prop_volatile); } else { - snprintf(relcache->sql, sizeof(relcache->sql), IS_STABLE_FUNCTION_QUERY, - "~", ".*", (char *) llast(names)); + snprintf(relcache->sql, sizeof(relcache->sql), VOLATILE_FUNCTION_QUERY, (char *) llast(names), + "~", ".*", prop_volatile); } } @@ -1099,22 +1151,22 @@ is_immutable_function(char *fname) list_free(names); ereport(WARNING, - (errmsg("unable to create relcache, while checking if the function is immutable"))); + (errmsg("unable to create relcache, while checking the function volatile property"))); return false; } ereport(DEBUG1, - (errmsg("checking if the function is IMMUTABLE"), + (errmsg("checking the function volatile property"), errdetail("relcache created"))); } - result = (pool_search_relcache(relcache, backend, key_str) == 0) ? 0 : 1; + result = (pool_search_relcache(relcache, backend, fname) == 0) ? 0 : 1; pfree(rawstring); list_free(names); ereport(DEBUG1, - (errmsg("checking if the function is IMMUTABLE"), - errdetail("search result = %d", result))); + (errmsg("checking the function volatile property"), + errdetail("search result = %d (%c)", result, prop_volatile))); return result; } -- 2.17.1