LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 754 881 85.6 %
Date: 2025-12-07 04:17:18 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * functioncmds.c
       4             :  *
       5             :  *    Routines for CREATE and DROP FUNCTION commands and CREATE and DROP
       6             :  *    CAST commands.
       7             :  *
       8             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       9             :  * Portions Copyright (c) 1994, Regents of the University of California
      10             :  *
      11             :  *
      12             :  * IDENTIFICATION
      13             :  *    src/backend/commands/functioncmds.c
      14             :  *
      15             :  * DESCRIPTION
      16             :  *    These routines take the parse tree and pick out the
      17             :  *    appropriate arguments/flags, and pass the results to the
      18             :  *    corresponding "FooCreate" routines (in src/backend/catalog) that do
      19             :  *    the actual catalog-munging.  These routines also verify permission
      20             :  *    of the user to execute the command.
      21             :  *
      22             :  * NOTES
      23             :  *    These things must be defined and committed in the following order:
      24             :  *      "create function":
      25             :  *              input/output, recv/send procedures
      26             :  *      "create type":
      27             :  *              type
      28             :  *      "create operator":
      29             :  *              operators
      30             :  *
      31             :  *-------------------------------------------------------------------------
      32             :  */
      33             : #include "postgres.h"
      34             : 
      35             : #include "access/htup_details.h"
      36             : #include "access/table.h"
      37             : #include "catalog/catalog.h"
      38             : #include "catalog/dependency.h"
      39             : #include "catalog/indexing.h"
      40             : #include "catalog/objectaccess.h"
      41             : #include "catalog/pg_aggregate.h"
      42             : #include "catalog/pg_cast.h"
      43             : #include "catalog/pg_language.h"
      44             : #include "catalog/pg_namespace.h"
      45             : #include "catalog/pg_proc.h"
      46             : #include "catalog/pg_transform.h"
      47             : #include "catalog/pg_type.h"
      48             : #include "commands/defrem.h"
      49             : #include "commands/extension.h"
      50             : #include "commands/proclang.h"
      51             : #include "executor/executor.h"
      52             : #include "executor/functions.h"
      53             : #include "funcapi.h"
      54             : #include "miscadmin.h"
      55             : #include "nodes/nodeFuncs.h"
      56             : #include "optimizer/optimizer.h"
      57             : #include "parser/analyze.h"
      58             : #include "parser/parse_coerce.h"
      59             : #include "parser/parse_collate.h"
      60             : #include "parser/parse_expr.h"
      61             : #include "parser/parse_func.h"
      62             : #include "parser/parse_type.h"
      63             : #include "pgstat.h"
      64             : #include "tcop/pquery.h"
      65             : #include "tcop/utility.h"
      66             : #include "utils/acl.h"
      67             : #include "utils/builtins.h"
      68             : #include "utils/guc.h"
      69             : #include "utils/lsyscache.h"
      70             : #include "utils/rel.h"
      71             : #include "utils/snapmgr.h"
      72             : #include "utils/syscache.h"
      73             : #include "utils/typcache.h"
      74             : 
      75             : /*
      76             :  *   Examine the RETURNS clause of the CREATE FUNCTION statement
      77             :  *   and return information about it as *prorettype_p and *returnsSet_p.
      78             :  *
      79             :  * This is more complex than the average typename lookup because we want to
      80             :  * allow a shell type to be used, or even created if the specified return type
      81             :  * doesn't exist yet.  (Without this, there's no way to define the I/O procs
      82             :  * for a new type.)  But SQL function creation won't cope, so error out if
      83             :  * the target language is SQL.  (We do this here, not in the SQL-function
      84             :  * validator, so as not to produce a NOTICE and then an ERROR for the same
      85             :  * condition.)
      86             :  */
      87             : static void
      88       25266 : compute_return_type(TypeName *returnType, Oid languageOid,
      89             :                     Oid *prorettype_p, bool *returnsSet_p)
      90             : {
      91             :     Oid         rettype;
      92             :     Type        typtup;
      93             :     AclResult   aclresult;
      94             : 
      95       25266 :     typtup = LookupTypeName(NULL, returnType, NULL, false);
      96             : 
      97       25266 :     if (typtup)
      98             :     {
      99       25168 :         if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
     100             :         {
     101         156 :             if (languageOid == SQLlanguageId)
     102           0 :                 ereport(ERROR,
     103             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     104             :                          errmsg("SQL function cannot return shell type %s",
     105             :                                 TypeNameToString(returnType))));
     106             :             else
     107         156 :                 ereport(NOTICE,
     108             :                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     109             :                          errmsg("return type %s is only a shell",
     110             :                                 TypeNameToString(returnType))));
     111             :         }
     112       25168 :         rettype = typeTypeId(typtup);
     113       25168 :         ReleaseSysCache(typtup);
     114             :     }
     115             :     else
     116             :     {
     117          98 :         char       *typnam = TypeNameToString(returnType);
     118             :         Oid         namespaceId;
     119             :         char       *typname;
     120             :         ObjectAddress address;
     121             : 
     122             :         /*
     123             :          * Only C-coded functions can be I/O functions.  We enforce this
     124             :          * restriction here mainly to prevent littering the catalogs with
     125             :          * shell types due to simple typos in user-defined function
     126             :          * definitions.
     127             :          */
     128          98 :         if (languageOid != INTERNALlanguageId &&
     129             :             languageOid != ClanguageId)
     130           0 :             ereport(ERROR,
     131             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     132             :                      errmsg("type \"%s\" does not exist", typnam)));
     133             : 
     134             :         /* Reject if there's typmod decoration, too */
     135          98 :         if (returnType->typmods != NIL)
     136           0 :             ereport(ERROR,
     137             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     138             :                      errmsg("type modifier cannot be specified for shell type \"%s\"",
     139             :                             typnam)));
     140             : 
     141             :         /* Otherwise, go ahead and make a shell type */
     142          98 :         ereport(NOTICE,
     143             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     144             :                  errmsg("type \"%s\" is not yet defined", typnam),
     145             :                  errdetail("Creating a shell type definition.")));
     146          98 :         namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
     147             :                                                         &typname);
     148          98 :         aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(),
     149             :                                     ACL_CREATE);
     150          98 :         if (aclresult != ACLCHECK_OK)
     151           0 :             aclcheck_error(aclresult, OBJECT_SCHEMA,
     152           0 :                            get_namespace_name(namespaceId));
     153          98 :         address = TypeShellMake(typname, namespaceId, GetUserId());
     154          98 :         rettype = address.objectId;
     155             :         Assert(OidIsValid(rettype));
     156             :         /* Ensure the new shell type is visible to ProcedureCreate */
     157          98 :         CommandCounterIncrement();
     158             :     }
     159             : 
     160       25266 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     161       25266 :     if (aclresult != ACLCHECK_OK)
     162           6 :         aclcheck_error_type(aclresult, rettype);
     163             : 
     164       25260 :     *prorettype_p = rettype;
     165       25260 :     *returnsSet_p = returnType->setof;
     166       25260 : }
     167             : 
     168             : /*
     169             :  * Interpret the function parameter list of a CREATE FUNCTION,
     170             :  * CREATE PROCEDURE, or CREATE AGGREGATE statement.
     171             :  *
     172             :  * Input parameters:
     173             :  * parameters: list of FunctionParameter structs
     174             :  * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE)
     175             :  * objtype: identifies type of object being created
     176             :  *
     177             :  * Results are stored into output parameters.  parameterTypes must always
     178             :  * be created, but the other arrays/lists can be NULL pointers if not needed.
     179             :  * variadicArgType is set to the variadic array type if there's a VARIADIC
     180             :  * parameter (there can be only one); or to InvalidOid if not.
     181             :  * requiredResultType is set to InvalidOid if there are no OUT parameters,
     182             :  * else it is set to the OID of the implied result type.
     183             :  */
     184             : void
     185       26696 : interpret_function_parameter_list(ParseState *pstate,
     186             :                                   List *parameters,
     187             :                                   Oid languageOid,
     188             :                                   ObjectType objtype,
     189             :                                   oidvector **parameterTypes,
     190             :                                   List **parameterTypes_list,
     191             :                                   ArrayType **allParameterTypes,
     192             :                                   ArrayType **parameterModes,
     193             :                                   ArrayType **parameterNames,
     194             :                                   List **inParameterNames_list,
     195             :                                   List **parameterDefaults,
     196             :                                   Oid *variadicArgType,
     197             :                                   Oid *requiredResultType)
     198             : {
     199       26696 :     int         parameterCount = list_length(parameters);
     200             :     Oid        *inTypes;
     201       26696 :     int         inCount = 0;
     202             :     Datum      *allTypes;
     203             :     Datum      *paramModes;
     204             :     Datum      *paramNames;
     205       26696 :     int         outCount = 0;
     206       26696 :     int         varCount = 0;
     207       26696 :     bool        have_names = false;
     208       26696 :     bool        have_defaults = false;
     209             :     ListCell   *x;
     210             :     int         i;
     211             : 
     212       26696 :     *variadicArgType = InvalidOid;  /* default result */
     213       26696 :     *requiredResultType = InvalidOid;   /* default result */
     214             : 
     215       26696 :     inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
     216       26696 :     allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
     217       26696 :     paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
     218       26696 :     paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
     219       26696 :     *parameterDefaults = NIL;
     220             : 
     221             :     /* Scan the list and extract data into work arrays */
     222       26696 :     i = 0;
     223       85560 :     foreach(x, parameters)
     224             :     {
     225       58924 :         FunctionParameter *fp = (FunctionParameter *) lfirst(x);
     226       58924 :         TypeName   *t = fp->argType;
     227       58924 :         FunctionParameterMode fpmode = fp->mode;
     228       58924 :         bool        isinput = false;
     229             :         Oid         toid;
     230             :         Type        typtup;
     231             :         AclResult   aclresult;
     232             : 
     233             :         /* For our purposes here, a defaulted mode spec is identical to IN */
     234       58924 :         if (fpmode == FUNC_PARAM_DEFAULT)
     235       40342 :             fpmode = FUNC_PARAM_IN;
     236             : 
     237       58924 :         typtup = LookupTypeName(pstate, t, NULL, false);
     238       58924 :         if (typtup)
     239             :         {
     240       58924 :             if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
     241             :             {
     242             :                 /* As above, hard error if language is SQL */
     243         248 :                 if (languageOid == SQLlanguageId)
     244           0 :                     ereport(ERROR,
     245             :                             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     246             :                              errmsg("SQL function cannot accept shell type %s",
     247             :                                     TypeNameToString(t)),
     248             :                              parser_errposition(pstate, t->location)));
     249             :                 /* We don't allow creating aggregates on shell types either */
     250         248 :                 else if (objtype == OBJECT_AGGREGATE)
     251           0 :                     ereport(ERROR,
     252             :                             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     253             :                              errmsg("aggregate cannot accept shell type %s",
     254             :                                     TypeNameToString(t)),
     255             :                              parser_errposition(pstate, t->location)));
     256             :                 else
     257         248 :                     ereport(NOTICE,
     258             :                             (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     259             :                              errmsg("argument type %s is only a shell",
     260             :                                     TypeNameToString(t)),
     261             :                              parser_errposition(pstate, t->location)));
     262             :             }
     263       58924 :             toid = typeTypeId(typtup);
     264       58924 :             ReleaseSysCache(typtup);
     265             :         }
     266             :         else
     267             :         {
     268           0 :             ereport(ERROR,
     269             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     270             :                      errmsg("type %s does not exist",
     271             :                             TypeNameToString(t)),
     272             :                      parser_errposition(pstate, t->location)));
     273             :             toid = InvalidOid;  /* keep compiler quiet */
     274             :         }
     275             : 
     276       58924 :         aclresult = object_aclcheck(TypeRelationId, toid, GetUserId(), ACL_USAGE);
     277       58924 :         if (aclresult != ACLCHECK_OK)
     278          12 :             aclcheck_error_type(aclresult, toid);
     279             : 
     280       58912 :         if (t->setof)
     281             :         {
     282           0 :             if (objtype == OBJECT_AGGREGATE)
     283           0 :                 ereport(ERROR,
     284             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     285             :                          errmsg("aggregates cannot accept set arguments"),
     286             :                          parser_errposition(pstate, fp->location)));
     287           0 :             else if (objtype == OBJECT_PROCEDURE)
     288           0 :                 ereport(ERROR,
     289             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     290             :                          errmsg("procedures cannot accept set arguments"),
     291             :                          parser_errposition(pstate, fp->location)));
     292             :             else
     293           0 :                 ereport(ERROR,
     294             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     295             :                          errmsg("functions cannot accept set arguments"),
     296             :                          parser_errposition(pstate, fp->location)));
     297             :         }
     298             : 
     299             :         /* handle input parameters */
     300       58912 :         if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
     301             :         {
     302             :             /* other input parameters can't follow a VARIADIC parameter */
     303       45484 :             if (varCount > 0)
     304           0 :                 ereport(ERROR,
     305             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     306             :                          errmsg("VARIADIC parameter must be the last input parameter"),
     307             :                          parser_errposition(pstate, fp->location)));
     308       45484 :             inTypes[inCount++] = toid;
     309       45484 :             isinput = true;
     310       45484 :             if (parameterTypes_list)
     311       44956 :                 *parameterTypes_list = lappend_oid(*parameterTypes_list, toid);
     312             :         }
     313             : 
     314             :         /* handle output parameters */
     315       58912 :         if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
     316             :         {
     317       13610 :             if (objtype == OBJECT_PROCEDURE)
     318             :             {
     319             :                 /*
     320             :                  * We disallow OUT-after-VARIADIC only for procedures.  While
     321             :                  * such a case causes no confusion in ordinary function calls,
     322             :                  * it would cause confusion in a CALL statement.
     323             :                  */
     324         190 :                 if (varCount > 0)
     325           6 :                     ereport(ERROR,
     326             :                             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     327             :                              errmsg("VARIADIC parameter must be the last parameter"),
     328             :                              parser_errposition(pstate, fp->location)));
     329             :                 /* Procedures with output parameters always return RECORD */
     330         184 :                 *requiredResultType = RECORDOID;
     331             :             }
     332       13420 :             else if (outCount == 0) /* save first output param's type */
     333        2540 :                 *requiredResultType = toid;
     334       13604 :             outCount++;
     335             :         }
     336             : 
     337       58906 :         if (fpmode == FUNC_PARAM_VARIADIC)
     338             :         {
     339         506 :             *variadicArgType = toid;
     340         506 :             varCount++;
     341             :             /* validate variadic parameter type */
     342         506 :             switch (toid)
     343             :             {
     344          70 :                 case ANYARRAYOID:
     345             :                 case ANYCOMPATIBLEARRAYOID:
     346             :                 case ANYOID:
     347             :                     /* okay */
     348          70 :                     break;
     349         436 :                 default:
     350         436 :                     if (!OidIsValid(get_element_type(toid)))
     351           0 :                         ereport(ERROR,
     352             :                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     353             :                                  errmsg("VARIADIC parameter must be an array"),
     354             :                                  parser_errposition(pstate, fp->location)));
     355         436 :                     break;
     356             :             }
     357             :         }
     358             : 
     359       58906 :         allTypes[i] = ObjectIdGetDatum(toid);
     360             : 
     361       58906 :         paramModes[i] = CharGetDatum(fpmode);
     362             : 
     363       58906 :         if (fp->name && fp->name[0])
     364             :         {
     365             :             ListCell   *px;
     366             : 
     367             :             /*
     368             :              * As of Postgres 9.0 we disallow using the same name for two
     369             :              * input or two output function parameters.  Depending on the
     370             :              * function's language, conflicting input and output names might
     371             :              * be bad too, but we leave it to the PL to complain if so.
     372             :              */
     373      178686 :             foreach(px, parameters)
     374             :             {
     375      178686 :                 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
     376             :                 FunctionParameterMode prevfpmode;
     377             : 
     378      178686 :                 if (prevfp == fp)
     379       33726 :                     break;
     380             :                 /* as above, default mode is IN */
     381      144960 :                 prevfpmode = prevfp->mode;
     382      144960 :                 if (prevfpmode == FUNC_PARAM_DEFAULT)
     383       21614 :                     prevfpmode = FUNC_PARAM_IN;
     384             :                 /* pure in doesn't conflict with pure out */
     385      144960 :                 if ((fpmode == FUNC_PARAM_IN ||
     386       22256 :                      fpmode == FUNC_PARAM_VARIADIC) &&
     387       22198 :                     (prevfpmode == FUNC_PARAM_OUT ||
     388             :                      prevfpmode == FUNC_PARAM_TABLE))
     389          58 :                     continue;
     390      144902 :                 if ((prevfpmode == FUNC_PARAM_IN ||
     391       43714 :                      prevfpmode == FUNC_PARAM_VARIADIC) &&
     392       22688 :                     (fpmode == FUNC_PARAM_OUT ||
     393             :                      fpmode == FUNC_PARAM_TABLE))
     394       21472 :                     continue;
     395      123430 :                 if (prevfp->name && prevfp->name[0] &&
     396      123392 :                     strcmp(prevfp->name, fp->name) == 0)
     397          24 :                     ereport(ERROR,
     398             :                             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     399             :                              errmsg("parameter name \"%s\" used more than once",
     400             :                                     fp->name),
     401             :                              parser_errposition(pstate, fp->location)));
     402             :             }
     403             : 
     404       33726 :             paramNames[i] = CStringGetTextDatum(fp->name);
     405       33726 :             have_names = true;
     406             :         }
     407             : 
     408       58882 :         if (inParameterNames_list)
     409       58354 :             *inParameterNames_list = lappend(*inParameterNames_list, makeString(fp->name ? fp->name : pstrdup("")));
     410             : 
     411       58882 :         if (fp->defexpr)
     412             :         {
     413             :             Node       *def;
     414             : 
     415        6582 :             if (!isinput)
     416           6 :                 ereport(ERROR,
     417             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     418             :                          errmsg("only input parameters can have default values"),
     419             :                          parser_errposition(pstate, fp->location)));
     420             : 
     421        6576 :             def = transformExpr(pstate, fp->defexpr,
     422             :                                 EXPR_KIND_FUNCTION_DEFAULT);
     423        6576 :             def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
     424        6576 :             assign_expr_collations(pstate, def);
     425             : 
     426             :             /*
     427             :              * Make sure no variables are referred to (this is probably dead
     428             :              * code now that add_missing_from is history).
     429             :              */
     430       13152 :             if (pstate->p_rtable != NIL ||
     431        6576 :                 contain_var_clause(def))
     432           0 :                 ereport(ERROR,
     433             :                         (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
     434             :                          errmsg("cannot use table references in parameter default value"),
     435             :                          parser_errposition(pstate, fp->location)));
     436             : 
     437             :             /*
     438             :              * transformExpr() should have already rejected subqueries,
     439             :              * aggregates, and window functions, based on the EXPR_KIND_ for a
     440             :              * default expression.
     441             :              *
     442             :              * It can't return a set either --- but coerce_to_specific_type
     443             :              * already checked that for us.
     444             :              *
     445             :              * Note: the point of these restrictions is to ensure that an
     446             :              * expression that, on its face, hasn't got subplans, aggregates,
     447             :              * etc cannot suddenly have them after function default arguments
     448             :              * are inserted.
     449             :              */
     450             : 
     451        6576 :             *parameterDefaults = lappend(*parameterDefaults, def);
     452        6576 :             have_defaults = true;
     453             :         }
     454             :         else
     455             :         {
     456       52300 :             if (isinput && have_defaults)
     457           6 :                 ereport(ERROR,
     458             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     459             :                          errmsg("input parameters after one with a default value must also have defaults"),
     460             :                          parser_errposition(pstate, fp->location)));
     461             : 
     462             :             /*
     463             :              * For procedures, we also can't allow OUT parameters after one
     464             :              * with a default, because the same sort of confusion arises in a
     465             :              * CALL statement.
     466             :              */
     467       52294 :             if (objtype == OBJECT_PROCEDURE && have_defaults)
     468           6 :                 ereport(ERROR,
     469             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     470             :                          errmsg("procedure OUT parameters cannot appear after one with a default value"),
     471             :                          parser_errposition(pstate, fp->location)));
     472             :         }
     473             : 
     474       58864 :         i++;
     475             :     }
     476             : 
     477             :     /* Now construct the proper outputs as needed */
     478       26636 :     *parameterTypes = buildoidvector(inTypes, inCount);
     479             : 
     480       26636 :     if (outCount > 0 || varCount > 0)
     481             :     {
     482        2738 :         *allParameterTypes = construct_array_builtin(allTypes, parameterCount, OIDOID);
     483        2738 :         *parameterModes = construct_array_builtin(paramModes, parameterCount, CHAROID);
     484        2738 :         if (outCount > 1)
     485        2394 :             *requiredResultType = RECORDOID;
     486             :         /* otherwise we set requiredResultType correctly above */
     487             :     }
     488             :     else
     489             :     {
     490       23898 :         *allParameterTypes = NULL;
     491       23898 :         *parameterModes = NULL;
     492             :     }
     493             : 
     494       26636 :     if (have_names)
     495             :     {
     496       42930 :         for (i = 0; i < parameterCount; i++)
     497             :         {
     498       33938 :             if (paramNames[i] == PointerGetDatum(NULL))
     499         266 :                 paramNames[i] = CStringGetTextDatum("");
     500             :         }
     501        8992 :         *parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
     502             :     }
     503             :     else
     504       17644 :         *parameterNames = NULL;
     505       26636 : }
     506             : 
     507             : 
     508             : /*
     509             :  * Recognize one of the options that can be passed to both CREATE
     510             :  * FUNCTION and ALTER FUNCTION and return it via one of the out
     511             :  * parameters. Returns true if the passed option was recognized. If
     512             :  * the out parameter we were going to assign to points to non-NULL,
     513             :  * raise a duplicate-clause error.  (We don't try to detect duplicate
     514             :  * SET parameters though --- if you're redundant, the last one wins.)
     515             :  */
     516             : static bool
     517       49970 : compute_common_attribute(ParseState *pstate,
     518             :                          bool is_procedure,
     519             :                          DefElem *defel,
     520             :                          DefElem **volatility_item,
     521             :                          DefElem **strict_item,
     522             :                          DefElem **security_item,
     523             :                          DefElem **leakproof_item,
     524             :                          List **set_items,
     525             :                          DefElem **cost_item,
     526             :                          DefElem **rows_item,
     527             :                          DefElem **support_item,
     528             :                          DefElem **parallel_item)
     529             : {
     530       49970 :     if (strcmp(defel->defname, "volatility") == 0)
     531             :     {
     532       14592 :         if (is_procedure)
     533           0 :             goto procedure_error;
     534       14592 :         if (*volatility_item)
     535           0 :             errorConflictingDefElem(defel, pstate);
     536             : 
     537       14592 :         *volatility_item = defel;
     538             :     }
     539       35378 :     else if (strcmp(defel->defname, "strict") == 0)
     540             :     {
     541       15492 :         if (is_procedure)
     542          12 :             goto procedure_error;
     543       15480 :         if (*strict_item)
     544           0 :             errorConflictingDefElem(defel, pstate);
     545             : 
     546       15480 :         *strict_item = defel;
     547             :     }
     548       19886 :     else if (strcmp(defel->defname, "security") == 0)
     549             :     {
     550          76 :         if (*security_item)
     551           0 :             errorConflictingDefElem(defel, pstate);
     552             : 
     553          76 :         *security_item = defel;
     554             :     }
     555       19810 :     else if (strcmp(defel->defname, "leakproof") == 0)
     556             :     {
     557          58 :         if (is_procedure)
     558           0 :             goto procedure_error;
     559          58 :         if (*leakproof_item)
     560           0 :             errorConflictingDefElem(defel, pstate);
     561             : 
     562          58 :         *leakproof_item = defel;
     563             :     }
     564       19752 :     else if (strcmp(defel->defname, "set") == 0)
     565             :     {
     566         154 :         *set_items = lappend(*set_items, defel->arg);
     567             :     }
     568       19598 :     else if (strcmp(defel->defname, "cost") == 0)
     569             :     {
     570        4360 :         if (is_procedure)
     571           0 :             goto procedure_error;
     572        4360 :         if (*cost_item)
     573           0 :             errorConflictingDefElem(defel, pstate);
     574             : 
     575        4360 :         *cost_item = defel;
     576             :     }
     577       15238 :     else if (strcmp(defel->defname, "rows") == 0)
     578             :     {
     579         600 :         if (is_procedure)
     580           0 :             goto procedure_error;
     581         600 :         if (*rows_item)
     582           0 :             errorConflictingDefElem(defel, pstate);
     583             : 
     584         600 :         *rows_item = defel;
     585             :     }
     586       14638 :     else if (strcmp(defel->defname, "support") == 0)
     587             :     {
     588         120 :         if (is_procedure)
     589           0 :             goto procedure_error;
     590         120 :         if (*support_item)
     591           0 :             errorConflictingDefElem(defel, pstate);
     592             : 
     593         120 :         *support_item = defel;
     594             :     }
     595       14518 :     else if (strcmp(defel->defname, "parallel") == 0)
     596             :     {
     597       14518 :         if (is_procedure)
     598           0 :             goto procedure_error;
     599       14518 :         if (*parallel_item)
     600           0 :             errorConflictingDefElem(defel, pstate);
     601             : 
     602       14518 :         *parallel_item = defel;
     603             :     }
     604             :     else
     605           0 :         return false;
     606             : 
     607             :     /* Recognized an option */
     608       49958 :     return true;
     609             : 
     610          12 : procedure_error:
     611          12 :     ereport(ERROR,
     612             :             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     613             :              errmsg("invalid attribute in procedure definition"),
     614             :              parser_errposition(pstate, defel->location)));
     615             :     return false;
     616             : }
     617             : 
     618             : static char
     619       14592 : interpret_func_volatility(DefElem *defel)
     620             : {
     621       14592 :     char       *str = strVal(defel->arg);
     622             : 
     623       14592 :     if (strcmp(str, "immutable") == 0)
     624       10202 :         return PROVOLATILE_IMMUTABLE;
     625        4390 :     else if (strcmp(str, "stable") == 0)
     626        2530 :         return PROVOLATILE_STABLE;
     627        1860 :     else if (strcmp(str, "volatile") == 0)
     628        1860 :         return PROVOLATILE_VOLATILE;
     629             :     else
     630             :     {
     631           0 :         elog(ERROR, "invalid volatility \"%s\"", str);
     632             :         return 0;               /* keep compiler quiet */
     633             :     }
     634             : }
     635             : 
     636             : static char
     637       14518 : interpret_func_parallel(DefElem *defel)
     638             : {
     639       14518 :     char       *str = strVal(defel->arg);
     640             : 
     641       14518 :     if (strcmp(str, "safe") == 0)
     642       12614 :         return PROPARALLEL_SAFE;
     643        1904 :     else if (strcmp(str, "unsafe") == 0)
     644         828 :         return PROPARALLEL_UNSAFE;
     645        1076 :     else if (strcmp(str, "restricted") == 0)
     646        1076 :         return PROPARALLEL_RESTRICTED;
     647             :     else
     648             :     {
     649           0 :         ereport(ERROR,
     650             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     651             :                  errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
     652             :         return PROPARALLEL_UNSAFE;  /* keep compiler quiet */
     653             :     }
     654             : }
     655             : 
     656             : /*
     657             :  * Update a proconfig value according to a list of VariableSetStmt items.
     658             :  *
     659             :  * The input and result may be NULL to signify a null entry.
     660             :  */
     661             : static ArrayType *
     662         114 : update_proconfig_value(ArrayType *a, List *set_items)
     663             : {
     664             :     ListCell   *l;
     665             : 
     666         268 :     foreach(l, set_items)
     667             :     {
     668         154 :         VariableSetStmt *sstmt = lfirst_node(VariableSetStmt, l);
     669             : 
     670         154 :         if (sstmt->kind == VAR_RESET_ALL)
     671          12 :             a = NULL;
     672             :         else
     673             :         {
     674         142 :             char       *valuestr = ExtractSetVariableArgs(sstmt);
     675             : 
     676         142 :             if (valuestr)
     677         142 :                 a = GUCArrayAdd(a, sstmt->name, valuestr);
     678             :             else                /* RESET */
     679           0 :                 a = GUCArrayDelete(a, sstmt->name);
     680             :         }
     681             :     }
     682             : 
     683         114 :     return a;
     684             : }
     685             : 
     686             : static Oid
     687         120 : interpret_func_support(DefElem *defel)
     688             : {
     689         120 :     List       *procName = defGetQualifiedName(defel);
     690             :     Oid         procOid;
     691             :     Oid         argList[1];
     692             : 
     693             :     /*
     694             :      * Support functions always take one INTERNAL argument and return
     695             :      * INTERNAL.
     696             :      */
     697         120 :     argList[0] = INTERNALOID;
     698             : 
     699         120 :     procOid = LookupFuncName(procName, 1, argList, true);
     700         120 :     if (!OidIsValid(procOid))
     701           0 :         ereport(ERROR,
     702             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     703             :                  errmsg("function %s does not exist",
     704             :                         func_signature_string(procName, 1, NIL, argList))));
     705             : 
     706         120 :     if (get_func_rettype(procOid) != INTERNALOID)
     707           0 :         ereport(ERROR,
     708             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     709             :                  errmsg("support function %s must return type %s",
     710             :                         NameListToString(procName), "internal")));
     711             : 
     712             :     /*
     713             :      * Someday we might want an ACL check here; but for now, we insist that
     714             :      * you be superuser to specify a support function, so privilege on the
     715             :      * support function is moot.
     716             :      */
     717         120 :     if (!superuser())
     718           0 :         ereport(ERROR,
     719             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     720             :                  errmsg("must be superuser to specify a support function")));
     721             : 
     722         120 :     return procOid;
     723             : }
     724             : 
     725             : 
     726             : /*
     727             :  * Dissect the list of options assembled in gram.y into function
     728             :  * attributes.
     729             :  */
     730             : static void
     731       26184 : compute_function_attributes(ParseState *pstate,
     732             :                             bool is_procedure,
     733             :                             List *options,
     734             :                             List **as,
     735             :                             char **language,
     736             :                             Node **transform,
     737             :                             bool *windowfunc_p,
     738             :                             char *volatility_p,
     739             :                             bool *strict_p,
     740             :                             bool *security_definer,
     741             :                             bool *leakproof_p,
     742             :                             ArrayType **proconfig,
     743             :                             float4 *procost,
     744             :                             float4 *prorows,
     745             :                             Oid *prosupport,
     746             :                             char *parallel_p)
     747             : {
     748             :     ListCell   *option;
     749       26184 :     DefElem    *as_item = NULL;
     750       26184 :     DefElem    *language_item = NULL;
     751       26184 :     DefElem    *transform_item = NULL;
     752       26184 :     DefElem    *windowfunc_item = NULL;
     753       26184 :     DefElem    *volatility_item = NULL;
     754       26184 :     DefElem    *strict_item = NULL;
     755       26184 :     DefElem    *security_item = NULL;
     756       26184 :     DefElem    *leakproof_item = NULL;
     757       26184 :     List       *set_items = NIL;
     758       26184 :     DefElem    *cost_item = NULL;
     759       26184 :     DefElem    *rows_item = NULL;
     760       26184 :     DefElem    *support_item = NULL;
     761       26184 :     DefElem    *parallel_item = NULL;
     762             : 
     763      121502 :     foreach(option, options)
     764             :     {
     765       95330 :         DefElem    *defel = (DefElem *) lfirst(option);
     766             : 
     767       95330 :         if (strcmp(defel->defname, "as") == 0)
     768             :         {
     769       20496 :             if (as_item)
     770           0 :                 errorConflictingDefElem(defel, pstate);
     771       20496 :             as_item = defel;
     772             :         }
     773       74834 :         else if (strcmp(defel->defname, "language") == 0)
     774             :         {
     775       26108 :             if (language_item)
     776           0 :                 errorConflictingDefElem(defel, pstate);
     777       26108 :             language_item = defel;
     778             :         }
     779       48726 :         else if (strcmp(defel->defname, "transform") == 0)
     780             :         {
     781         118 :             if (transform_item)
     782           0 :                 errorConflictingDefElem(defel, pstate);
     783         118 :             transform_item = defel;
     784             :         }
     785       48608 :         else if (strcmp(defel->defname, "window") == 0)
     786             :         {
     787          20 :             if (windowfunc_item)
     788           0 :                 errorConflictingDefElem(defel, pstate);
     789          20 :             if (is_procedure)
     790           6 :                 ereport(ERROR,
     791             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     792             :                          errmsg("invalid attribute in procedure definition"),
     793             :                          parser_errposition(pstate, defel->location)));
     794          14 :             windowfunc_item = defel;
     795             :         }
     796       48588 :         else if (compute_common_attribute(pstate,
     797             :                                           is_procedure,
     798             :                                           defel,
     799             :                                           &volatility_item,
     800             :                                           &strict_item,
     801             :                                           &security_item,
     802             :                                           &leakproof_item,
     803             :                                           &set_items,
     804             :                                           &cost_item,
     805             :                                           &rows_item,
     806             :                                           &support_item,
     807             :                                           &parallel_item))
     808             :         {
     809             :             /* recognized common option */
     810       48582 :             continue;
     811             :         }
     812             :         else
     813           0 :             elog(ERROR, "option \"%s\" not recognized",
     814             :                  defel->defname);
     815             :     }
     816             : 
     817       26172 :     if (as_item)
     818       20496 :         *as = (List *) as_item->arg;
     819       26172 :     if (language_item)
     820       26096 :         *language = strVal(language_item->arg);
     821       26172 :     if (transform_item)
     822         118 :         *transform = transform_item->arg;
     823       26172 :     if (windowfunc_item)
     824          14 :         *windowfunc_p = boolVal(windowfunc_item->arg);
     825       26172 :     if (volatility_item)
     826       14554 :         *volatility_p = interpret_func_volatility(volatility_item);
     827       26172 :     if (strict_item)
     828       15456 :         *strict_p = boolVal(strict_item->arg);
     829       26172 :     if (security_item)
     830          52 :         *security_definer = boolVal(security_item->arg);
     831       26172 :     if (leakproof_item)
     832          34 :         *leakproof_p = boolVal(leakproof_item->arg);
     833       26172 :     if (set_items)
     834          96 :         *proconfig = update_proconfig_value(NULL, set_items);
     835       26172 :     if (cost_item)
     836             :     {
     837        4346 :         *procost = defGetNumeric(cost_item);
     838        4346 :         if (*procost <= 0)
     839           0 :             ereport(ERROR,
     840             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     841             :                      errmsg("COST must be positive")));
     842             :     }
     843       26172 :     if (rows_item)
     844             :     {
     845         600 :         *prorows = defGetNumeric(rows_item);
     846         600 :         if (*prorows <= 0)
     847           0 :             ereport(ERROR,
     848             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     849             :                      errmsg("ROWS must be positive")));
     850             :     }
     851       26172 :     if (support_item)
     852         108 :         *prosupport = interpret_func_support(support_item);
     853       26172 :     if (parallel_item)
     854       13296 :         *parallel_p = interpret_func_parallel(parallel_item);
     855       26172 : }
     856             : 
     857             : 
     858             : /*
     859             :  * For a dynamically linked C language object, the form of the clause is
     860             :  *
     861             :  *     AS <object file name> [, <link symbol name> ]
     862             :  *
     863             :  * In all other cases
     864             :  *
     865             :  *     AS <object reference, or sql code>
     866             :  */
     867             : static void
     868       26086 : interpret_AS_clause(Oid languageOid, const char *languageName,
     869             :                     char *funcname, List *as, Node *sql_body_in,
     870             :                     List *parameterTypes, List *inParameterNames,
     871             :                     char **prosrc_str_p, char **probin_str_p,
     872             :                     Node **sql_body_out,
     873             :                     const char *queryString)
     874             : {
     875       26086 :     if (!sql_body_in && !as)
     876           0 :         ereport(ERROR,
     877             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     878             :                  errmsg("no function body specified")));
     879             : 
     880       26086 :     if (sql_body_in && as)
     881           6 :         ereport(ERROR,
     882             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     883             :                  errmsg("duplicate function body specified")));
     884             : 
     885       26080 :     if (sql_body_in && languageOid != SQLlanguageId)
     886           0 :         ereport(ERROR,
     887             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     888             :                  errmsg("inline SQL function body only valid for language SQL")));
     889             : 
     890       26080 :     *sql_body_out = NULL;
     891             : 
     892       26080 :     if (languageOid == ClanguageId)
     893             :     {
     894             :         /*
     895             :          * For "C" language, store the file name in probin and, when given,
     896             :          * the link symbol name in prosrc.  If link symbol is omitted,
     897             :          * substitute procedure name.  We also allow link symbol to be
     898             :          * specified as "-", since that was the habit in PG versions before
     899             :          * 8.4, and there might be dump files out there that don't translate
     900             :          * that back to "omitted".
     901             :          */
     902        7474 :         *probin_str_p = strVal(linitial(as));
     903        7474 :         if (list_length(as) == 1)
     904        3706 :             *prosrc_str_p = funcname;
     905             :         else
     906             :         {
     907        3768 :             *prosrc_str_p = strVal(lsecond(as));
     908        3768 :             if (strcmp(*prosrc_str_p, "-") == 0)
     909           0 :                 *prosrc_str_p = funcname;
     910             :         }
     911             :     }
     912       18606 :     else if (sql_body_in)
     913             :     {
     914             :         SQLFunctionParseInfoPtr pinfo;
     915             : 
     916        5676 :         pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
     917             : 
     918        5676 :         pinfo->fname = funcname;
     919        5676 :         pinfo->nargs = list_length(parameterTypes);
     920        5676 :         pinfo->argtypes = (Oid *) palloc(pinfo->nargs * sizeof(Oid));
     921        5676 :         pinfo->argnames = (char **) palloc(pinfo->nargs * sizeof(char *));
     922       17172 :         for (int i = 0; i < list_length(parameterTypes); i++)
     923             :         {
     924       11502 :             char       *s = strVal(list_nth(inParameterNames, i));
     925             : 
     926       11502 :             pinfo->argtypes[i] = list_nth_oid(parameterTypes, i);
     927       11502 :             if (IsPolymorphicType(pinfo->argtypes[i]))
     928           6 :                 ereport(ERROR,
     929             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     930             :                          errmsg("SQL function with unquoted function body cannot have polymorphic arguments")));
     931             : 
     932       11496 :             if (s[0] != '\0')
     933        1886 :                 pinfo->argnames[i] = s;
     934             :             else
     935        9610 :                 pinfo->argnames[i] = NULL;
     936             :         }
     937             : 
     938        5670 :         if (IsA(sql_body_in, List))
     939             :         {
     940         804 :             List       *stmts = linitial_node(List, castNode(List, sql_body_in));
     941             :             ListCell   *lc;
     942         804 :             List       *transformed_stmts = NIL;
     943             : 
     944        1600 :             foreach(lc, stmts)
     945             :             {
     946         802 :                 Node       *stmt = lfirst(lc);
     947             :                 Query      *q;
     948         802 :                 ParseState *pstate = make_parsestate(NULL);
     949             : 
     950         802 :                 pstate->p_sourcetext = queryString;
     951         802 :                 sql_fn_parser_setup(pstate, pinfo);
     952         802 :                 q = transformStmt(pstate, stmt);
     953         802 :                 if (q->commandType == CMD_UTILITY)
     954           6 :                     ereport(ERROR,
     955             :                             errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     956             :                             errmsg("%s is not yet supported in unquoted SQL function body",
     957             :                                    GetCommandTagName(CreateCommandTag(q->utilityStmt))));
     958         796 :                 transformed_stmts = lappend(transformed_stmts, q);
     959         796 :                 free_parsestate(pstate);
     960             :             }
     961             : 
     962         798 :             *sql_body_out = (Node *) list_make1(transformed_stmts);
     963             :         }
     964             :         else
     965             :         {
     966             :             Query      *q;
     967        4866 :             ParseState *pstate = make_parsestate(NULL);
     968             : 
     969        4866 :             pstate->p_sourcetext = queryString;
     970        4866 :             sql_fn_parser_setup(pstate, pinfo);
     971        4866 :             q = transformStmt(pstate, sql_body_in);
     972        4860 :             if (q->commandType == CMD_UTILITY)
     973           0 :                 ereport(ERROR,
     974             :                         errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     975             :                         errmsg("%s is not yet supported in unquoted SQL function body",
     976             :                                GetCommandTagName(CreateCommandTag(q->utilityStmt))));
     977        4860 :             free_parsestate(pstate);
     978             : 
     979        4860 :             *sql_body_out = (Node *) q;
     980             :         }
     981             : 
     982             :         /*
     983             :          * We must put something in prosrc.  For the moment, just record an
     984             :          * empty string.  It might be useful to store the original text of the
     985             :          * CREATE FUNCTION statement --- but to make actual use of that in
     986             :          * error reports, we'd also have to adjust readfuncs.c to not throw
     987             :          * away node location fields when reading prosqlbody.
     988             :          */
     989        5658 :         *prosrc_str_p = pstrdup("");
     990             : 
     991             :         /* But we definitely don't need probin. */
     992        5658 :         *probin_str_p = NULL;
     993             :     }
     994             :     else
     995             :     {
     996             :         /* Everything else wants the given string in prosrc. */
     997       12930 :         *prosrc_str_p = strVal(linitial(as));
     998       12930 :         *probin_str_p = NULL;
     999             : 
    1000       12930 :         if (list_length(as) != 1)
    1001           6 :             ereport(ERROR,
    1002             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
    1003             :                      errmsg("only one AS item needed for language \"%s\"",
    1004             :                             languageName)));
    1005             : 
    1006       12924 :         if (languageOid == INTERNALlanguageId)
    1007             :         {
    1008             :             /*
    1009             :              * In PostgreSQL versions before 6.5, the SQL name of the created
    1010             :              * function could not be different from the internal name, and
    1011             :              * "prosrc" wasn't used.  So there is code out there that does
    1012             :              * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
    1013             :              * modicum of backwards compatibility, accept an empty "prosrc"
    1014             :              * value as meaning the supplied SQL function name.
    1015             :              */
    1016        4328 :             if (strlen(*prosrc_str_p) == 0)
    1017           0 :                 *prosrc_str_p = funcname;
    1018             :         }
    1019             :     }
    1020       26056 : }
    1021             : 
    1022             : 
    1023             : /*
    1024             :  * CreateFunction
    1025             :  *   Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement.
    1026             :  */
    1027             : ObjectAddress
    1028       26184 : CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
    1029             : {
    1030             :     char       *probin_str;
    1031             :     char       *prosrc_str;
    1032             :     Node       *prosqlbody;
    1033             :     Oid         prorettype;
    1034             :     bool        returnsSet;
    1035             :     char       *language;
    1036             :     Oid         languageOid;
    1037             :     Oid         languageValidator;
    1038       26184 :     Node       *transformDefElem = NULL;
    1039             :     char       *funcname;
    1040             :     Oid         namespaceId;
    1041             :     AclResult   aclresult;
    1042             :     oidvector  *parameterTypes;
    1043       26184 :     List       *parameterTypes_list = NIL;
    1044             :     ArrayType  *allParameterTypes;
    1045             :     ArrayType  *parameterModes;
    1046             :     ArrayType  *parameterNames;
    1047       26184 :     List       *inParameterNames_list = NIL;
    1048             :     List       *parameterDefaults;
    1049             :     Oid         variadicArgType;
    1050       26184 :     List       *trftypes_list = NIL;
    1051       26184 :     List       *trfoids_list = NIL;
    1052             :     ArrayType  *trftypes;
    1053             :     Oid         requiredResultType;
    1054             :     bool        isWindowFunc,
    1055             :                 isStrict,
    1056             :                 security,
    1057             :                 isLeakProof;
    1058             :     char        volatility;
    1059             :     ArrayType  *proconfig;
    1060             :     float4      procost;
    1061             :     float4      prorows;
    1062             :     Oid         prosupport;
    1063             :     HeapTuple   languageTuple;
    1064             :     Form_pg_language languageStruct;
    1065             :     List       *as_clause;
    1066             :     char        parallel;
    1067             : 
    1068             :     /* Convert list of names to a name and namespace */
    1069       26184 :     namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
    1070             :                                                     &funcname);
    1071             : 
    1072             :     /* Check we have creation rights in target namespace */
    1073       26184 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
    1074       26184 :     if (aclresult != ACLCHECK_OK)
    1075           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
    1076           0 :                        get_namespace_name(namespaceId));
    1077             : 
    1078             :     /* Set default attributes */
    1079       26184 :     as_clause = NIL;
    1080       26184 :     language = NULL;
    1081       26184 :     isWindowFunc = false;
    1082       26184 :     isStrict = false;
    1083       26184 :     security = false;
    1084       26184 :     isLeakProof = false;
    1085       26184 :     volatility = PROVOLATILE_VOLATILE;
    1086       26184 :     proconfig = NULL;
    1087       26184 :     procost = -1;               /* indicates not set */
    1088       26184 :     prorows = -1;               /* indicates not set */
    1089       26184 :     prosupport = InvalidOid;
    1090       26184 :     parallel = PROPARALLEL_UNSAFE;
    1091             : 
    1092             :     /* Extract non-default attributes from stmt->options list */
    1093       26184 :     compute_function_attributes(pstate,
    1094       26184 :                                 stmt->is_procedure,
    1095             :                                 stmt->options,
    1096             :                                 &as_clause, &language, &transformDefElem,
    1097             :                                 &isWindowFunc, &volatility,
    1098             :                                 &isStrict, &security, &isLeakProof,
    1099             :                                 &proconfig, &procost, &prorows,
    1100             :                                 &prosupport, &parallel);
    1101             : 
    1102       26172 :     if (!language)
    1103             :     {
    1104          76 :         if (stmt->sql_body)
    1105          76 :             language = "sql";
    1106             :         else
    1107           0 :             ereport(ERROR,
    1108             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
    1109             :                      errmsg("no language specified")));
    1110             :     }
    1111             : 
    1112             :     /* Look up the language and validate permissions */
    1113       26172 :     languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
    1114       26172 :     if (!HeapTupleIsValid(languageTuple))
    1115           0 :         ereport(ERROR,
    1116             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1117             :                  errmsg("language \"%s\" does not exist", language),
    1118             :                  (extension_file_exists(language) ?
    1119             :                   errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
    1120             : 
    1121       26172 :     languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
    1122       26172 :     languageOid = languageStruct->oid;
    1123             : 
    1124       26172 :     if (languageStruct->lanpltrusted)
    1125             :     {
    1126             :         /* if trusted language, need USAGE privilege */
    1127       13820 :         aclresult = object_aclcheck(LanguageRelationId, languageOid, GetUserId(), ACL_USAGE);
    1128       13820 :         if (aclresult != ACLCHECK_OK)
    1129           8 :             aclcheck_error(aclresult, OBJECT_LANGUAGE,
    1130           8 :                            NameStr(languageStruct->lanname));
    1131             :     }
    1132             :     else
    1133             :     {
    1134             :         /* if untrusted language, must be superuser */
    1135       12352 :         if (!superuser())
    1136           0 :             aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
    1137           0 :                            NameStr(languageStruct->lanname));
    1138             :     }
    1139             : 
    1140       26164 :     languageValidator = languageStruct->lanvalidator;
    1141             : 
    1142       26164 :     ReleaseSysCache(languageTuple);
    1143             : 
    1144             :     /*
    1145             :      * Only superuser is allowed to create leakproof functions because
    1146             :      * leakproof functions can see tuples which have not yet been filtered out
    1147             :      * by security barrier views or row-level security policies.
    1148             :      */
    1149       26164 :     if (isLeakProof && !superuser())
    1150           6 :         ereport(ERROR,
    1151             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1152             :                  errmsg("only superuser can define a leakproof function")));
    1153             : 
    1154       26158 :     if (transformDefElem)
    1155             :     {
    1156             :         ListCell   *lc;
    1157             : 
    1158         240 :         foreach(lc, castNode(List, transformDefElem))
    1159             :         {
    1160         122 :             Oid         typeid = typenameTypeId(NULL,
    1161         122 :                                                 lfirst_node(TypeName, lc));
    1162         122 :             Oid         elt = get_base_element_type(typeid);
    1163             :             Oid         transformid;
    1164             : 
    1165         122 :             typeid = elt ? elt : typeid;
    1166         122 :             transformid = get_transform_oid(typeid, languageOid, false);
    1167         122 :             trftypes_list = lappend_oid(trftypes_list, typeid);
    1168         122 :             trfoids_list = lappend_oid(trfoids_list, transformid);
    1169             :         }
    1170             :     }
    1171             : 
    1172             :     /*
    1173             :      * Convert remaining parameters of CREATE to form wanted by
    1174             :      * ProcedureCreate.
    1175             :      */
    1176       26158 :     interpret_function_parameter_list(pstate,
    1177             :                                       stmt->parameters,
    1178             :                                       languageOid,
    1179       26158 :                                       stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
    1180             :                                       &parameterTypes,
    1181             :                                       &parameterTypes_list,
    1182             :                                       &allParameterTypes,
    1183             :                                       &parameterModes,
    1184             :                                       &parameterNames,
    1185             :                                       &inParameterNames_list,
    1186             :                                       &parameterDefaults,
    1187             :                                       &variadicArgType,
    1188             :                                       &requiredResultType);
    1189             : 
    1190       26104 :     if (stmt->is_procedure)
    1191             :     {
    1192             :         Assert(!stmt->returnType);
    1193         344 :         prorettype = requiredResultType ? requiredResultType : VOIDOID;
    1194         344 :         returnsSet = false;
    1195             :     }
    1196       25760 :     else if (stmt->returnType)
    1197             :     {
    1198             :         /* explicit RETURNS clause */
    1199       25266 :         compute_return_type(stmt->returnType, languageOid,
    1200             :                             &prorettype, &returnsSet);
    1201       25260 :         if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
    1202          12 :             ereport(ERROR,
    1203             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
    1204             :                      errmsg("function result type must be %s because of OUT parameters",
    1205             :                             format_type_be(requiredResultType))));
    1206             :     }
    1207         494 :     else if (OidIsValid(requiredResultType))
    1208             :     {
    1209             :         /* default RETURNS clause from OUT parameters */
    1210         494 :         prorettype = requiredResultType;
    1211         494 :         returnsSet = false;
    1212             :     }
    1213             :     else
    1214             :     {
    1215           0 :         ereport(ERROR,
    1216             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
    1217             :                  errmsg("function result type must be specified")));
    1218             :         /* Alternative possibility: default to RETURNS VOID */
    1219             :         prorettype = VOIDOID;
    1220             :         returnsSet = false;
    1221             :     }
    1222             : 
    1223       26086 :     if (trftypes_list != NIL)
    1224             :     {
    1225             :         ListCell   *lc;
    1226             :         Datum      *arr;
    1227             :         int         i;
    1228             : 
    1229         118 :         arr = palloc(list_length(trftypes_list) * sizeof(Datum));
    1230         118 :         i = 0;
    1231         240 :         foreach(lc, trftypes_list)
    1232         122 :             arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
    1233         118 :         trftypes = construct_array_builtin(arr, list_length(trftypes_list), OIDOID);
    1234             :     }
    1235             :     else
    1236             :     {
    1237             :         /* store SQL NULL instead of empty array */
    1238       25968 :         trftypes = NULL;
    1239             :     }
    1240             : 
    1241       26086 :     interpret_AS_clause(languageOid, language, funcname, as_clause, stmt->sql_body,
    1242             :                         parameterTypes_list, inParameterNames_list,
    1243             :                         &prosrc_str, &probin_str, &prosqlbody,
    1244             :                         pstate->p_sourcetext);
    1245             : 
    1246             :     /*
    1247             :      * Set default values for COST and ROWS depending on other parameters;
    1248             :      * reject ROWS if it's not returnsSet.  NB: pg_dump knows these default
    1249             :      * values, keep it in sync if you change them.
    1250             :      */
    1251       26056 :     if (procost < 0)
    1252             :     {
    1253             :         /* SQL and PL-language functions are assumed more expensive */
    1254       21710 :         if (languageOid == INTERNALlanguageId ||
    1255             :             languageOid == ClanguageId)
    1256       11322 :             procost = 1;
    1257             :         else
    1258       10388 :             procost = 100;
    1259             :     }
    1260       26056 :     if (prorows < 0)
    1261             :     {
    1262       25456 :         if (returnsSet)
    1263        2012 :             prorows = 1000;
    1264             :         else
    1265       23444 :             prorows = 0;        /* dummy value if not returnsSet */
    1266             :     }
    1267         600 :     else if (!returnsSet)
    1268           0 :         ereport(ERROR,
    1269             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1270             :                  errmsg("ROWS is not applicable when function does not return a set")));
    1271             : 
    1272             :     /*
    1273             :      * And now that we have all the parameters, and know we're permitted to do
    1274             :      * so, go ahead and create the function.
    1275             :      */
    1276       52112 :     return ProcedureCreate(funcname,
    1277             :                            namespaceId,
    1278       26056 :                            stmt->replace,
    1279             :                            returnsSet,
    1280             :                            prorettype,
    1281             :                            GetUserId(),
    1282             :                            languageOid,
    1283             :                            languageValidator,
    1284             :                            prosrc_str,  /* converted to text later */
    1285             :                            probin_str,  /* converted to text later */
    1286             :                            prosqlbody,
    1287       26056 :                            stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
    1288             :                            security,
    1289             :                            isLeakProof,
    1290             :                            isStrict,
    1291             :                            volatility,
    1292             :                            parallel,
    1293             :                            parameterTypes,
    1294             :                            PointerGetDatum(allParameterTypes),
    1295             :                            PointerGetDatum(parameterModes),
    1296             :                            PointerGetDatum(parameterNames),
    1297             :                            parameterDefaults,
    1298             :                            PointerGetDatum(trftypes),
    1299             :                            trfoids_list,
    1300             :                            PointerGetDatum(proconfig),
    1301             :                            prosupport,
    1302             :                            procost,
    1303             :                            prorows);
    1304             : }
    1305             : 
    1306             : /*
    1307             :  * Guts of function deletion.
    1308             :  *
    1309             :  * Note: this is also used for aggregate deletion, since the OIDs of
    1310             :  * both functions and aggregates point to pg_proc.
    1311             :  */
    1312             : void
    1313        8702 : RemoveFunctionById(Oid funcOid)
    1314             : {
    1315             :     Relation    relation;
    1316             :     HeapTuple   tup;
    1317             :     char        prokind;
    1318             : 
    1319             :     /*
    1320             :      * Delete the pg_proc tuple.
    1321             :      */
    1322        8702 :     relation = table_open(ProcedureRelationId, RowExclusiveLock);
    1323             : 
    1324        8702 :     tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
    1325        8702 :     if (!HeapTupleIsValid(tup)) /* should not happen */
    1326           0 :         elog(ERROR, "cache lookup failed for function %u", funcOid);
    1327             : 
    1328        8702 :     prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
    1329             : 
    1330        8702 :     CatalogTupleDelete(relation, &tup->t_self);
    1331             : 
    1332        8702 :     ReleaseSysCache(tup);
    1333             : 
    1334        8702 :     table_close(relation, RowExclusiveLock);
    1335             : 
    1336        8702 :     pgstat_drop_function(funcOid);
    1337             : 
    1338             :     /*
    1339             :      * If there's a pg_aggregate tuple, delete that too.
    1340             :      */
    1341        8702 :     if (prokind == PROKIND_AGGREGATE)
    1342             :     {
    1343         120 :         relation = table_open(AggregateRelationId, RowExclusiveLock);
    1344             : 
    1345         120 :         tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
    1346         120 :         if (!HeapTupleIsValid(tup)) /* should not happen */
    1347           0 :             elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
    1348             : 
    1349         120 :         CatalogTupleDelete(relation, &tup->t_self);
    1350             : 
    1351         120 :         ReleaseSysCache(tup);
    1352             : 
    1353         120 :         table_close(relation, RowExclusiveLock);
    1354             :     }
    1355        8702 : }
    1356             : 
    1357             : /*
    1358             :  * Implements the ALTER FUNCTION utility command (except for the
    1359             :  * RENAME and OWNER clauses, which are handled as part of the generic
    1360             :  * ALTER framework).
    1361             :  */
    1362             : ObjectAddress
    1363        1396 : AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
    1364             : {
    1365             :     HeapTuple   tup;
    1366             :     Oid         funcOid;
    1367             :     Form_pg_proc procForm;
    1368             :     bool        is_procedure;
    1369             :     Relation    rel;
    1370             :     ListCell   *l;
    1371        1396 :     DefElem    *volatility_item = NULL;
    1372        1396 :     DefElem    *strict_item = NULL;
    1373        1396 :     DefElem    *security_def_item = NULL;
    1374        1396 :     DefElem    *leakproof_item = NULL;
    1375        1396 :     List       *set_items = NIL;
    1376        1396 :     DefElem    *cost_item = NULL;
    1377        1396 :     DefElem    *rows_item = NULL;
    1378        1396 :     DefElem    *support_item = NULL;
    1379        1396 :     DefElem    *parallel_item = NULL;
    1380             :     ObjectAddress address;
    1381             : 
    1382        1396 :     rel = table_open(ProcedureRelationId, RowExclusiveLock);
    1383             : 
    1384        1396 :     funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
    1385             : 
    1386        1378 :     ObjectAddressSet(address, ProcedureRelationId, funcOid);
    1387             : 
    1388        1378 :     tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
    1389        1378 :     if (!HeapTupleIsValid(tup)) /* should not happen */
    1390           0 :         elog(ERROR, "cache lookup failed for function %u", funcOid);
    1391             : 
    1392        1378 :     procForm = (Form_pg_proc) GETSTRUCT(tup);
    1393             : 
    1394             :     /* Permission check: must own function */
    1395        1378 :     if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
    1396           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
    1397           0 :                        NameListToString(stmt->func->objname));
    1398             : 
    1399        1378 :     if (procForm->prokind == PROKIND_AGGREGATE)
    1400           0 :         ereport(ERROR,
    1401             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1402             :                  errmsg("\"%s\" is an aggregate function",
    1403             :                         NameListToString(stmt->func->objname))));
    1404             : 
    1405        1378 :     is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
    1406             : 
    1407             :     /* Examine requested actions. */
    1408        2754 :     foreach(l, stmt->actions)
    1409             :     {
    1410        1382 :         DefElem    *defel = (DefElem *) lfirst(l);
    1411             : 
    1412        1382 :         if (compute_common_attribute(pstate,
    1413             :                                      is_procedure,
    1414             :                                      defel,
    1415             :                                      &volatility_item,
    1416             :                                      &strict_item,
    1417             :                                      &security_def_item,
    1418             :                                      &leakproof_item,
    1419             :                                      &set_items,
    1420             :                                      &cost_item,
    1421             :                                      &rows_item,
    1422             :                                      &support_item,
    1423        1376 :                                      &parallel_item) == false)
    1424           0 :             elog(ERROR, "option \"%s\" not recognized", defel->defname);
    1425             :     }
    1426             : 
    1427        1372 :     if (volatility_item)
    1428          38 :         procForm->provolatile = interpret_func_volatility(volatility_item);
    1429        1372 :     if (strict_item)
    1430          24 :         procForm->proisstrict = boolVal(strict_item->arg);
    1431        1372 :     if (security_def_item)
    1432          24 :         procForm->prosecdef = boolVal(security_def_item->arg);
    1433        1372 :     if (leakproof_item)
    1434             :     {
    1435          24 :         procForm->proleakproof = boolVal(leakproof_item->arg);
    1436          24 :         if (procForm->proleakproof && !superuser())
    1437           6 :             ereport(ERROR,
    1438             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1439             :                      errmsg("only superuser can define a leakproof function")));
    1440             :     }
    1441        1366 :     if (cost_item)
    1442             :     {
    1443          14 :         procForm->procost = defGetNumeric(cost_item);
    1444          14 :         if (procForm->procost <= 0)
    1445           0 :             ereport(ERROR,
    1446             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1447             :                      errmsg("COST must be positive")));
    1448             :     }
    1449        1366 :     if (rows_item)
    1450             :     {
    1451           0 :         procForm->prorows = defGetNumeric(rows_item);
    1452           0 :         if (procForm->prorows <= 0)
    1453           0 :             ereport(ERROR,
    1454             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1455             :                      errmsg("ROWS must be positive")));
    1456           0 :         if (!procForm->proretset)
    1457           0 :             ereport(ERROR,
    1458             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1459             :                      errmsg("ROWS is not applicable when function does not return a set")));
    1460             :     }
    1461        1366 :     if (support_item)
    1462             :     {
    1463             :         /* interpret_func_support handles the privilege check */
    1464          12 :         Oid         newsupport = interpret_func_support(support_item);
    1465             : 
    1466             :         /* Add or replace dependency on support function */
    1467          12 :         if (OidIsValid(procForm->prosupport))
    1468             :         {
    1469           0 :             if (changeDependencyFor(ProcedureRelationId, funcOid,
    1470             :                                     ProcedureRelationId, procForm->prosupport,
    1471             :                                     newsupport) != 1)
    1472           0 :                 elog(ERROR, "could not change support dependency for function %s",
    1473             :                      get_func_name(funcOid));
    1474             :         }
    1475             :         else
    1476             :         {
    1477             :             ObjectAddress referenced;
    1478             : 
    1479          12 :             referenced.classId = ProcedureRelationId;
    1480          12 :             referenced.objectId = newsupport;
    1481          12 :             referenced.objectSubId = 0;
    1482          12 :             recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
    1483             :         }
    1484             : 
    1485          12 :         procForm->prosupport = newsupport;
    1486             :     }
    1487        1366 :     if (parallel_item)
    1488        1222 :         procForm->proparallel = interpret_func_parallel(parallel_item);
    1489        1366 :     if (set_items)
    1490             :     {
    1491             :         Datum       datum;
    1492             :         bool        isnull;
    1493             :         ArrayType  *a;
    1494             :         Datum       repl_val[Natts_pg_proc];
    1495             :         bool        repl_null[Natts_pg_proc];
    1496             :         bool        repl_repl[Natts_pg_proc];
    1497             : 
    1498             :         /* extract existing proconfig setting */
    1499          18 :         datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
    1500          18 :         a = isnull ? NULL : DatumGetArrayTypeP(datum);
    1501             : 
    1502             :         /* update according to each SET or RESET item, left to right */
    1503          18 :         a = update_proconfig_value(a, set_items);
    1504             : 
    1505             :         /* update the tuple */
    1506          18 :         memset(repl_repl, false, sizeof(repl_repl));
    1507          18 :         repl_repl[Anum_pg_proc_proconfig - 1] = true;
    1508             : 
    1509          18 :         if (a == NULL)
    1510             :         {
    1511          12 :             repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
    1512          12 :             repl_null[Anum_pg_proc_proconfig - 1] = true;
    1513             :         }
    1514             :         else
    1515             :         {
    1516           6 :             repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
    1517           6 :             repl_null[Anum_pg_proc_proconfig - 1] = false;
    1518             :         }
    1519             : 
    1520          18 :         tup = heap_modify_tuple(tup, RelationGetDescr(rel),
    1521             :                                 repl_val, repl_null, repl_repl);
    1522             :     }
    1523             :     /* DO NOT put more touches of procForm below here; it's now dangling. */
    1524             : 
    1525             :     /* Do the update */
    1526        1366 :     CatalogTupleUpdate(rel, &tup->t_self, tup);
    1527             : 
    1528        1366 :     InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
    1529             : 
    1530        1366 :     table_close(rel, NoLock);
    1531        1366 :     heap_freetuple(tup);
    1532             : 
    1533        1366 :     return address;
    1534             : }
    1535             : 
    1536             : 
    1537             : /*
    1538             :  * CREATE CAST
    1539             :  */
    1540             : ObjectAddress
    1541         278 : CreateCast(CreateCastStmt *stmt)
    1542             : {
    1543             :     Oid         sourcetypeid;
    1544             :     Oid         targettypeid;
    1545             :     char        sourcetyptype;
    1546             :     char        targettyptype;
    1547             :     Oid         funcid;
    1548         278 :     Oid         incastid = InvalidOid;
    1549         278 :     Oid         outcastid = InvalidOid;
    1550             :     int         nargs;
    1551             :     char        castcontext;
    1552             :     char        castmethod;
    1553             :     HeapTuple   tuple;
    1554             :     AclResult   aclresult;
    1555             :     ObjectAddress myself;
    1556             : 
    1557         278 :     sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
    1558         278 :     targettypeid = typenameTypeId(NULL, stmt->targettype);
    1559         278 :     sourcetyptype = get_typtype(sourcetypeid);
    1560         278 :     targettyptype = get_typtype(targettypeid);
    1561             : 
    1562             :     /* No pseudo-types allowed */
    1563         278 :     if (sourcetyptype == TYPTYPE_PSEUDO)
    1564           0 :         ereport(ERROR,
    1565             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1566             :                  errmsg("source data type %s is a pseudo-type",
    1567             :                         TypeNameToString(stmt->sourcetype))));
    1568             : 
    1569         278 :     if (targettyptype == TYPTYPE_PSEUDO)
    1570           0 :         ereport(ERROR,
    1571             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1572             :                  errmsg("target data type %s is a pseudo-type",
    1573             :                         TypeNameToString(stmt->targettype))));
    1574             : 
    1575             :     /* Permission check */
    1576         278 :     if (!object_ownercheck(TypeRelationId, sourcetypeid, GetUserId())
    1577          12 :         && !object_ownercheck(TypeRelationId, targettypeid, GetUserId()))
    1578           0 :         ereport(ERROR,
    1579             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1580             :                  errmsg("must be owner of type %s or type %s",
    1581             :                         format_type_be(sourcetypeid),
    1582             :                         format_type_be(targettypeid))));
    1583             : 
    1584         278 :     aclresult = object_aclcheck(TypeRelationId, sourcetypeid, GetUserId(), ACL_USAGE);
    1585         278 :     if (aclresult != ACLCHECK_OK)
    1586           6 :         aclcheck_error_type(aclresult, sourcetypeid);
    1587             : 
    1588         272 :     aclresult = object_aclcheck(TypeRelationId, targettypeid, GetUserId(), ACL_USAGE);
    1589         272 :     if (aclresult != ACLCHECK_OK)
    1590           0 :         aclcheck_error_type(aclresult, targettypeid);
    1591             : 
    1592             :     /* Domains are allowed for historical reasons, but we warn */
    1593         272 :     if (sourcetyptype == TYPTYPE_DOMAIN)
    1594           6 :         ereport(WARNING,
    1595             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1596             :                  errmsg("cast will be ignored because the source data type is a domain")));
    1597             : 
    1598         266 :     else if (targettyptype == TYPTYPE_DOMAIN)
    1599           0 :         ereport(WARNING,
    1600             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1601             :                  errmsg("cast will be ignored because the target data type is a domain")));
    1602             : 
    1603             :     /* Determine the cast method */
    1604         272 :     if (stmt->func != NULL)
    1605         102 :         castmethod = COERCION_METHOD_FUNCTION;
    1606         170 :     else if (stmt->inout)
    1607           8 :         castmethod = COERCION_METHOD_INOUT;
    1608             :     else
    1609         162 :         castmethod = COERCION_METHOD_BINARY;
    1610             : 
    1611         272 :     if (castmethod == COERCION_METHOD_FUNCTION)
    1612             :     {
    1613             :         Form_pg_proc procstruct;
    1614             : 
    1615         102 :         funcid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->func, false);
    1616             : 
    1617         102 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
    1618         102 :         if (!HeapTupleIsValid(tuple))
    1619           0 :             elog(ERROR, "cache lookup failed for function %u", funcid);
    1620             : 
    1621         102 :         procstruct = (Form_pg_proc) GETSTRUCT(tuple);
    1622         102 :         nargs = procstruct->pronargs;
    1623         102 :         if (nargs < 1 || nargs > 3)
    1624           0 :             ereport(ERROR,
    1625             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1626             :                      errmsg("cast function must take one to three arguments")));
    1627         102 :         if (!IsBinaryCoercibleWithCast(sourcetypeid,
    1628             :                                        procstruct->proargtypes.values[0],
    1629             :                                        &incastid))
    1630           0 :             ereport(ERROR,
    1631             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1632             :                      errmsg("argument of cast function must match or be binary-coercible from source data type")));
    1633         102 :         if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
    1634           0 :             ereport(ERROR,
    1635             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1636             :                      errmsg("second argument of cast function must be type %s",
    1637             :                             "integer")));
    1638         102 :         if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
    1639           0 :             ereport(ERROR,
    1640             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1641             :                      errmsg("third argument of cast function must be type %s",
    1642             :                             "boolean")));
    1643         102 :         if (!IsBinaryCoercibleWithCast(procstruct->prorettype,
    1644             :                                        targettypeid,
    1645             :                                        &outcastid))
    1646           0 :             ereport(ERROR,
    1647             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1648             :                      errmsg("return data type of cast function must match or be binary-coercible to target data type")));
    1649             : 
    1650             :         /*
    1651             :          * Restricting the volatility of a cast function may or may not be a
    1652             :          * good idea in the abstract, but it definitely breaks many old
    1653             :          * user-defined types.  Disable this check --- tgl 2/1/03
    1654             :          */
    1655             : #ifdef NOT_USED
    1656             :         if (procstruct->provolatile == PROVOLATILE_VOLATILE)
    1657             :             ereport(ERROR,
    1658             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1659             :                      errmsg("cast function must not be volatile")));
    1660             : #endif
    1661         102 :         if (procstruct->prokind != PROKIND_FUNCTION)
    1662           0 :             ereport(ERROR,
    1663             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1664             :                      errmsg("cast function must be a normal function")));
    1665         102 :         if (procstruct->proretset)
    1666           0 :             ereport(ERROR,
    1667             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1668             :                      errmsg("cast function must not return a set")));
    1669             : 
    1670         102 :         ReleaseSysCache(tuple);
    1671             :     }
    1672             :     else
    1673             :     {
    1674         170 :         funcid = InvalidOid;
    1675         170 :         nargs = 0;
    1676             :     }
    1677             : 
    1678         272 :     if (castmethod == COERCION_METHOD_BINARY)
    1679             :     {
    1680             :         int16       typ1len;
    1681             :         int16       typ2len;
    1682             :         bool        typ1byval;
    1683             :         bool        typ2byval;
    1684             :         char        typ1align;
    1685             :         char        typ2align;
    1686             : 
    1687             :         /*
    1688             :          * Must be superuser to create binary-compatible casts, since
    1689             :          * erroneous casts can easily crash the backend.
    1690             :          */
    1691         162 :         if (!superuser())
    1692           0 :             ereport(ERROR,
    1693             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1694             :                      errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
    1695             : 
    1696             :         /*
    1697             :          * Also, insist that the types match as to size, alignment, and
    1698             :          * pass-by-value attributes; this provides at least a crude check that
    1699             :          * they have similar representations.  A pair of types that fail this
    1700             :          * test should certainly not be equated.
    1701             :          */
    1702         162 :         get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
    1703         162 :         get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
    1704         162 :         if (typ1len != typ2len ||
    1705         162 :             typ1byval != typ2byval ||
    1706         162 :             typ1align != typ2align)
    1707           0 :             ereport(ERROR,
    1708             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1709             :                      errmsg("source and target data types are not physically compatible")));
    1710             : 
    1711             :         /*
    1712             :          * We know that composite, array, range and enum types are never
    1713             :          * binary-compatible with each other.  They all have OIDs embedded in
    1714             :          * them.
    1715             :          *
    1716             :          * Theoretically you could build a user-defined base type that is
    1717             :          * binary-compatible with such a type.  But we disallow it anyway, as
    1718             :          * in practice such a cast is surely a mistake.  You can always work
    1719             :          * around that by writing a cast function.
    1720             :          *
    1721             :          * NOTE: if we ever have a kind of container type that doesn't need to
    1722             :          * be rejected for this reason, we'd likely need to recursively apply
    1723             :          * all of these same checks to the contained type(s).
    1724             :          */
    1725         162 :         if (sourcetyptype == TYPTYPE_COMPOSITE ||
    1726             :             targettyptype == TYPTYPE_COMPOSITE)
    1727           0 :             ereport(ERROR,
    1728             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1729             :                      errmsg("composite data types are not binary-compatible")));
    1730             : 
    1731         324 :         if (OidIsValid(get_element_type(sourcetypeid)) ||
    1732         162 :             OidIsValid(get_element_type(targettypeid)))
    1733           0 :             ereport(ERROR,
    1734             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1735             :                      errmsg("array data types are not binary-compatible")));
    1736             : 
    1737         162 :         if (sourcetyptype == TYPTYPE_RANGE ||
    1738         162 :             targettyptype == TYPTYPE_RANGE ||
    1739         162 :             sourcetyptype == TYPTYPE_MULTIRANGE ||
    1740             :             targettyptype == TYPTYPE_MULTIRANGE)
    1741           0 :             ereport(ERROR,
    1742             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1743             :                      errmsg("range data types are not binary-compatible")));
    1744             : 
    1745         162 :         if (sourcetyptype == TYPTYPE_ENUM ||
    1746             :             targettyptype == TYPTYPE_ENUM)
    1747           0 :             ereport(ERROR,
    1748             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1749             :                      errmsg("enum data types are not binary-compatible")));
    1750             : 
    1751             :         /*
    1752             :          * We also disallow creating binary-compatibility casts involving
    1753             :          * domains.  Casting from a domain to its base type is already
    1754             :          * allowed, and casting the other way ought to go through domain
    1755             :          * coercion to permit constraint checking.  Again, if you're intent on
    1756             :          * having your own semantics for that, create a no-op cast function.
    1757             :          *
    1758             :          * NOTE: if we were to relax this, the above checks for composites
    1759             :          * etc. would have to be modified to look through domains to their
    1760             :          * base types.
    1761             :          */
    1762         162 :         if (sourcetyptype == TYPTYPE_DOMAIN ||
    1763             :             targettyptype == TYPTYPE_DOMAIN)
    1764           0 :             ereport(ERROR,
    1765             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1766             :                      errmsg("domain data types must not be marked binary-compatible")));
    1767             :     }
    1768             : 
    1769             :     /*
    1770             :      * Allow source and target types to be same only for length coercion
    1771             :      * functions.  We assume a multi-arg function does length coercion.
    1772             :      */
    1773         272 :     if (sourcetypeid == targettypeid && nargs < 2)
    1774           0 :         ereport(ERROR,
    1775             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1776             :                  errmsg("source data type and target data type are the same")));
    1777             : 
    1778             :     /* convert CoercionContext enum to char value for castcontext */
    1779         272 :     switch (stmt->context)
    1780             :     {
    1781          36 :         case COERCION_IMPLICIT:
    1782          36 :             castcontext = COERCION_CODE_IMPLICIT;
    1783          36 :             break;
    1784          58 :         case COERCION_ASSIGNMENT:
    1785          58 :             castcontext = COERCION_CODE_ASSIGNMENT;
    1786          58 :             break;
    1787             :             /* COERCION_PLPGSQL is intentionally not covered here */
    1788         178 :         case COERCION_EXPLICIT:
    1789         178 :             castcontext = COERCION_CODE_EXPLICIT;
    1790         178 :             break;
    1791           0 :         default:
    1792           0 :             elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
    1793             :             castcontext = 0;    /* keep compiler quiet */
    1794             :             break;
    1795             :     }
    1796             : 
    1797         272 :     myself = CastCreate(sourcetypeid, targettypeid, funcid, incastid, outcastid,
    1798             :                         castcontext, castmethod, DEPENDENCY_NORMAL);
    1799         272 :     return myself;
    1800             : }
    1801             : 
    1802             : 
    1803             : static void
    1804          80 : check_transform_function(Form_pg_proc procstruct)
    1805             : {
    1806          80 :     if (procstruct->provolatile == PROVOLATILE_VOLATILE)
    1807           0 :         ereport(ERROR,
    1808             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1809             :                  errmsg("transform function must not be volatile")));
    1810          80 :     if (procstruct->prokind != PROKIND_FUNCTION)
    1811           0 :         ereport(ERROR,
    1812             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1813             :                  errmsg("transform function must be a normal function")));
    1814          80 :     if (procstruct->proretset)
    1815           0 :         ereport(ERROR,
    1816             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1817             :                  errmsg("transform function must not return a set")));
    1818          80 :     if (procstruct->pronargs != 1)
    1819           0 :         ereport(ERROR,
    1820             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1821             :                  errmsg("transform function must take one argument")));
    1822          80 :     if (procstruct->proargtypes.values[0] != INTERNALOID)
    1823           2 :         ereport(ERROR,
    1824             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1825             :                  errmsg("first argument of transform function must be type %s",
    1826             :                         "internal")));
    1827          78 : }
    1828             : 
    1829             : 
    1830             : /*
    1831             :  * CREATE TRANSFORM
    1832             :  */
    1833             : ObjectAddress
    1834          50 : CreateTransform(CreateTransformStmt *stmt)
    1835             : {
    1836             :     Oid         typeid;
    1837             :     char        typtype;
    1838             :     Oid         langid;
    1839             :     Oid         fromsqlfuncid;
    1840             :     Oid         tosqlfuncid;
    1841             :     AclResult   aclresult;
    1842             :     Form_pg_proc procstruct;
    1843             :     Datum       values[Natts_pg_transform];
    1844          50 :     bool        nulls[Natts_pg_transform] = {0};
    1845          50 :     bool        replaces[Natts_pg_transform] = {0};
    1846             :     Oid         transformid;
    1847             :     HeapTuple   tuple;
    1848             :     HeapTuple   newtuple;
    1849             :     Relation    relation;
    1850             :     ObjectAddress myself,
    1851             :                 referenced;
    1852             :     ObjectAddresses *addrs;
    1853             :     bool        is_replace;
    1854             : 
    1855             :     /*
    1856             :      * Get the type
    1857             :      */
    1858          50 :     typeid = typenameTypeId(NULL, stmt->type_name);
    1859          48 :     typtype = get_typtype(typeid);
    1860             : 
    1861          48 :     if (typtype == TYPTYPE_PSEUDO)
    1862           0 :         ereport(ERROR,
    1863             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1864             :                  errmsg("data type %s is a pseudo-type",
    1865             :                         TypeNameToString(stmt->type_name))));
    1866             : 
    1867          48 :     if (typtype == TYPTYPE_DOMAIN)
    1868           0 :         ereport(ERROR,
    1869             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1870             :                  errmsg("data type %s is a domain",
    1871             :                         TypeNameToString(stmt->type_name))));
    1872             : 
    1873          48 :     if (!object_ownercheck(TypeRelationId, typeid, GetUserId()))
    1874           0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
    1875             : 
    1876          48 :     aclresult = object_aclcheck(TypeRelationId, typeid, GetUserId(), ACL_USAGE);
    1877          48 :     if (aclresult != ACLCHECK_OK)
    1878           0 :         aclcheck_error_type(aclresult, typeid);
    1879             : 
    1880             :     /*
    1881             :      * Get the language
    1882             :      */
    1883          48 :     langid = get_language_oid(stmt->lang, false);
    1884             : 
    1885          46 :     aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE);
    1886          46 :     if (aclresult != ACLCHECK_OK)
    1887           0 :         aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang);
    1888             : 
    1889             :     /*
    1890             :      * Get the functions
    1891             :      */
    1892          46 :     if (stmt->fromsql)
    1893             :     {
    1894          44 :         fromsqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->fromsql, false);
    1895             : 
    1896          44 :         if (!object_ownercheck(ProcedureRelationId, fromsqlfuncid, GetUserId()))
    1897           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
    1898             : 
    1899          44 :         aclresult = object_aclcheck(ProcedureRelationId, fromsqlfuncid, GetUserId(), ACL_EXECUTE);
    1900          44 :         if (aclresult != ACLCHECK_OK)
    1901           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
    1902             : 
    1903          44 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
    1904          44 :         if (!HeapTupleIsValid(tuple))
    1905           0 :             elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
    1906          44 :         procstruct = (Form_pg_proc) GETSTRUCT(tuple);
    1907          44 :         if (procstruct->prorettype != INTERNALOID)
    1908           2 :             ereport(ERROR,
    1909             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1910             :                      errmsg("return data type of FROM SQL function must be %s",
    1911             :                             "internal")));
    1912          42 :         check_transform_function(procstruct);
    1913          40 :         ReleaseSysCache(tuple);
    1914             :     }
    1915             :     else
    1916           2 :         fromsqlfuncid = InvalidOid;
    1917             : 
    1918          42 :     if (stmt->tosql)
    1919             :     {
    1920          38 :         tosqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->tosql, false);
    1921             : 
    1922          38 :         if (!object_ownercheck(ProcedureRelationId, tosqlfuncid, GetUserId()))
    1923           0 :             aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
    1924             : 
    1925          38 :         aclresult = object_aclcheck(ProcedureRelationId, tosqlfuncid, GetUserId(), ACL_EXECUTE);
    1926          38 :         if (aclresult != ACLCHECK_OK)
    1927           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
    1928             : 
    1929          38 :         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
    1930          38 :         if (!HeapTupleIsValid(tuple))
    1931           0 :             elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
    1932          38 :         procstruct = (Form_pg_proc) GETSTRUCT(tuple);
    1933          38 :         if (procstruct->prorettype != typeid)
    1934           0 :             ereport(ERROR,
    1935             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1936             :                      errmsg("return data type of TO SQL function must be the transform data type")));
    1937          38 :         check_transform_function(procstruct);
    1938          38 :         ReleaseSysCache(tuple);
    1939             :     }
    1940             :     else
    1941           4 :         tosqlfuncid = InvalidOid;
    1942             : 
    1943             :     /*
    1944             :      * Ready to go
    1945             :      */
    1946          42 :     values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
    1947          42 :     values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
    1948          42 :     values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
    1949          42 :     values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
    1950             : 
    1951          42 :     relation = table_open(TransformRelationId, RowExclusiveLock);
    1952             : 
    1953          42 :     tuple = SearchSysCache2(TRFTYPELANG,
    1954             :                             ObjectIdGetDatum(typeid),
    1955             :                             ObjectIdGetDatum(langid));
    1956          42 :     if (HeapTupleIsValid(tuple))
    1957             :     {
    1958           8 :         Form_pg_transform form = (Form_pg_transform) GETSTRUCT(tuple);
    1959             : 
    1960           8 :         if (!stmt->replace)
    1961           2 :             ereport(ERROR,
    1962             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1963             :                      errmsg("transform for type %s language \"%s\" already exists",
    1964             :                             format_type_be(typeid),
    1965             :                             stmt->lang)));
    1966             : 
    1967           6 :         replaces[Anum_pg_transform_trffromsql - 1] = true;
    1968           6 :         replaces[Anum_pg_transform_trftosql - 1] = true;
    1969             : 
    1970           6 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
    1971           6 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    1972             : 
    1973           6 :         transformid = form->oid;
    1974           6 :         ReleaseSysCache(tuple);
    1975           6 :         is_replace = true;
    1976             :     }
    1977             :     else
    1978             :     {
    1979          34 :         transformid = GetNewOidWithIndex(relation, TransformOidIndexId,
    1980             :                                          Anum_pg_transform_oid);
    1981          34 :         values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid);
    1982          34 :         newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
    1983          34 :         CatalogTupleInsert(relation, newtuple);
    1984          34 :         is_replace = false;
    1985             :     }
    1986             : 
    1987          40 :     if (is_replace)
    1988           6 :         deleteDependencyRecordsFor(TransformRelationId, transformid, true);
    1989             : 
    1990          40 :     addrs = new_object_addresses();
    1991             : 
    1992             :     /* make dependency entries */
    1993          40 :     ObjectAddressSet(myself, TransformRelationId, transformid);
    1994             : 
    1995             :     /* dependency on language */
    1996          40 :     ObjectAddressSet(referenced, LanguageRelationId, langid);
    1997          40 :     add_exact_object_address(&referenced, addrs);
    1998             : 
    1999             :     /* dependency on type */
    2000          40 :     ObjectAddressSet(referenced, TypeRelationId, typeid);
    2001          40 :     add_exact_object_address(&referenced, addrs);
    2002             : 
    2003             :     /* dependencies on functions */
    2004          40 :     if (OidIsValid(fromsqlfuncid))
    2005             :     {
    2006          38 :         ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
    2007          38 :         add_exact_object_address(&referenced, addrs);
    2008             :     }
    2009          40 :     if (OidIsValid(tosqlfuncid))
    2010             :     {
    2011          36 :         ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
    2012          36 :         add_exact_object_address(&referenced, addrs);
    2013             :     }
    2014             : 
    2015          40 :     record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
    2016          40 :     free_object_addresses(addrs);
    2017             : 
    2018             :     /* dependency on extension */
    2019          40 :     recordDependencyOnCurrentExtension(&myself, is_replace);
    2020             : 
    2021             :     /* Post creation hook for new transform */
    2022          40 :     InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
    2023             : 
    2024          40 :     heap_freetuple(newtuple);
    2025             : 
    2026          40 :     table_close(relation, RowExclusiveLock);
    2027             : 
    2028          40 :     return myself;
    2029             : }
    2030             : 
    2031             : 
    2032             : /*
    2033             :  * get_transform_oid - given type OID and language OID, look up a transform OID
    2034             :  *
    2035             :  * If missing_ok is false, throw an error if the transform is not found.  If
    2036             :  * true, just return InvalidOid.
    2037             :  */
    2038             : Oid
    2039         164 : get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
    2040             : {
    2041             :     Oid         oid;
    2042             : 
    2043         164 :     oid = GetSysCacheOid2(TRFTYPELANG, Anum_pg_transform_oid,
    2044             :                           ObjectIdGetDatum(type_id),
    2045             :                           ObjectIdGetDatum(lang_id));
    2046         164 :     if (!OidIsValid(oid) && !missing_ok)
    2047           0 :         ereport(ERROR,
    2048             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2049             :                  errmsg("transform for type %s language \"%s\" does not exist",
    2050             :                         format_type_be(type_id),
    2051             :                         get_language_name(lang_id, false))));
    2052         164 :     return oid;
    2053             : }
    2054             : 
    2055             : 
    2056             : /*
    2057             :  * Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA/RENAME
    2058             :  *
    2059             :  * Is there a function with the given name and signature already in the given
    2060             :  * namespace?  If so, raise an appropriate error message.
    2061             :  */
    2062             : void
    2063         136 : IsThereFunctionInNamespace(const char *proname, int pronargs,
    2064             :                            oidvector *proargtypes, Oid nspOid)
    2065             : {
    2066             :     /* check for duplicate name (more friendly than unique-index failure) */
    2067         136 :     if (SearchSysCacheExists3(PROCNAMEARGSNSP,
    2068             :                               CStringGetDatum(proname),
    2069             :                               PointerGetDatum(proargtypes),
    2070             :                               ObjectIdGetDatum(nspOid)))
    2071          24 :         ereport(ERROR,
    2072             :                 (errcode(ERRCODE_DUPLICATE_FUNCTION),
    2073             :                  errmsg("function %s already exists in schema \"%s\"",
    2074             :                         funcname_signature_string(proname, pronargs,
    2075             :                                                   NIL, proargtypes->values),
    2076             :                         get_namespace_name(nspOid))));
    2077         112 : }
    2078             : 
    2079             : /*
    2080             :  * ExecuteDoStmt
    2081             :  *      Execute inline procedural-language code
    2082             :  *
    2083             :  * See at ExecuteCallStmt() about the atomic argument.
    2084             :  */
    2085             : void
    2086        1594 : ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic)
    2087             : {
    2088        1594 :     InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
    2089             :     ListCell   *arg;
    2090        1594 :     DefElem    *as_item = NULL;
    2091        1594 :     DefElem    *language_item = NULL;
    2092             :     char       *language;
    2093             :     Oid         laninline;
    2094             :     HeapTuple   languageTuple;
    2095             :     Form_pg_language languageStruct;
    2096             : 
    2097             :     /* Process options we got from gram.y */
    2098        3386 :     foreach(arg, stmt->args)
    2099             :     {
    2100        1792 :         DefElem    *defel = (DefElem *) lfirst(arg);
    2101             : 
    2102        1792 :         if (strcmp(defel->defname, "as") == 0)
    2103             :         {
    2104        1594 :             if (as_item)
    2105           0 :                 errorConflictingDefElem(defel, pstate);
    2106        1594 :             as_item = defel;
    2107             :         }
    2108         198 :         else if (strcmp(defel->defname, "language") == 0)
    2109             :         {
    2110         198 :             if (language_item)
    2111           0 :                 errorConflictingDefElem(defel, pstate);
    2112         198 :             language_item = defel;
    2113             :         }
    2114             :         else
    2115           0 :             elog(ERROR, "option \"%s\" not recognized",
    2116             :                  defel->defname);
    2117             :     }
    2118             : 
    2119        1594 :     if (as_item)
    2120        1594 :         codeblock->source_text = strVal(as_item->arg);
    2121             :     else
    2122           0 :         ereport(ERROR,
    2123             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    2124             :                  errmsg("no inline code specified")));
    2125             : 
    2126             :     /* if LANGUAGE option wasn't specified, use the default */
    2127        1594 :     if (language_item)
    2128         198 :         language = strVal(language_item->arg);
    2129             :     else
    2130        1396 :         language = "plpgsql";
    2131             : 
    2132             :     /* Look up the language and validate permissions */
    2133        1594 :     languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
    2134        1594 :     if (!HeapTupleIsValid(languageTuple))
    2135           0 :         ereport(ERROR,
    2136             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2137             :                  errmsg("language \"%s\" does not exist", language),
    2138             :                  (extension_file_exists(language) ?
    2139             :                   errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
    2140             : 
    2141        1594 :     languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
    2142        1594 :     codeblock->langOid = languageStruct->oid;
    2143        1594 :     codeblock->langIsTrusted = languageStruct->lanpltrusted;
    2144        1594 :     codeblock->atomic = atomic;
    2145             : 
    2146        1594 :     if (languageStruct->lanpltrusted)
    2147             :     {
    2148             :         /* if trusted language, need USAGE privilege */
    2149             :         AclResult   aclresult;
    2150             : 
    2151        1550 :         aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(),
    2152             :                                     ACL_USAGE);
    2153        1550 :         if (aclresult != ACLCHECK_OK)
    2154           0 :             aclcheck_error(aclresult, OBJECT_LANGUAGE,
    2155           0 :                            NameStr(languageStruct->lanname));
    2156             :     }
    2157             :     else
    2158             :     {
    2159             :         /* if untrusted language, must be superuser */
    2160          44 :         if (!superuser())
    2161           0 :             aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE,
    2162           0 :                            NameStr(languageStruct->lanname));
    2163             :     }
    2164             : 
    2165             :     /* get the handler function's OID */
    2166        1594 :     laninline = languageStruct->laninline;
    2167        1594 :     if (!OidIsValid(laninline))
    2168           0 :         ereport(ERROR,
    2169             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2170             :                  errmsg("language \"%s\" does not support inline code execution",
    2171             :                         NameStr(languageStruct->lanname))));
    2172             : 
    2173        1594 :     ReleaseSysCache(languageTuple);
    2174             : 
    2175             :     /* execute the inline handler */
    2176        1594 :     OidFunctionCall1(laninline, PointerGetDatum(codeblock));
    2177        1186 : }
    2178             : 
    2179             : /*
    2180             :  * Execute CALL statement
    2181             :  *
    2182             :  * Inside a top-level CALL statement, transaction-terminating commands such as
    2183             :  * COMMIT or a PL-specific equivalent are allowed.  The terminology in the SQL
    2184             :  * standard is that CALL establishes a non-atomic execution context.  Most
    2185             :  * other commands establish an atomic execution context, in which transaction
    2186             :  * control actions are not allowed.  If there are nested executions of CALL,
    2187             :  * we want to track the execution context recursively, so that the nested
    2188             :  * CALLs can also do transaction control.  Note, however, that for example in
    2189             :  * CALL -> SELECT -> CALL, the second call cannot do transaction control,
    2190             :  * because the SELECT in between establishes an atomic execution context.
    2191             :  *
    2192             :  * So when ExecuteCallStmt() is called from the top level, we pass in atomic =
    2193             :  * false (recall that that means transactions = yes).  We then create a
    2194             :  * CallContext node with content atomic = false, which is passed in the
    2195             :  * fcinfo->context field to the procedure invocation.  The language
    2196             :  * implementation should then take appropriate measures to allow or prevent
    2197             :  * transaction commands based on that information, e.g., call
    2198             :  * SPI_connect_ext(SPI_OPT_NONATOMIC).  The language should also pass on the
    2199             :  * atomic flag to any nested invocations to CALL.
    2200             :  *
    2201             :  * The expression data structures and execution context that we create
    2202             :  * within this function are children of the portalContext of the Portal
    2203             :  * that the CALL utility statement runs in.  Therefore, any pass-by-ref
    2204             :  * values that we're passing to the procedure will survive transaction
    2205             :  * commits that might occur inside the procedure.
    2206             :  */
    2207             : void
    2208         492 : ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
    2209             : {
    2210         492 :     LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
    2211             :     ListCell   *lc;
    2212             :     FuncExpr   *fexpr;
    2213             :     int         nargs;
    2214             :     int         i;
    2215             :     AclResult   aclresult;
    2216             :     FmgrInfo    flinfo;
    2217             :     CallContext *callcontext;
    2218             :     EState     *estate;
    2219             :     ExprContext *econtext;
    2220             :     HeapTuple   tp;
    2221             :     PgStat_FunctionCallUsage fcusage;
    2222             :     Datum       retval;
    2223             : 
    2224         492 :     fexpr = stmt->funcexpr;
    2225             :     Assert(fexpr);
    2226             :     Assert(IsA(fexpr, FuncExpr));
    2227             : 
    2228         492 :     aclresult = object_aclcheck(ProcedureRelationId, fexpr->funcid, GetUserId(), ACL_EXECUTE);
    2229         492 :     if (aclresult != ACLCHECK_OK)
    2230          12 :         aclcheck_error(aclresult, OBJECT_PROCEDURE, get_func_name(fexpr->funcid));
    2231             : 
    2232             :     /* Prep the context object we'll pass to the procedure */
    2233         480 :     callcontext = makeNode(CallContext);
    2234         480 :     callcontext->atomic = atomic;
    2235             : 
    2236         480 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
    2237         480 :     if (!HeapTupleIsValid(tp))
    2238           0 :         elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
    2239             : 
    2240             :     /*
    2241             :      * If proconfig is set we can't allow transaction commands because of the
    2242             :      * way the GUC stacking works: The transaction boundary would have to pop
    2243             :      * the proconfig setting off the stack.  That restriction could be lifted
    2244             :      * by redesigning the GUC nesting mechanism a bit.
    2245             :      */
    2246         480 :     if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL))
    2247           2 :         callcontext->atomic = true;
    2248             : 
    2249             :     /*
    2250             :      * In security definer procedures, we can't allow transaction commands.
    2251             :      * StartTransaction() insists that the security context stack is empty,
    2252             :      * and AbortTransaction() resets the security context.  This could be
    2253             :      * reorganized, but right now it doesn't work.
    2254             :      */
    2255         480 :     if (((Form_pg_proc) GETSTRUCT(tp))->prosecdef)
    2256           2 :         callcontext->atomic = true;
    2257             : 
    2258         480 :     ReleaseSysCache(tp);
    2259             : 
    2260             :     /* safety check; see ExecInitFunc() */
    2261         480 :     nargs = list_length(fexpr->args);
    2262         480 :     if (nargs > FUNC_MAX_ARGS)
    2263           0 :         ereport(ERROR,
    2264             :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
    2265             :                  errmsg_plural("cannot pass more than %d argument to a procedure",
    2266             :                                "cannot pass more than %d arguments to a procedure",
    2267             :                                FUNC_MAX_ARGS,
    2268             :                                FUNC_MAX_ARGS)));
    2269             : 
    2270             :     /* Initialize function call structure */
    2271         480 :     InvokeFunctionExecuteHook(fexpr->funcid);
    2272         480 :     fmgr_info(fexpr->funcid, &flinfo);
    2273         480 :     fmgr_info_set_expr((Node *) fexpr, &flinfo);
    2274         480 :     InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
    2275             :                              (Node *) callcontext, NULL);
    2276             : 
    2277             :     /*
    2278             :      * Evaluate procedure arguments inside a suitable execution context.  Note
    2279             :      * we can't free this context till the procedure returns.
    2280             :      */
    2281         480 :     estate = CreateExecutorState();
    2282         480 :     estate->es_param_list_info = params;
    2283         480 :     econtext = CreateExprContext(estate);
    2284             : 
    2285             :     /*
    2286             :      * If we're called in non-atomic context, we also have to ensure that the
    2287             :      * argument expressions run with an up-to-date snapshot.  Our caller will
    2288             :      * have provided a current snapshot in atomic contexts, but not in
    2289             :      * non-atomic contexts, because the possibility of a COMMIT/ROLLBACK
    2290             :      * destroying the snapshot makes higher-level management too complicated.
    2291             :      */
    2292         480 :     if (!atomic)
    2293         442 :         PushActiveSnapshot(GetTransactionSnapshot());
    2294             : 
    2295         480 :     i = 0;
    2296        1116 :     foreach(lc, fexpr->args)
    2297             :     {
    2298             :         ExprState  *exprstate;
    2299             :         Datum       val;
    2300             :         bool        isnull;
    2301             : 
    2302         636 :         exprstate = ExecPrepareExpr(lfirst(lc), estate);
    2303             : 
    2304         636 :         val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
    2305             : 
    2306         636 :         fcinfo->args[i].value = val;
    2307         636 :         fcinfo->args[i].isnull = isnull;
    2308             : 
    2309         636 :         i++;
    2310             :     }
    2311             : 
    2312             :     /* Get rid of temporary snapshot for arguments, if we made one */
    2313         480 :     if (!atomic)
    2314         442 :         PopActiveSnapshot();
    2315             : 
    2316             :     /* Here we actually call the procedure */
    2317         480 :     pgstat_init_function_usage(fcinfo, &fcusage);
    2318         480 :     retval = FunctionCallInvoke(fcinfo);
    2319         448 :     pgstat_end_function_usage(&fcusage, true);
    2320             : 
    2321             :     /* Handle the procedure's outputs */
    2322         448 :     if (fexpr->funcresulttype == VOIDOID)
    2323             :     {
    2324             :         /* do nothing */
    2325             :     }
    2326         202 :     else if (fexpr->funcresulttype == RECORDOID)
    2327             :     {
    2328             :         /* send tuple to client */
    2329             :         HeapTupleHeader td;
    2330             :         Oid         tupType;
    2331             :         int32       tupTypmod;
    2332             :         TupleDesc   retdesc;
    2333             :         HeapTupleData rettupdata;
    2334             :         TupOutputState *tstate;
    2335             :         TupleTableSlot *slot;
    2336             : 
    2337         202 :         if (fcinfo->isnull)
    2338           0 :             elog(ERROR, "procedure returned null record");
    2339             : 
    2340             :         /*
    2341             :          * Ensure there's an active snapshot whilst we execute whatever's
    2342             :          * involved here.  Note that this is *not* sufficient to make the
    2343             :          * world safe for TOAST pointers to be included in the returned data:
    2344             :          * the referenced data could have gone away while we didn't hold a
    2345             :          * snapshot.  Hence, it's incumbent on PLs that can do COMMIT/ROLLBACK
    2346             :          * to not return TOAST pointers, unless those pointers were fetched
    2347             :          * after the last COMMIT/ROLLBACK in the procedure.
    2348             :          *
    2349             :          * XXX that is a really nasty, hard-to-test requirement.  Is there a
    2350             :          * way to remove it?
    2351             :          */
    2352         202 :         EnsurePortalSnapshotExists();
    2353             : 
    2354         202 :         td = DatumGetHeapTupleHeader(retval);
    2355         202 :         tupType = HeapTupleHeaderGetTypeId(td);
    2356         202 :         tupTypmod = HeapTupleHeaderGetTypMod(td);
    2357         202 :         retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    2358             : 
    2359         202 :         tstate = begin_tup_output_tupdesc(dest, retdesc,
    2360             :                                           &TTSOpsHeapTuple);
    2361             : 
    2362         202 :         rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
    2363         202 :         ItemPointerSetInvalid(&(rettupdata.t_self));
    2364         202 :         rettupdata.t_tableOid = InvalidOid;
    2365         202 :         rettupdata.t_data = td;
    2366             : 
    2367         202 :         slot = ExecStoreHeapTuple(&rettupdata, tstate->slot, false);
    2368         202 :         tstate->dest->receiveSlot(slot, tstate->dest);
    2369             : 
    2370         202 :         end_tup_output(tstate);
    2371             : 
    2372         202 :         ReleaseTupleDesc(retdesc);
    2373             :     }
    2374             :     else
    2375           0 :         elog(ERROR, "unexpected result type for procedure: %u",
    2376             :              fexpr->funcresulttype);
    2377             : 
    2378         448 :     FreeExecutorState(estate);
    2379         448 : }
    2380             : 
    2381             : /*
    2382             :  * Construct the tuple descriptor for a CALL statement return
    2383             :  */
    2384             : TupleDesc
    2385         196 : CallStmtResultDesc(CallStmt *stmt)
    2386             : {
    2387             :     FuncExpr   *fexpr;
    2388             :     HeapTuple   tuple;
    2389             :     TupleDesc   tupdesc;
    2390             : 
    2391         196 :     fexpr = stmt->funcexpr;
    2392             : 
    2393         196 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
    2394         196 :     if (!HeapTupleIsValid(tuple))
    2395           0 :         elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
    2396             : 
    2397         196 :     tupdesc = build_function_result_tupdesc_t(tuple);
    2398             : 
    2399         196 :     ReleaseSysCache(tuple);
    2400             : 
    2401             :     /*
    2402             :      * The result of build_function_result_tupdesc_t has the right column
    2403             :      * names, but it just has the declared output argument types, which is the
    2404             :      * wrong thing in polymorphic cases.  Get the correct types by examining
    2405             :      * stmt->outargs.  We intentionally keep the atttypmod as -1 and the
    2406             :      * attcollation as the type's default, since that's always the appropriate
    2407             :      * thing for function outputs; there's no point in considering any
    2408             :      * additional info available from outargs.  Note that tupdesc is null if
    2409             :      * there are no outargs.
    2410             :      */
    2411         196 :     if (tupdesc)
    2412             :     {
    2413             :         Assert(tupdesc->natts == list_length(stmt->outargs));
    2414         502 :         for (int i = 0; i < tupdesc->natts; i++)
    2415             :         {
    2416         306 :             Form_pg_attribute att = TupleDescAttr(tupdesc, i);
    2417         306 :             Node       *outarg = (Node *) list_nth(stmt->outargs, i);
    2418             : 
    2419         306 :             TupleDescInitEntry(tupdesc,
    2420         306 :                                i + 1,
    2421         306 :                                NameStr(att->attname),
    2422             :                                exprType(outarg),
    2423             :                                -1,
    2424             :                                0);
    2425             :         }
    2426             :     }
    2427             : 
    2428         196 :     return tupdesc;
    2429             : }

Generated by: LCOV version 1.16