Generalize plpgsql's heuristic for importing expanded objects.
authorTom Lane <[email protected]>
Thu, 24 Oct 2024 17:28:22 +0000 (13:28 -0400)
committerTom Lane <[email protected]>
Thu, 24 Oct 2024 17:28:22 +0000 (13:28 -0400)
If a R/W expanded-object pointer is passed as a function parameter,
take ownership of the object, regardless of its type.  Previously
this happened only for expanded arrays, but that was a result of
sloppy thinking.  (If the plpgsql function did not end by returning
the object, the result would be to leak the object until the
surrounding memory context is cleaned up.  That's not awful,
since non-expanded values have always been managed that way,
but we can do better.)

Per discussion with Michel Pelletier.  There's a lot more to do
here to make plpgsql work efficiently with expanded objects that
aren't arrays, but this is an easy first step.

Discussion: https://postgr.es/m/CACxu=vJaKFNsYxooSnW1wEgsAO5u_v1XYBacfVJ14wgJV_PYeg@mail.gmail.com

src/pl/plpgsql/src/pl_exec.c

index ea9740e3f89b525d1f5ffb1d18500f21d31bfa3d..e69559b980eaa0771874bb9a602a80026e007273 100644 (file)
@@ -532,21 +532,22 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
                                      false);
 
                    /*
-                    * Force any array-valued parameter to be stored in
+                    * If it's a varlena type, check to see if we received a
+                    * R/W expanded-object pointer.  If so, we can commandeer
+                    * the object rather than having to copy it.  If passed a
+                    * R/O expanded pointer, just keep it as the value of the
+                    * variable for the moment.  (We can change it to R/W if
+                    * the variable gets modified, but that may very well
+                    * never happen.)
+                    *
+                    * Also, force any flat array value to be stored in
                     * expanded form in our local variable, in hopes of
                     * improving efficiency of uses of the variable.  (This is
                     * a hack, really: why only arrays? Need more thought
                     * about which cases are likely to win.  See also
                     * typisarray-specific heuristic in exec_assign_value.)
-                    *
-                    * Special cases: If passed a R/W expanded pointer, assume
-                    * we can commandeer the object rather than having to copy
-                    * it.  If passed a R/O expanded pointer, just keep it as
-                    * the value of the variable for the moment.  (We'll force
-                    * it to R/W if the variable gets modified, but that may
-                    * very well never happen.)
                     */
-                   if (!var->isnull && var->datatype->typisarray)
+                   if (!var->isnull && var->datatype->typlen == -1)
                    {
                        if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(var->value)))
                        {
@@ -561,7 +562,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
                        {
                            /* R/O pointer, keep it as-is until assigned to */
                        }
-                       else
+                       else if (var->datatype->typisarray)
                        {
                            /* flat array, so force to expanded form */
                            assign_simple_var(&estate, var,