aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/array_userfuncs.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-02-11 12:49:34 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2025-02-11 12:49:34 -0500
commitc366d2bdba7c3b9b2cca1429d4535866e231ca55 (patch)
tree114d1f6c13af036eed4c1a2b0198bf796ad82797 /src/backend/utils/adt/array_userfuncs.c
parent6c7251db0ce12a83dd03c840e7d0ff7516b27229 (diff)
downloadpostgresql-c366d2bdba7c3b9b2cca1429d4535866e231ca55.tar.gz
postgresql-c366d2bdba7c3b9b2cca1429d4535866e231ca55.zip
Allow extension functions to participate in in-place updates.
Commit 1dc5ebc90 allowed PL/pgSQL to perform in-place updates of expanded-object variables that are being updated with assignments like "x := f(x, ...)". However this was allowed only for a hard-wired list of functions f(), since we need to be sure that f() will not modify the variable if it fails. It was always envisioned that we should make that extensible, but at the time we didn't have a good way to do so. Since then we've invented the idea of "support functions" to allow attaching specialized optimization knowledge to functions, and that is a perfect mechanism for doing this. Hence, adjust PL/pgSQL to use a support function request instead of hard-wired logic to decide if in-place update is safe. Preserve the previous optimizations by creating support functions for the three functions that were previously hard-wired. Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru> Reviewed-by: Pavel Borisov <pashkin.elfe@gmail.com> Discussion: https://postgr.es/m/CACxu=vJaKFNsYxooSnW1wEgsAO5u_v1XYBacfVJ14wgJV_PYeg@mail.gmail.com
Diffstat (limited to 'src/backend/utils/adt/array_userfuncs.c')
-rw-r--r--src/backend/utils/adt/array_userfuncs.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 0b02fe37445..2aae2f8ed93 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -16,6 +16,7 @@
#include "common/int.h"
#include "common/pg_prng.h"
#include "libpq/pqformat.h"
+#include "nodes/supportnodes.h"
#include "port/pg_bitutils.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -167,6 +168,36 @@ array_append(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(result);
}
+/*
+ * array_append_support()
+ *
+ * Planner support function for array_append()
+ */
+Datum
+array_append_support(PG_FUNCTION_ARGS)
+{
+ Node *rawreq = (Node *) PG_GETARG_POINTER(0);
+ Node *ret = NULL;
+
+ if (IsA(rawreq, SupportRequestModifyInPlace))
+ {
+ /*
+ * We can optimize in-place appends if the function's array argument
+ * is the array being assigned to. We don't need to worry about array
+ * references within the other argument.
+ */
+ SupportRequestModifyInPlace *req = (SupportRequestModifyInPlace *) rawreq;
+ Param *arg = (Param *) linitial(req->args);
+
+ if (arg && IsA(arg, Param) &&
+ arg->paramkind == PARAM_EXTERN &&
+ arg->paramid == req->paramid)
+ ret = (Node *) arg;
+ }
+
+ PG_RETURN_POINTER(ret);
+}
+
/*-----------------------------------------------------------------------------
* array_prepend :
* push an element onto the front of a one-dimensional array
@@ -230,6 +261,36 @@ array_prepend(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(result);
}
+/*
+ * array_prepend_support()
+ *
+ * Planner support function for array_prepend()
+ */
+Datum
+array_prepend_support(PG_FUNCTION_ARGS)
+{
+ Node *rawreq = (Node *) PG_GETARG_POINTER(0);
+ Node *ret = NULL;
+
+ if (IsA(rawreq, SupportRequestModifyInPlace))
+ {
+ /*
+ * We can optimize in-place prepends if the function's array argument
+ * is the array being assigned to. We don't need to worry about array
+ * references within the other argument.
+ */
+ SupportRequestModifyInPlace *req = (SupportRequestModifyInPlace *) rawreq;
+ Param *arg = (Param *) lsecond(req->args);
+
+ if (arg && IsA(arg, Param) &&
+ arg->paramkind == PARAM_EXTERN &&
+ arg->paramid == req->paramid)
+ ret = (Node *) arg;
+ }
+
+ PG_RETURN_POINTER(ret);
+}
+
/*-----------------------------------------------------------------------------
* array_cat :
* concatenate two nD arrays to form an nD array, or