Dept. of second thoughts: supporting inlining of polymorphic SQL functions
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Jul 2003 19:07:02 +0000 (19:07 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Jul 2003 19:07:02 +0000 (19:07 +0000)
takes only a few more lines of code than preventing it, so might as well
support it.

src/backend/optimizer/util/clauses.c

index 3da79cc4957cdaafdf05ec361183dc57dc58422e..4ed18ee5cd0e6822ad57477e7d4190537c529f7f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.143 2003/07/01 00:04:37 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.144 2003/07/01 19:07:02 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -30,6 +30,7 @@
 #include "optimizer/var.h"
 #include "parser/analyze.h"
 #include "parser/parse_clause.h"
+#include "parser/parse_expr.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -1719,6 +1720,8 @@ inline_function(Oid funcid, Oid result_type, List *args,
 {
        Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
        char            result_typtype;
+       bool            polymorphic = false;
+       Oid                     argtypes[FUNC_MAX_ARGS];
        char       *src;
        Datum           tmp;
        bool            isNull;
@@ -1731,7 +1734,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
        int                *usecounts;
        List       *arg;
        int                     i;
-       int                     j;
 
        /*
         * Forget it if the function is not SQL-language or has other
@@ -1743,17 +1745,15 @@ inline_function(Oid funcid, Oid result_type, List *args,
                funcform->pronargs != length(args))
                return NULL;
 
-       /* Forget it if declared return type is not base or domain */
+       /* Forget it if declared return type is not base, domain, or polymorphic */
        result_typtype = get_typtype(funcform->prorettype);
        if (result_typtype != 'b' &&
                result_typtype != 'd')
-               return NULL;
-
-       /* Forget it if any declared argument type is polymorphic */
-       for (j = 0; j < funcform->pronargs; j++)
        {
-               if (funcform->proargtypes[j] == ANYARRAYOID ||
-                       funcform->proargtypes[j] == ANYELEMENTOID)
+               if (funcform->prorettype == ANYARRAYOID ||
+                       funcform->prorettype == ANYELEMENTOID)
+                       polymorphic = true;
+               else
                        return NULL;
        }
 
@@ -1765,6 +1765,18 @@ inline_function(Oid funcid, Oid result_type, List *args,
        if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK)
                return NULL;
 
+       /* Check for polymorphic arguments, and substitute actual arg types */
+       memcpy(argtypes, funcform->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
+       for (i = 0; i < funcform->pronargs; i++)
+       {
+               if (argtypes[i] == ANYARRAYOID ||
+                       argtypes[i] == ANYELEMENTOID)
+               {
+                       polymorphic = true;
+                       argtypes[i] = exprType((Node *) nth(i, args));
+               }
+       }
+
        /*
         * Make a temporary memory context, so that we don't leak all the
         * stuff that parsing might create.
@@ -1797,8 +1809,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
                goto fail;
 
        querytree_list = parse_analyze(lfirst(raw_parsetree_list),
-                                                                  funcform->proargtypes,
-                                                                  funcform->pronargs);
+                                                                  argtypes, funcform->pronargs);
 
        if (length(querytree_list) != 1)
                goto fail;
@@ -1829,6 +1840,18 @@ inline_function(Oid funcid, Oid result_type, List *args,
 
        newexpr = (Node *) ((TargetEntry *) lfirst(querytree->targetList))->expr;
 
+       /*
+        * If the function has any arguments declared as polymorphic types,
+        * then it wasn't type-checked at definition time; must do so now.
+        * (This will raise an error if wrong, but that's okay since the
+        * function would fail at runtime anyway.  Note we do not try this
+        * until we have verified that no rewriting was needed; that's probably
+        * not important, but let's be careful.)
+        */
+       if (polymorphic)
+               check_sql_fn_retval(result_type, get_typtype(result_type),
+                                                       querytree_list);
+
        /*
         * Additional validity checks on the expression.  It mustn't return a
         * set, and it mustn't be more volatile than the surrounding function