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

Generated by: LCOV version 2.0-1