LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 752 879 85.6 %
Date: 2025-01-18 04:15:08 Functions: 20 20 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14