LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 85.6 % 882 755
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 20 20
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 60.3 % 860 519

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

Generated by: LCOV version 2.0-1