LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 706 834 84.7 %
Date: 2020-06-01 08:06:25 Functions: 22 22 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13