In the case of purely mathematical circumstances, it is my understanding that the premise of a function f
calling a volatile
function g
would indicate that f
is inherently volatile
as well. That's because functions in mathematics are equivalencies designed to reduce the work of explaining systems and the one (function or expression) can be substituted for the other, often as syntactic sugar moreso than anything else.
However, my answer isn't specifically from the context of postgres, as I don't normally work in PG. It may be reasonable in PG that the f
function would be stable
even while the g
function were volatile
.
I would encourage every developer to examine their code as being basically just mathematics exposed, and so therefore would encourage you to consider the code here as volatile
.
As you were hinted in comments above, your RBAR approach might be very inefficient. Consider the suggestions there.
Also, I am not going into details about the different approaches of UPSERT
, as it is a very broad topic, especially when one wants to do concurrency-safe. PostgreSQL 9.5 helps a lot in this regard.
So, to your actual question: it is not directly possible writing PL/pgSQL 'commands' interspersed with bash, but the task is definitely solvable.
For this, you need to define a function like this (left out the complexity to show my point more concisely):
CREATE OR REPLACE FUNCTION dynamic_upsert(
table_to_upsert name,
key_column name,
value_column name,
key integer,
value text
)
RETURNS void
LANGUAGE plpgsql
AS $BODY$
BEGIN
...
EXECUTE $$ UPDATE $$ || quote_ident(table_to_upsert) ||
$$ SET $$ || quote_ident(value_column) || $$ = $2
WHERE $$ || quote_ident(key_column) || $$ = $1 $$
USING key, value;
...
END;
$BODY$;
Please note that this is fully dynamic in that you can choose any table, match against any column of it and modify any (other) column. The type of the key (integer
) and the value (text
) are fixed, though.
Now you can call this from a shell script like
psql -h $DBHOST -U $DBUSER -d $DBNAME \
-c "SELECT dynamic_upsert($TABLE, $KEY_COL, $VAL_COL, $key, $value)"
If you are still RBARing, this will produce an additional overhead of connecting to the database for every single change, so be patient (or set up a connection pool).
Notes:
- using concatenation, one has to be absolutely sure to quote the object names properly. This is here done using
quote_ident()
, which is the way to go if you are concatenating the dynamic statement. In newer versions (from 9.1), one would use the format()
function to avoid the mess:
EXECUTE format($$ UPDATE %I SET %I = $2 WHERE %I = $1$$,
table_to_upsert, value_column, key_column)
USING key, value;
- here I am using dollar quoting when building the dynamic query. This allows me to use 'normal' syntax, as opposed to multiplicating single quotes, for example (not present in this example). This way most editors will highlight the statements nicely.
Best Answer
I checked the documentation again, and the answer to my second question is, yes you can alter it using the
alter function
query.Also, I see that checking for function volatility has been asked and answered before.
https://stackoverflow.com/questions/54452415/how-to-check-whether-a-function-is-immutable