LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 84.2 % 1164 980
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 20 20
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 47.0 % 1030 484

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

Generated by: LCOV version 2.3.2-1