LCOV - code coverage report
Current view: top level - src/backend/commands - functioncmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 612 776 78.9 %
Date: 2017-09-29 15:12:54 Functions: 22 23 95.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11