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

Generated by: LCOV version 1.14