PostgreSQL Source Code  git master
functioncmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_transform.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "executor/execdesc.h"
#include "executor/executor.h"
#include "executor/functions.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "pgstat.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for functioncmds.c:

Go to the source code of this file.

Functions

static void compute_return_type (TypeName *returnType, Oid languageOid, Oid *prorettype_p, bool *returnsSet_p)
 
void interpret_function_parameter_list (ParseState *pstate, List *parameters, Oid languageOid, ObjectType objtype, oidvector **parameterTypes, List **parameterTypes_list, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **inParameterNames_list, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
 
static bool compute_common_attribute (ParseState *pstate, bool is_procedure, DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, DefElem **leakproof_item, List **set_items, DefElem **cost_item, DefElem **rows_item, DefElem **support_item, DefElem **parallel_item)
 
static char interpret_func_volatility (DefElem *defel)
 
static char interpret_func_parallel (DefElem *defel)
 
static ArrayTypeupdate_proconfig_value (ArrayType *a, List *set_items)
 
static Oid interpret_func_support (DefElem *defel)
 
static void compute_function_attributes (ParseState *pstate, bool is_procedure, List *options, List **as, char **language, Node **transform, bool *windowfunc_p, char *volatility_p, bool *strict_p, bool *security_definer, bool *leakproof_p, ArrayType **proconfig, float4 *procost, float4 *prorows, Oid *prosupport, char *parallel_p)
 
static void interpret_AS_clause (Oid languageOid, const char *languageName, char *funcname, List *as, Node *sql_body_in, List *parameterTypes, List *inParameterNames, char **prosrc_str_p, char **probin_str_p, Node **sql_body_out, const char *queryString)
 
ObjectAddress CreateFunction (ParseState *pstate, CreateFunctionStmt *stmt)
 
void RemoveFunctionById (Oid funcOid)
 
ObjectAddress AlterFunction (ParseState *pstate, AlterFunctionStmt *stmt)
 
ObjectAddress CreateCast (CreateCastStmt *stmt)
 
static void check_transform_function (Form_pg_proc procstruct)
 
ObjectAddress CreateTransform (CreateTransformStmt *stmt)
 
Oid get_transform_oid (Oid type_id, Oid lang_id, bool missing_ok)
 
void IsThereFunctionInNamespace (const char *proname, int pronargs, oidvector *proargtypes, Oid nspOid)
 
void ExecuteDoStmt (ParseState *pstate, DoStmt *stmt, bool atomic)
 
void ExecuteCallStmt (CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
 
TupleDesc CallStmtResultDesc (CallStmt *stmt)
 

Function Documentation

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)

Definition at line 1348 of file functioncmds.c.

1349 {
1350  HeapTuple tup;
1351  Oid funcOid;
1352  Form_pg_proc procForm;
1353  bool is_procedure;
1354  Relation rel;
1355  ListCell *l;
1356  DefElem *volatility_item = NULL;
1357  DefElem *strict_item = NULL;
1358  DefElem *security_def_item = NULL;
1359  DefElem *leakproof_item = NULL;
1360  List *set_items = NIL;
1361  DefElem *cost_item = NULL;
1362  DefElem *rows_item = NULL;
1363  DefElem *support_item = NULL;
1364  DefElem *parallel_item = NULL;
1365  ObjectAddress address;
1366 
1367  rel = table_open(ProcedureRelationId, RowExclusiveLock);
1368 
1369  funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1370 
1371  ObjectAddressSet(address, ProcedureRelationId, funcOid);
1372 
1373  tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1374  if (!HeapTupleIsValid(tup)) /* should not happen */
1375  elog(ERROR, "cache lookup failed for function %u", funcOid);
1376 
1377  procForm = (Form_pg_proc) GETSTRUCT(tup);
1378 
1379  /* Permission check: must own function */
1380  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
1382  NameListToString(stmt->func->objname));
1383 
1384  if (procForm->prokind == PROKIND_AGGREGATE)
1385  ereport(ERROR,
1386  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1387  errmsg("\"%s\" is an aggregate function",
1388  NameListToString(stmt->func->objname))));
1389 
1390  is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1391 
1392  /* Examine requested actions. */
1393  foreach(l, stmt->actions)
1394  {
1395  DefElem *defel = (DefElem *) lfirst(l);
1396 
1397  if (compute_common_attribute(pstate,
1398  is_procedure,
1399  defel,
1400  &volatility_item,
1401  &strict_item,
1402  &security_def_item,
1403  &leakproof_item,
1404  &set_items,
1405  &cost_item,
1406  &rows_item,
1407  &support_item,
1408  &parallel_item) == false)
1409  elog(ERROR, "option \"%s\" not recognized", defel->defname);
1410  }
1411 
1412  if (volatility_item)
1413  procForm->provolatile = interpret_func_volatility(volatility_item);
1414  if (strict_item)
1415  procForm->proisstrict = boolVal(strict_item->arg);
1416  if (security_def_item)
1417  procForm->prosecdef = boolVal(security_def_item->arg);
1418  if (leakproof_item)
1419  {
1420  procForm->proleakproof = boolVal(leakproof_item->arg);
1421  if (procForm->proleakproof && !superuser())
1422  ereport(ERROR,
1423  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1424  errmsg("only superuser can define a leakproof function")));
1425  }
1426  if (cost_item)
1427  {
1428  procForm->procost = defGetNumeric(cost_item);
1429  if (procForm->procost <= 0)
1430  ereport(ERROR,
1431  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1432  errmsg("COST must be positive")));
1433  }
1434  if (rows_item)
1435  {
1436  procForm->prorows = defGetNumeric(rows_item);
1437  if (procForm->prorows <= 0)
1438  ereport(ERROR,
1439  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1440  errmsg("ROWS must be positive")));
1441  if (!procForm->proretset)
1442  ereport(ERROR,
1443  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1444  errmsg("ROWS is not applicable when function does not return a set")));
1445  }
1446  if (support_item)
1447  {
1448  /* interpret_func_support handles the privilege check */
1449  Oid newsupport = interpret_func_support(support_item);
1450 
1451  /* Add or replace dependency on support function */
1452  if (OidIsValid(procForm->prosupport))
1453  changeDependencyFor(ProcedureRelationId, funcOid,
1454  ProcedureRelationId, procForm->prosupport,
1455  newsupport);
1456  else
1457  {
1458  ObjectAddress referenced;
1459 
1460  referenced.classId = ProcedureRelationId;
1461  referenced.objectId = newsupport;
1462  referenced.objectSubId = 0;
1463  recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
1464  }
1465 
1466  procForm->prosupport = newsupport;
1467  }
1468  if (parallel_item)
1469  procForm->proparallel = interpret_func_parallel(parallel_item);
1470  if (set_items)
1471  {
1472  Datum datum;
1473  bool isnull;
1474  ArrayType *a;
1475  Datum repl_val[Natts_pg_proc];
1476  bool repl_null[Natts_pg_proc];
1477  bool repl_repl[Natts_pg_proc];
1478 
1479  /* extract existing proconfig setting */
1480  datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1481  a = isnull ? NULL : DatumGetArrayTypeP(datum);
1482 
1483  /* update according to each SET or RESET item, left to right */
1484  a = update_proconfig_value(a, set_items);
1485 
1486  /* update the tuple */
1487  memset(repl_repl, false, sizeof(repl_repl));
1488  repl_repl[Anum_pg_proc_proconfig - 1] = true;
1489 
1490  if (a == NULL)
1491  {
1492  repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1493  repl_null[Anum_pg_proc_proconfig - 1] = true;
1494  }
1495  else
1496  {
1497  repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1498  repl_null[Anum_pg_proc_proconfig - 1] = false;
1499  }
1500 
1501  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1502  repl_val, repl_null, repl_repl);
1503  }
1504  /* DO NOT put more touches of procForm below here; it's now dangling. */
1505 
1506  /* Do the update */
1507  CatalogTupleUpdate(rel, &tup->t_self, tup);
1508 
1509  InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1510 
1511  table_close(rel, NoLock);
1512  heap_freetuple(tup);
1513 
1514  return address;
1515 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4799
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define OidIsValid(objectId)
Definition: c.h:711
double defGetNumeric(DefElem *def)
Definition: define.c:82
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
static ArrayType * update_proconfig_value(ArrayType *a, List *set_items)
Definition: functioncmds.c:650
static Oid interpret_func_support(DefElem *defel)
Definition: functioncmds.c:675
static bool compute_common_attribute(ParseState *pstate, bool is_procedure, DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, DefElem **leakproof_item, List **set_items, DefElem **cost_item, DefElem **rows_item, DefElem **support_item, DefElem **parallel_item)
Definition: functioncmds.c:505
static char interpret_func_volatility(DefElem *defel)
Definition: functioncmds.c:607
static char interpret_func_parallel(DefElem *defel)
Definition: functioncmds.c:625
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
int a
Definition: isn.c:69
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:497
char * NameListToString(List *names)
Definition: namespace.c:3145
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2208
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:456
#define lfirst(lc)
Definition: pg_list.h:170
#define NIL
Definition: pg_list.h:66
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
ObjectWithArgs * func
Definition: parsenodes.h:3107
ObjectType objtype
Definition: parsenodes.h:3106
char * defname
Definition: parsenodes.h:779
Node * arg
Definition: parsenodes.h:780
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:52
bool superuser(void)
Definition: superuser.c:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ PROCOID
Definition: syscache.h:79
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
#define boolVal(v)
Definition: value.h:81

References a, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterFunctionStmt::actions, DefElem::arg, boolVal, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, compute_common_attribute(), DatumGetArrayTypeP, defGetNumeric(), DefElem::defname, DEPENDENCY_NORMAL, elog(), ereport, errcode(), errmsg(), ERROR, AlterFunctionStmt::func, GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, interpret_func_parallel(), interpret_func_support(), interpret_func_volatility(), InvokeObjectPostAlterHook, lfirst, LookupFuncWithArgs(), NameListToString(), NIL, NoLock, object_ownercheck(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, ObjectWithArgs::objname, AlterFunctionStmt::objtype, OidIsValid, PointerGetDatum(), PROCOID, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and update_proconfig_value().

Referenced by ProcessUtilitySlow().

◆ CallStmtResultDesc()

TupleDesc CallStmtResultDesc ( CallStmt stmt)

Definition at line 2353 of file functioncmds.c.

2354 {
2355  FuncExpr *fexpr;
2356  HeapTuple tuple;
2357  TupleDesc tupdesc;
2358 
2359  fexpr = stmt->funcexpr;
2360 
2361  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2362  if (!HeapTupleIsValid(tuple))
2363  elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
2364 
2365  tupdesc = build_function_result_tupdesc_t(tuple);
2366 
2367  ReleaseSysCache(tuple);
2368 
2369  return tupdesc;
2370 }
TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple)
Definition: funcapi.c:1702
FuncExpr * funcexpr
Definition: parsenodes.h:3147
Oid funcid
Definition: primnodes.h:598
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173

References build_function_result_tupdesc_t(), elog(), ERROR, CallStmt::funcexpr, FuncExpr::funcid, HeapTupleIsValid, ObjectIdGetDatum(), PROCOID, ReleaseSysCache(), and SearchSysCache1().

Referenced by UtilityTupleDescriptor().

◆ check_transform_function()

static void check_transform_function ( Form_pg_proc  procstruct)
static

Definition at line 1772 of file functioncmds.c.

1773 {
1774  if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1775  ereport(ERROR,
1776  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1777  errmsg("transform function must not be volatile")));
1778  if (procstruct->prokind != PROKIND_FUNCTION)
1779  ereport(ERROR,
1780  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1781  errmsg("transform function must be a normal function")));
1782  if (procstruct->proretset)
1783  ereport(ERROR,
1784  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1785  errmsg("transform function must not return a set")));
1786  if (procstruct->pronargs != 1)
1787  ereport(ERROR,
1788  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1789  errmsg("transform function must take one argument")));
1790  if (procstruct->proargtypes.values[0] != INTERNALOID)
1791  ereport(ERROR,
1792  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1793  errmsg("first argument of transform function must be type %s",
1794  "internal")));
1795 }

References ereport, errcode(), errmsg(), and ERROR.

Referenced by CreateTransform().

◆ compute_common_attribute()

static bool compute_common_attribute ( ParseState pstate,
bool  is_procedure,
DefElem defel,
DefElem **  volatility_item,
DefElem **  strict_item,
DefElem **  security_item,
DefElem **  leakproof_item,
List **  set_items,
DefElem **  cost_item,
DefElem **  rows_item,
DefElem **  support_item,
DefElem **  parallel_item 
)
static

Definition at line 505 of file functioncmds.c.

517 {
518  if (strcmp(defel->defname, "volatility") == 0)
519  {
520  if (is_procedure)
521  goto procedure_error;
522  if (*volatility_item)
523  errorConflictingDefElem(defel, pstate);
524 
525  *volatility_item = defel;
526  }
527  else if (strcmp(defel->defname, "strict") == 0)
528  {
529  if (is_procedure)
530  goto procedure_error;
531  if (*strict_item)
532  errorConflictingDefElem(defel, pstate);
533 
534  *strict_item = defel;
535  }
536  else if (strcmp(defel->defname, "security") == 0)
537  {
538  if (*security_item)
539  errorConflictingDefElem(defel, pstate);
540 
541  *security_item = defel;
542  }
543  else if (strcmp(defel->defname, "leakproof") == 0)
544  {
545  if (is_procedure)
546  goto procedure_error;
547  if (*leakproof_item)
548  errorConflictingDefElem(defel, pstate);
549 
550  *leakproof_item = defel;
551  }
552  else if (strcmp(defel->defname, "set") == 0)
553  {
554  *set_items = lappend(*set_items, defel->arg);
555  }
556  else if (strcmp(defel->defname, "cost") == 0)
557  {
558  if (is_procedure)
559  goto procedure_error;
560  if (*cost_item)
561  errorConflictingDefElem(defel, pstate);
562 
563  *cost_item = defel;
564  }
565  else if (strcmp(defel->defname, "rows") == 0)
566  {
567  if (is_procedure)
568  goto procedure_error;
569  if (*rows_item)
570  errorConflictingDefElem(defel, pstate);
571 
572  *rows_item = defel;
573  }
574  else if (strcmp(defel->defname, "support") == 0)
575  {
576  if (is_procedure)
577  goto procedure_error;
578  if (*support_item)
579  errorConflictingDefElem(defel, pstate);
580 
581  *support_item = defel;
582  }
583  else if (strcmp(defel->defname, "parallel") == 0)
584  {
585  if (is_procedure)
586  goto procedure_error;
587  if (*parallel_item)
588  errorConflictingDefElem(defel, pstate);
589 
590  *parallel_item = defel;
591  }
592  else
593  return false;
594 
595  /* Recognized an option */
596  return true;
597 
598 procedure_error:
599  ereport(ERROR,
600  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601  errmsg("invalid attribute in procedure definition"),
602  parser_errposition(pstate, defel->location)));
603  return false;
604 }
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
List * lappend(List *list, void *datum)
Definition: list.c:338
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
int location
Definition: parsenodes.h:783

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), lappend(), DefElem::location, and parser_errposition().

Referenced by AlterFunction(), and compute_function_attributes().

◆ compute_function_attributes()

static void compute_function_attributes ( ParseState pstate,
bool  is_procedure,
List options,
List **  as,
char **  language,
Node **  transform,
bool windowfunc_p,
char *  volatility_p,
bool strict_p,
bool security_definer,
bool leakproof_p,
ArrayType **  proconfig,
float4 procost,
float4 prorows,
Oid prosupport,
char *  parallel_p 
)
static

Definition at line 719 of file functioncmds.c.

735 {
736  ListCell *option;
737  DefElem *as_item = NULL;
738  DefElem *language_item = NULL;
739  DefElem *transform_item = NULL;
740  DefElem *windowfunc_item = NULL;
741  DefElem *volatility_item = NULL;
742  DefElem *strict_item = NULL;
743  DefElem *security_item = NULL;
744  DefElem *leakproof_item = NULL;
745  List *set_items = NIL;
746  DefElem *cost_item = NULL;
747  DefElem *rows_item = NULL;
748  DefElem *support_item = NULL;
749  DefElem *parallel_item = NULL;
750 
751  foreach(option, options)
752  {
753  DefElem *defel = (DefElem *) lfirst(option);
754 
755  if (strcmp(defel->defname, "as") == 0)
756  {
757  if (as_item)
758  errorConflictingDefElem(defel, pstate);
759  as_item = defel;
760  }
761  else if (strcmp(defel->defname, "language") == 0)
762  {
763  if (language_item)
764  errorConflictingDefElem(defel, pstate);
765  language_item = defel;
766  }
767  else if (strcmp(defel->defname, "transform") == 0)
768  {
769  if (transform_item)
770  errorConflictingDefElem(defel, pstate);
771  transform_item = defel;
772  }
773  else if (strcmp(defel->defname, "window") == 0)
774  {
775  if (windowfunc_item)
776  errorConflictingDefElem(defel, pstate);
777  if (is_procedure)
778  ereport(ERROR,
779  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
780  errmsg("invalid attribute in procedure definition"),
781  parser_errposition(pstate, defel->location)));
782  windowfunc_item = defel;
783  }
784  else if (compute_common_attribute(pstate,
785  is_procedure,
786  defel,
787  &volatility_item,
788  &strict_item,
789  &security_item,
790  &leakproof_item,
791  &set_items,
792  &cost_item,
793  &rows_item,
794  &support_item,
795  &parallel_item))
796  {
797  /* recognized common option */
798  continue;
799  }
800  else
801  elog(ERROR, "option \"%s\" not recognized",
802  defel->defname);
803  }
804 
805  if (as_item)
806  *as = (List *) as_item->arg;
807  if (language_item)
808  *language = strVal(language_item->arg);
809  if (transform_item)
810  *transform = transform_item->arg;
811  if (windowfunc_item)
812  *windowfunc_p = boolVal(windowfunc_item->arg);
813  if (volatility_item)
814  *volatility_p = interpret_func_volatility(volatility_item);
815  if (strict_item)
816  *strict_p = boolVal(strict_item->arg);
817  if (security_item)
818  *security_definer = boolVal(security_item->arg);
819  if (leakproof_item)
820  *leakproof_p = boolVal(leakproof_item->arg);
821  if (set_items)
822  *proconfig = update_proconfig_value(NULL, set_items);
823  if (cost_item)
824  {
825  *procost = defGetNumeric(cost_item);
826  if (*procost <= 0)
827  ereport(ERROR,
828  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
829  errmsg("COST must be positive")));
830  }
831  if (rows_item)
832  {
833  *prorows = defGetNumeric(rows_item);
834  if (*prorows <= 0)
835  ereport(ERROR,
836  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
837  errmsg("ROWS must be positive")));
838  }
839  if (support_item)
840  *prosupport = interpret_func_support(support_item);
841  if (parallel_item)
842  *parallel_p = interpret_func_parallel(parallel_item);
843 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define strVal(v)
Definition: value.h:82

References DefElem::arg, boolVal, compute_common_attribute(), defGetNumeric(), DefElem::defname, elog(), ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), if(), interpret_func_parallel(), interpret_func_support(), interpret_func_volatility(), lfirst, DefElem::location, NIL, parser_errposition(), strVal, and update_proconfig_value().

Referenced by CreateFunction().

◆ compute_return_type()

static void compute_return_type ( TypeName returnType,
Oid  languageOid,
Oid prorettype_p,
bool returnsSet_p 
)
static

Definition at line 93 of file functioncmds.c.

95 {
96  Oid rettype;
97  Type typtup;
98  AclResult aclresult;
99 
100  typtup = LookupTypeName(NULL, returnType, NULL, false);
101 
102  if (typtup)
103  {
104  if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
105  {
106  if (languageOid == SQLlanguageId)
107  ereport(ERROR,
108  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
109  errmsg("SQL function cannot return shell type %s",
110  TypeNameToString(returnType))));
111  else
112  ereport(NOTICE,
113  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
114  errmsg("return type %s is only a shell",
115  TypeNameToString(returnType))));
116  }
117  rettype = typeTypeId(typtup);
118  ReleaseSysCache(typtup);
119  }
120  else
121  {
122  char *typnam = TypeNameToString(returnType);
123  Oid namespaceId;
124  char *typname;
125  ObjectAddress address;
126 
127  /*
128  * Only C-coded functions can be I/O functions. We enforce this
129  * restriction here mainly to prevent littering the catalogs with
130  * shell types due to simple typos in user-defined function
131  * definitions.
132  */
133  if (languageOid != INTERNALlanguageId &&
134  languageOid != ClanguageId)
135  ereport(ERROR,
136  (errcode(ERRCODE_UNDEFINED_OBJECT),
137  errmsg("type \"%s\" does not exist", typnam)));
138 
139  /* Reject if there's typmod decoration, too */
140  if (returnType->typmods != NIL)
141  ereport(ERROR,
142  (errcode(ERRCODE_SYNTAX_ERROR),
143  errmsg("type modifier cannot be specified for shell type \"%s\"",
144  typnam)));
145 
146  /* Otherwise, go ahead and make a shell type */
147  ereport(NOTICE,
148  (errcode(ERRCODE_UNDEFINED_OBJECT),
149  errmsg("type \"%s\" is not yet defined", typnam),
150  errdetail("Creating a shell type definition.")));
151  namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
152  &typname);
153  aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(),
154  ACL_CREATE);
155  if (aclresult != ACLCHECK_OK)
156  aclcheck_error(aclresult, OBJECT_SCHEMA,
157  get_namespace_name(namespaceId));
158  address = TypeShellMake(typname, namespaceId, GetUserId());
159  rettype = address.objectId;
160  Assert(OidIsValid(rettype));
161  }
162 
163  aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
164  if (aclresult != ACLCHECK_OK)
165  aclcheck_error_type(aclresult, rettype);
166 
167  *prorettype_p = rettype;
168  *returnsSet_p = returnType->setof;
169 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3804
int errdetail(const char *fmt,...)
Definition: elog.c:1039
#define NOTICE
Definition: elog.h:31
Assert(fmt[strlen(fmt) - 1] !='\n')
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3038
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:38
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:478
Oid typeTypeId(Type tp)
Definition: parse_type.c:590
#define ACL_USAGE
Definition: parsenodes.h:91
@ OBJECT_SCHEMA
Definition: parsenodes.h:1924
#define ACL_CREATE
Definition: parsenodes.h:92
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:58
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
NameData typname
Definition: pg_type.h:41
bool setof
Definition: parsenodes.h:237
List * names
Definition: parsenodes.h:235
List * typmods
Definition: parsenodes.h:239

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, Assert(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_namespace_name(), GETSTRUCT, GetUserId(), LookupTypeName(), TypeName::names, NIL, NOTICE, object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, OidIsValid, QualifiedNameGetCreationNamespace(), ReleaseSysCache(), TypeName::setof, TypeNameToString(), TypeShellMake(), typeTypeId(), TypeName::typmods, and typname.

Referenced by CreateFunction().

◆ CreateCast()

ObjectAddress CreateCast ( CreateCastStmt stmt)

Definition at line 1522 of file functioncmds.c.

1523 {
1524  Oid sourcetypeid;
1525  Oid targettypeid;
1526  char sourcetyptype;
1527  char targettyptype;
1528  Oid funcid;
1529  Oid incastid = InvalidOid;
1530  Oid outcastid = InvalidOid;
1531  int nargs;
1532  char castcontext;
1533  char castmethod;
1534  HeapTuple tuple;
1535  AclResult aclresult;
1536  ObjectAddress myself;
1537 
1538  sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
1539  targettypeid = typenameTypeId(NULL, stmt->targettype);
1540  sourcetyptype = get_typtype(sourcetypeid);
1541  targettyptype = get_typtype(targettypeid);
1542 
1543  /* No pseudo-types allowed */
1544  if (sourcetyptype == TYPTYPE_PSEUDO)
1545  ereport(ERROR,
1546  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1547  errmsg("source data type %s is a pseudo-type",
1548  TypeNameToString(stmt->sourcetype))));
1549 
1550  if (targettyptype == TYPTYPE_PSEUDO)
1551  ereport(ERROR,
1552  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1553  errmsg("target data type %s is a pseudo-type",
1554  TypeNameToString(stmt->targettype))));
1555 
1556  /* Permission check */
1557  if (!object_ownercheck(TypeRelationId, sourcetypeid, GetUserId())
1558  && !object_ownercheck(TypeRelationId, targettypeid, GetUserId()))
1559  ereport(ERROR,
1560  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1561  errmsg("must be owner of type %s or type %s",
1562  format_type_be(sourcetypeid),
1563  format_type_be(targettypeid))));
1564 
1565  aclresult = object_aclcheck(TypeRelationId, sourcetypeid, GetUserId(), ACL_USAGE);
1566  if (aclresult != ACLCHECK_OK)
1567  aclcheck_error_type(aclresult, sourcetypeid);
1568 
1569  aclresult = object_aclcheck(TypeRelationId, targettypeid, GetUserId(), ACL_USAGE);
1570  if (aclresult != ACLCHECK_OK)
1571  aclcheck_error_type(aclresult, targettypeid);
1572 
1573  /* Domains are allowed for historical reasons, but we warn */
1574  if (sourcetyptype == TYPTYPE_DOMAIN)
1575  ereport(WARNING,
1576  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1577  errmsg("cast will be ignored because the source data type is a domain")));
1578 
1579  else if (targettyptype == TYPTYPE_DOMAIN)
1580  ereport(WARNING,
1581  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1582  errmsg("cast will be ignored because the target data type is a domain")));
1583 
1584  /* Determine the cast method */
1585  if (stmt->func != NULL)
1586  castmethod = COERCION_METHOD_FUNCTION;
1587  else if (stmt->inout)
1588  castmethod = COERCION_METHOD_INOUT;
1589  else
1590  castmethod = COERCION_METHOD_BINARY;
1591 
1592  if (castmethod == COERCION_METHOD_FUNCTION)
1593  {
1594  Form_pg_proc procstruct;
1595 
1596  funcid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->func, false);
1597 
1598  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1599  if (!HeapTupleIsValid(tuple))
1600  elog(ERROR, "cache lookup failed for function %u", funcid);
1601 
1602  procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1603  nargs = procstruct->pronargs;
1604  if (nargs < 1 || nargs > 3)
1605  ereport(ERROR,
1606  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1607  errmsg("cast function must take one to three arguments")));
1608  if (!IsBinaryCoercibleWithCast(sourcetypeid,
1609  procstruct->proargtypes.values[0],
1610  &incastid))
1611  ereport(ERROR,
1612  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1613  errmsg("argument of cast function must match or be binary-coercible from source data type")));
1614  if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
1615  ereport(ERROR,
1616  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1617  errmsg("second argument of cast function must be type %s",
1618  "integer")));
1619  if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
1620  ereport(ERROR,
1621  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1622  errmsg("third argument of cast function must be type %s",
1623  "boolean")));
1624  if (!IsBinaryCoercibleWithCast(procstruct->prorettype,
1625  targettypeid,
1626  &outcastid))
1627  ereport(ERROR,
1628  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1629  errmsg("return data type of cast function must match or be binary-coercible to target data type")));
1630 
1631  /*
1632  * Restricting the volatility of a cast function may or may not be a
1633  * good idea in the abstract, but it definitely breaks many old
1634  * user-defined types. Disable this check --- tgl 2/1/03
1635  */
1636 #ifdef NOT_USED
1637  if (procstruct->provolatile == PROVOLATILE_VOLATILE)
1638  ereport(ERROR,
1639  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1640  errmsg("cast function must not be volatile")));
1641 #endif
1642  if (procstruct->prokind != PROKIND_FUNCTION)
1643  ereport(ERROR,
1644  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1645  errmsg("cast function must be a normal function")));
1646  if (procstruct->proretset)
1647  ereport(ERROR,
1648  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1649  errmsg("cast function must not return a set")));
1650 
1651  ReleaseSysCache(tuple);
1652  }
1653  else
1654  {
1655  funcid = InvalidOid;
1656  nargs = 0;
1657  }
1658 
1659  if (castmethod == COERCION_METHOD_BINARY)
1660  {
1661  int16 typ1len;
1662  int16 typ2len;
1663  bool typ1byval;
1664  bool typ2byval;
1665  char typ1align;
1666  char typ2align;
1667 
1668  /*
1669  * Must be superuser to create binary-compatible casts, since
1670  * erroneous casts can easily crash the backend.
1671  */
1672  if (!superuser())
1673  ereport(ERROR,
1674  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1675  errmsg("must be superuser to create a cast WITHOUT FUNCTION")));
1676 
1677  /*
1678  * Also, insist that the types match as to size, alignment, and
1679  * pass-by-value attributes; this provides at least a crude check that
1680  * they have similar representations. A pair of types that fail this
1681  * test should certainly not be equated.
1682  */
1683  get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
1684  get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
1685  if (typ1len != typ2len ||
1686  typ1byval != typ2byval ||
1687  typ1align != typ2align)
1688  ereport(ERROR,
1689  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1690  errmsg("source and target data types are not physically compatible")));
1691 
1692  /*
1693  * We know that composite, enum and array types are never binary-
1694  * compatible with each other. They all have OIDs embedded in them.
1695  *
1696  * Theoretically you could build a user-defined base type that is
1697  * binary-compatible with a composite, enum, or array type. But we
1698  * disallow that too, as in practice such a cast is surely a mistake.
1699  * You can always work around that by writing a cast function.
1700  */
1701  if (sourcetyptype == TYPTYPE_COMPOSITE ||
1702  targettyptype == TYPTYPE_COMPOSITE)
1703  ereport(ERROR,
1704  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1705  errmsg("composite data types are not binary-compatible")));
1706 
1707  if (sourcetyptype == TYPTYPE_ENUM ||
1708  targettyptype == TYPTYPE_ENUM)
1709  ereport(ERROR,
1710  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1711  errmsg("enum data types are not binary-compatible")));
1712 
1713  if (OidIsValid(get_element_type(sourcetypeid)) ||
1714  OidIsValid(get_element_type(targettypeid)))
1715  ereport(ERROR,
1716  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1717  errmsg("array data types are not binary-compatible")));
1718 
1719  /*
1720  * We also disallow creating binary-compatibility casts involving
1721  * domains. Casting from a domain to its base type is already
1722  * allowed, and casting the other way ought to go through domain
1723  * coercion to permit constraint checking. Again, if you're intent on
1724  * having your own semantics for that, create a no-op cast function.
1725  *
1726  * NOTE: if we were to relax this, the above checks for composites
1727  * etc. would have to be modified to look through domains to their
1728  * base types.
1729  */
1730  if (sourcetyptype == TYPTYPE_DOMAIN ||
1731  targettyptype == TYPTYPE_DOMAIN)
1732  ereport(ERROR,
1733  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1734  errmsg("domain data types must not be marked binary-compatible")));
1735  }
1736 
1737  /*
1738  * Allow source and target types to be same only for length coercion
1739  * functions. We assume a multi-arg function does length coercion.
1740  */
1741  if (sourcetypeid == targettypeid && nargs < 2)
1742  ereport(ERROR,
1743  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1744  errmsg("source data type and target data type are the same")));
1745 
1746  /* convert CoercionContext enum to char value for castcontext */
1747  switch (stmt->context)
1748  {
1749  case COERCION_IMPLICIT:
1750  castcontext = COERCION_CODE_IMPLICIT;
1751  break;
1752  case COERCION_ASSIGNMENT:
1753  castcontext = COERCION_CODE_ASSIGNMENT;
1754  break;
1755  /* COERCION_PLPGSQL is intentionally not covered here */
1756  case COERCION_EXPLICIT:
1757  castcontext = COERCION_CODE_EXPLICIT;
1758  break;
1759  default:
1760  elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
1761  castcontext = 0; /* keep compiler quiet */
1762  break;
1763  }
1764 
1765  myself = CastCreate(sourcetypeid, targettypeid, funcid, incastid, outcastid,
1766  castcontext, castmethod, DEPENDENCY_NORMAL);
1767  return myself;
1768 }
signed short int16
Definition: c.h:429
#define WARNING
Definition: elog.h:32
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2717
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2229
char get_typtype(Oid typid)
Definition: lsyscache.c:2587
bool IsBinaryCoercibleWithCast(Oid srctype, Oid targettype, Oid *castoid)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
@ OBJECT_FUNCTION
Definition: parsenodes.h:1907
ObjectAddress CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, Oid incastid, Oid outcastid, char castcontext, char castmethod, DependencyType behavior)
Definition: pg_cast.c:49
#define InvalidOid
Definition: postgres_ext.h:36
@ COERCION_ASSIGNMENT
Definition: primnodes.h:567
@ COERCION_EXPLICIT
Definition: primnodes.h:569
@ COERCION_IMPLICIT
Definition: primnodes.h:566
TypeName * sourcetype
Definition: parsenodes.h:3639
TypeName * targettype
Definition: parsenodes.h:3640
CoercionContext context
Definition: parsenodes.h:3642
ObjectWithArgs * func
Definition: parsenodes.h:3641

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, CastCreate(), COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, CreateCastStmt::context, DEPENDENCY_NORMAL, elog(), ereport, errcode(), errmsg(), ERROR, format_type_be(), CreateCastStmt::func, get_element_type(), get_typlenbyvalalign(), get_typtype(), GETSTRUCT, GetUserId(), HeapTupleIsValid, CreateCastStmt::inout, InvalidOid, IsBinaryCoercibleWithCast(), LookupFuncWithArgs(), object_aclcheck(), OBJECT_FUNCTION, object_ownercheck(), ObjectIdGetDatum(), OidIsValid, PROCOID, ReleaseSysCache(), SearchSysCache1(), CreateCastStmt::sourcetype, superuser(), CreateCastStmt::targettype, TypeNameToString(), typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ CreateFunction()

ObjectAddress CreateFunction ( ParseState pstate,
CreateFunctionStmt stmt 
)

Definition at line 1016 of file functioncmds.c.

1017 {
1018  char *probin_str;
1019  char *prosrc_str;
1020  Node *prosqlbody;
1021  Oid prorettype;
1022  bool returnsSet;
1023  char *language;
1024  Oid languageOid;
1025  Oid languageValidator;
1026  Node *transformDefElem = NULL;
1027  char *funcname;
1028  Oid namespaceId;
1029  AclResult aclresult;
1030  oidvector *parameterTypes;
1031  List *parameterTypes_list = NIL;
1032  ArrayType *allParameterTypes;
1033  ArrayType *parameterModes;
1034  ArrayType *parameterNames;
1035  List *inParameterNames_list = NIL;
1036  List *parameterDefaults;
1037  Oid variadicArgType;
1038  List *trftypes_list = NIL;
1039  ArrayType *trftypes;
1040  Oid requiredResultType;
1041  bool isWindowFunc,
1042  isStrict,
1043  security,
1044  isLeakProof;
1045  char volatility;
1046  ArrayType *proconfig;
1047  float4 procost;
1048  float4 prorows;
1049  Oid prosupport;
1050  HeapTuple languageTuple;
1051  Form_pg_language languageStruct;
1052  List *as_clause;
1053  char parallel;
1054 
1055  /* Convert list of names to a name and namespace */
1056  namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
1057  &funcname);
1058 
1059  /* Check we have creation rights in target namespace */
1060  aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(), ACL_CREATE);
1061  if (aclresult != ACLCHECK_OK)
1062  aclcheck_error(aclresult, OBJECT_SCHEMA,
1063  get_namespace_name(namespaceId));
1064 
1065  /* Set default attributes */
1066  as_clause = NIL;
1067  language = NULL;
1068  isWindowFunc = false;
1069  isStrict = false;
1070  security = false;
1071  isLeakProof = false;
1072  volatility = PROVOLATILE_VOLATILE;
1073  proconfig = NULL;
1074  procost = -1; /* indicates not set */
1075  prorows = -1; /* indicates not set */
1076  prosupport = InvalidOid;
1077  parallel = PROPARALLEL_UNSAFE;
1078 
1079  /* Extract non-default attributes from stmt->options list */
1081  stmt->is_procedure,
1082  stmt->options,
1083  &as_clause, &language, &transformDefElem,
1084  &isWindowFunc, &volatility,
1085  &isStrict, &security, &isLeakProof,
1086  &proconfig, &procost, &prorows,
1087  &prosupport, &parallel);
1088 
1089  if (!language)
1090  {
1091  if (stmt->sql_body)
1092  language = "sql";
1093  else
1094  ereport(ERROR,
1095  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1096  errmsg("no language specified")));
1097  }
1098 
1099  /* Look up the language and validate permissions */
1100  languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
1101  if (!HeapTupleIsValid(languageTuple))
1102  ereport(ERROR,
1103  (errcode(ERRCODE_UNDEFINED_OBJECT),
1104  errmsg("language \"%s\" does not exist", language),
1105  (extension_file_exists(language) ?
1106  errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
1107 
1108  languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
1109  languageOid = languageStruct->oid;
1110 
1111  if (languageStruct->lanpltrusted)
1112  {
1113  /* if trusted language, need USAGE privilege */
1114  aclresult = object_aclcheck(LanguageRelationId, languageOid, GetUserId(), ACL_USAGE);
1115  if (aclresult != ACLCHECK_OK)
1116  aclcheck_error(aclresult, OBJECT_LANGUAGE,
1117  NameStr(languageStruct->lanname));
1118  }
1119  else
1120  {
1121  /* if untrusted language, must be superuser */
1122  if (!superuser())
1124  NameStr(languageStruct->lanname));
1125  }
1126 
1127  languageValidator = languageStruct->lanvalidator;
1128 
1129  ReleaseSysCache(languageTuple);
1130 
1131  /*
1132  * Only superuser is allowed to create leakproof functions because
1133  * leakproof functions can see tuples which have not yet been filtered out
1134  * by security barrier views or row-level security policies.
1135  */
1136  if (isLeakProof && !superuser())
1137  ereport(ERROR,
1138  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1139  errmsg("only superuser can define a leakproof function")));
1140 
1141  if (transformDefElem)
1142  {
1143  ListCell *lc;
1144 
1145  foreach(lc, castNode(List, transformDefElem))
1146  {
1147  Oid typeid = typenameTypeId(NULL,
1148  lfirst_node(TypeName, lc));
1149  Oid elt = get_base_element_type(typeid);
1150 
1151  typeid = elt ? elt : typeid;
1152 
1153  get_transform_oid(typeid, languageOid, false);
1154  trftypes_list = lappend_oid(trftypes_list, typeid);
1155  }
1156  }
1157 
1158  /*
1159  * Convert remaining parameters of CREATE to form wanted by
1160  * ProcedureCreate.
1161  */
1163  stmt->parameters,
1164  languageOid,
1166  &parameterTypes,
1167  &parameterTypes_list,
1168  &allParameterTypes,
1169  &parameterModes,
1170  &parameterNames,
1171  &inParameterNames_list,
1172  &parameterDefaults,
1173  &variadicArgType,
1174  &requiredResultType);
1175 
1176  if (stmt->is_procedure)
1177  {
1178  Assert(!stmt->returnType);
1179  prorettype = requiredResultType ? requiredResultType : VOIDOID;
1180  returnsSet = false;
1181  }
1182  else if (stmt->returnType)
1183  {
1184  /* explicit RETURNS clause */
1185  compute_return_type(stmt->returnType, languageOid,
1186  &prorettype, &returnsSet);
1187  if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1188  ereport(ERROR,
1189  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1190  errmsg("function result type must be %s because of OUT parameters",
1191  format_type_be(requiredResultType))));
1192  }
1193  else if (OidIsValid(requiredResultType))
1194  {
1195  /* default RETURNS clause from OUT parameters */
1196  prorettype = requiredResultType;
1197  returnsSet = false;
1198  }
1199  else
1200  {
1201  ereport(ERROR,
1202  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1203  errmsg("function result type must be specified")));
1204  /* Alternative possibility: default to RETURNS VOID */
1205  prorettype = VOIDOID;
1206  returnsSet = false;
1207  }
1208 
1209  if (trftypes_list != NIL)
1210  {
1211  ListCell *lc;
1212  Datum *arr;
1213  int i;
1214 
1215  arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1216  i = 0;
1217  foreach(lc, trftypes_list)
1218  arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1219  trftypes = construct_array_builtin(arr, list_length(trftypes_list), OIDOID);
1220  }
1221  else
1222  {
1223  /* store SQL NULL instead of empty array */
1224  trftypes = NULL;
1225  }
1226 
1227  interpret_AS_clause(languageOid, language, funcname, as_clause, stmt->sql_body,
1228  parameterTypes_list, inParameterNames_list,
1229  &prosrc_str, &probin_str, &prosqlbody,
1230  pstate->p_sourcetext);
1231 
1232  /*
1233  * Set default values for COST and ROWS depending on other parameters;
1234  * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1235  * values, keep it in sync if you change them.
1236  */
1237  if (procost < 0)
1238  {
1239  /* SQL and PL-language functions are assumed more expensive */
1240  if (languageOid == INTERNALlanguageId ||
1241  languageOid == ClanguageId)
1242  procost = 1;
1243  else
1244  procost = 100;
1245  }
1246  if (prorows < 0)
1247  {
1248  if (returnsSet)
1249  prorows = 1000;
1250  else
1251  prorows = 0; /* dummy value if not returnsSet */
1252  }
1253  else if (!returnsSet)
1254  ereport(ERROR,
1255  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1256  errmsg("ROWS is not applicable when function does not return a set")));
1257 
1258  /*
1259  * And now that we have all the parameters, and know we're permitted to do
1260  * so, go ahead and create the function.
1261  */
1262  return ProcedureCreate(funcname,
1263  namespaceId,
1264  stmt->replace,
1265  returnsSet,
1266  prorettype,
1267  GetUserId(),
1268  languageOid,
1269  languageValidator,
1270  prosrc_str, /* converted to text later */
1271  probin_str, /* converted to text later */
1272  prosqlbody,
1273  stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
1274  security,
1275  isLeakProof,
1276  isStrict,
1277  volatility,
1278  parallel,
1279  parameterTypes,
1280  PointerGetDatum(allParameterTypes),
1281  PointerGetDatum(parameterModes),
1282  PointerGetDatum(parameterNames),
1283  parameterDefaults,
1284  PointerGetDatum(trftypes),
1285  PointerGetDatum(proconfig),
1286  prosupport,
1287  procost,
1288  prorows);
1289 }
@ ACLCHECK_NO_PRIV
Definition: acl.h:185
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3338
#define NameStr(name)
Definition: c.h:682
float float4
Definition: c.h:565
int errhint(const char *fmt,...)
Definition: elog.c:1153
bool extension_file_exists(const char *extensionName)
Definition: extension.c:2196
static void compute_return_type(TypeName *returnType, Oid languageOid, Oid *prorettype_p, bool *returnsSet_p)
Definition: functioncmds.c:93
static void compute_function_attributes(ParseState *pstate, bool is_procedure, List *options, List **as, char **language, Node **transform, bool *windowfunc_p, char *volatility_p, bool *strict_p, bool *security_definer, bool *leakproof_p, ArrayType **proconfig, float4 *procost, float4 *prorows, Oid *prosupport, char *parallel_p)
Definition: functioncmds.c:719
void interpret_function_parameter_list(ParseState *pstate, List *parameters, Oid languageOid, ObjectType objtype, oidvector **parameterTypes, List **parameterTypes_list, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **inParameterNames_list, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
Definition: functioncmds.c:188
static void interpret_AS_clause(Oid languageOid, const char *languageName, char *funcname, List *as, Node *sql_body_in, List *parameterTypes, List *inParameterNames, char **prosrc_str_p, char **probin_str_p, Node **sql_body_out, const char *queryString)
Definition: functioncmds.c:856
Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
int i
Definition: isn.c:73
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
Oid get_base_element_type(Oid typid)
Definition: lsyscache.c:2790
void * palloc(Size size)
Definition: mcxt.c:1199
#define castNode(_type_, nodeptr)
Definition: nodes.h:186
@ OBJECT_PROCEDURE
Definition: parsenodes.h:1917
@ OBJECT_LANGUAGE
Definition: parsenodes.h:1909
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65
#define lfirst_node(type, lc)
Definition: pg_list.h:174
static int list_length(const List *l)
Definition: pg_list.h:150
#define lfirst_oid(lc)
Definition: pg_list.h:172
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:72
TypeName * returnType
Definition: parsenodes.h:3077
Definition: nodes.h:118
const char * p_sourcetext
Definition: parse_node.h:185
Definition: c.h:662
@ LANGNAME
Definition: syscache.h:67

References ACL_CREATE, ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, Assert(), castNode, compute_function_attributes(), compute_return_type(), construct_array_builtin(), ereport, errcode(), errhint(), errmsg(), ERROR, extension_file_exists(), format_type_be(), CreateFunctionStmt::funcname, get_base_element_type(), get_namespace_name(), get_transform_oid(), GETSTRUCT, GetUserId(), HeapTupleIsValid, i, interpret_AS_clause(), interpret_function_parameter_list(), InvalidOid, CreateFunctionStmt::is_procedure, LANGNAME, lappend_oid(), lfirst_node, lfirst_oid, list_length(), NameStr, NIL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_PROCEDURE, OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, CreateFunctionStmt::options, ParseState::p_sourcetext, palloc(), CreateFunctionStmt::parameters, PointerGetDatum(), ProcedureCreate(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), CreateFunctionStmt::replace, CreateFunctionStmt::returnType, SearchSysCache1(), CreateFunctionStmt::sql_body, superuser(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ CreateTransform()

ObjectAddress CreateTransform ( CreateTransformStmt stmt)

Definition at line 1802 of file functioncmds.c.

1803 {
1804  Oid typeid;
1805  char typtype;
1806  Oid langid;
1807  Oid fromsqlfuncid;
1808  Oid tosqlfuncid;
1809  AclResult aclresult;
1810  Form_pg_proc procstruct;
1811  Datum values[Natts_pg_transform];
1812  bool nulls[Natts_pg_transform] = {0};
1813  bool replaces[Natts_pg_transform] = {0};
1814  Oid transformid;
1815  HeapTuple tuple;
1816  HeapTuple newtuple;
1817  Relation relation;
1818  ObjectAddress myself,
1819  referenced;
1820  ObjectAddresses *addrs;
1821  bool is_replace;
1822 
1823  /*
1824  * Get the type
1825  */
1826  typeid = typenameTypeId(NULL, stmt->type_name);
1827  typtype = get_typtype(typeid);
1828 
1829  if (typtype == TYPTYPE_PSEUDO)
1830  ereport(ERROR,
1831  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1832  errmsg("data type %s is a pseudo-type",
1833  TypeNameToString(stmt->type_name))));
1834 
1835  if (typtype == TYPTYPE_DOMAIN)
1836  ereport(ERROR,
1837  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1838  errmsg("data type %s is a domain",
1839  TypeNameToString(stmt->type_name))));
1840 
1841  if (!object_ownercheck(TypeRelationId, typeid, GetUserId()))
1843 
1844  aclresult = object_aclcheck(TypeRelationId, typeid, GetUserId(), ACL_USAGE);
1845  if (aclresult != ACLCHECK_OK)
1846  aclcheck_error_type(aclresult, typeid);
1847 
1848  /*
1849  * Get the language
1850  */
1851  langid = get_language_oid(stmt->lang, false);
1852 
1853  aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE);
1854  if (aclresult != ACLCHECK_OK)
1855  aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang);
1856 
1857  /*
1858  * Get the functions
1859  */
1860  if (stmt->fromsql)
1861  {
1862  fromsqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->fromsql, false);
1863 
1864  if (!object_ownercheck(ProcedureRelationId, fromsqlfuncid, GetUserId()))
1866 
1867  aclresult = object_aclcheck(ProcedureRelationId, fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1868  if (aclresult != ACLCHECK_OK)
1870 
1871  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1872  if (!HeapTupleIsValid(tuple))
1873  elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1874  procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1875  if (procstruct->prorettype != INTERNALOID)
1876  ereport(ERROR,
1877  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1878  errmsg("return data type of FROM SQL function must be %s",
1879  "internal")));
1880  check_transform_function(procstruct);
1881  ReleaseSysCache(tuple);
1882  }
1883  else
1884  fromsqlfuncid = InvalidOid;
1885 
1886  if (stmt->tosql)
1887  {
1888  tosqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->tosql, false);
1889 
1890  if (!object_ownercheck(ProcedureRelationId, tosqlfuncid, GetUserId()))
1892 
1893  aclresult = object_aclcheck(ProcedureRelationId, tosqlfuncid, GetUserId(), ACL_EXECUTE);
1894  if (aclresult != ACLCHECK_OK)
1896 
1897  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1898  if (!HeapTupleIsValid(tuple))
1899  elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1900  procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1901  if (procstruct->prorettype != typeid)
1902  ereport(ERROR,
1903  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1904  errmsg("return data type of TO SQL function must be the transform data type")));
1905  check_transform_function(procstruct);
1906  ReleaseSysCache(tuple);
1907  }
1908  else
1909  tosqlfuncid = InvalidOid;
1910 
1911  /*
1912  * Ready to go
1913  */
1914  values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1915  values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1916  values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1917  values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1918 
1919  relation = table_open(TransformRelationId, RowExclusiveLock);
1920 
1921  tuple = SearchSysCache2(TRFTYPELANG,
1922  ObjectIdGetDatum(typeid),
1923  ObjectIdGetDatum(langid));
1924  if (HeapTupleIsValid(tuple))
1925  {
1927 
1928  if (!stmt->replace)
1929  ereport(ERROR,
1931  errmsg("transform for type %s language \"%s\" already exists",
1932  format_type_be(typeid),
1933  stmt->lang)));
1934 
1935  replaces[Anum_pg_transform_trffromsql - 1] = true;
1936  replaces[Anum_pg_transform_trftosql - 1] = true;
1937 
1938  newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1939  CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1940 
1941  transformid = form->oid;
1942  ReleaseSysCache(tuple);
1943  is_replace = true;
1944  }
1945  else
1946  {
1947  transformid = GetNewOidWithIndex(relation, TransformOidIndexId,
1948  Anum_pg_transform_oid);
1949  values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid);
1950  newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1951  CatalogTupleInsert(relation, newtuple);
1952  is_replace = false;
1953  }
1954 
1955  if (is_replace)
1956  deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1957 
1958  addrs = new_object_addresses();
1959 
1960  /* make dependency entries */
1961  ObjectAddressSet(myself, TransformRelationId, transformid);
1962 
1963  /* dependency on language */
1964  ObjectAddressSet(referenced, LanguageRelationId, langid);
1965  add_exact_object_address(&referenced, addrs);
1966 
1967  /* dependency on type */
1968  ObjectAddressSet(referenced, TypeRelationId, typeid);
1969  add_exact_object_address(&referenced, addrs);
1970 
1971  /* dependencies on functions */
1972  if (OidIsValid(fromsqlfuncid))
1973  {
1974  ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
1975  add_exact_object_address(&referenced, addrs);
1976  }
1977  if (OidIsValid(tosqlfuncid))
1978  {
1979  ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
1980  add_exact_object_address(&referenced, addrs);
1981  }
1982 
1984  free_object_addresses(addrs);
1985 
1986  /* dependency on extension */
1987  recordDependencyOnCurrentExtension(&myself, is_replace);
1988 
1989  /* Post creation hook for new transform */
1990  InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
1991 
1992  heap_freetuple(newtuple);
1993 
1994  table_close(relation, RowExclusiveLock);
1995 
1996  return myself;
1997 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2790
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2526
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
static void check_transform_function(Form_pg_proc procstruct)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define ACL_EXECUTE
Definition: parsenodes.h:90
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
FormData_pg_transform * Form_pg_transform
Definition: pg_transform.h:43
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:228
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ObjectWithArgs * tosql
Definition: parsenodes.h:3657
TypeName * type_name
Definition: parsenodes.h:3654
ObjectWithArgs * fromsql
Definition: parsenodes.h:3656
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:1184
@ TRFTYPELANG
Definition: syscache.h:103

References ACL_EXECUTE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, add_exact_object_address(), CatalogTupleInsert(), CatalogTupleUpdate(), check_transform_function(), deleteDependencyRecordsFor(), DEPENDENCY_NORMAL, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), free_object_addresses(), CreateTransformStmt::fromsql, get_language_oid(), get_typtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostCreateHook, CreateTransformStmt::lang, LookupFuncWithArgs(), NameListToString(), new_object_addresses(), object_aclcheck(), OBJECT_FUNCTION, OBJECT_LANGUAGE, object_ownercheck(), ObjectAddressSet, ObjectIdGetDatum(), ObjectWithArgs::objname, OidIsValid, PROCOID, record_object_address_dependencies(), recordDependencyOnCurrentExtension(), RelationGetDescr, ReleaseSysCache(), CreateTransformStmt::replace, RowExclusiveLock, SearchSysCache1(), SearchSysCache2(), HeapTupleData::t_self, table_close(), table_open(), CreateTransformStmt::tosql, TRFTYPELANG, CreateTransformStmt::type_name, TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

◆ ExecuteCallStmt()

void ExecuteCallStmt ( CallStmt stmt,
ParamListInfo  params,
bool  atomic,
DestReceiver dest 
)

Definition at line 2176 of file functioncmds.c.

2177 {
2178  LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
2179  ListCell *lc;
2180  FuncExpr *fexpr;
2181  int nargs;
2182  int i;
2183  AclResult aclresult;
2184  FmgrInfo flinfo;
2185  CallContext *callcontext;
2186  EState *estate;
2187  ExprContext *econtext;
2188  HeapTuple tp;
2189  PgStat_FunctionCallUsage fcusage;
2190  Datum retval;
2191 
2192  fexpr = stmt->funcexpr;
2193  Assert(fexpr);
2194  Assert(IsA(fexpr, FuncExpr));
2195 
2196  aclresult = object_aclcheck(ProcedureRelationId, fexpr->funcid, GetUserId(), ACL_EXECUTE);
2197  if (aclresult != ACLCHECK_OK)
2198  aclcheck_error(aclresult, OBJECT_PROCEDURE, get_func_name(fexpr->funcid));
2199 
2200  /* Prep the context object we'll pass to the procedure */
2201  callcontext = makeNode(CallContext);
2202  callcontext->atomic = atomic;
2203 
2205  if (!HeapTupleIsValid(tp))
2206  elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
2207 
2208  /*
2209  * If proconfig is set we can't allow transaction commands because of the
2210  * way the GUC stacking works: The transaction boundary would have to pop
2211  * the proconfig setting off the stack. That restriction could be lifted
2212  * by redesigning the GUC nesting mechanism a bit.
2213  */
2214  if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL))
2215  callcontext->atomic = true;
2216 
2217  /*
2218  * In security definer procedures, we can't allow transaction commands.
2219  * StartTransaction() insists that the security context stack is empty,
2220  * and AbortTransaction() resets the security context. This could be
2221  * reorganized, but right now it doesn't work.
2222  */
2223  if (((Form_pg_proc) GETSTRUCT(tp))->prosecdef)
2224  callcontext->atomic = true;
2225 
2226  ReleaseSysCache(tp);
2227 
2228  /* safety check; see ExecInitFunc() */
2229  nargs = list_length(fexpr->args);
2230  if (nargs > FUNC_MAX_ARGS)
2231  ereport(ERROR,
2232  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2233  errmsg_plural("cannot pass more than %d argument to a procedure",
2234  "cannot pass more than %d arguments to a procedure",
2235  FUNC_MAX_ARGS,
2236  FUNC_MAX_ARGS)));
2237 
2238  /* Initialize function call structure */
2240  fmgr_info(fexpr->funcid, &flinfo);
2241  fmgr_info_set_expr((Node *) fexpr, &flinfo);
2242  InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
2243  (Node *) callcontext, NULL);
2244 
2245  /*
2246  * Evaluate procedure arguments inside a suitable execution context. Note
2247  * we can't free this context till the procedure returns.
2248  */
2249  estate = CreateExecutorState();
2250  estate->es_param_list_info = params;
2251  econtext = CreateExprContext(estate);
2252 
2253  /*
2254  * If we're called in non-atomic context, we also have to ensure that the
2255  * argument expressions run with an up-to-date snapshot. Our caller will
2256  * have provided a current snapshot in atomic contexts, but not in
2257  * non-atomic contexts, because the possibility of a COMMIT/ROLLBACK
2258  * destroying the snapshot makes higher-level management too complicated.
2259  */
2260  if (!atomic)
2262 
2263  i = 0;
2264  foreach(lc, fexpr->args)
2265  {
2266  ExprState *exprstate;
2267  Datum val;
2268  bool isnull;
2269 
2270  exprstate = ExecPrepareExpr(lfirst(lc), estate);
2271 
2272  val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
2273 
2274  fcinfo->args[i].value = val;
2275  fcinfo->args[i].isnull = isnull;
2276 
2277  i++;
2278  }
2279 
2280  /* Get rid of temporary snapshot for arguments, if we made one */
2281  if (!atomic)
2283 
2284  /* Here we actually call the procedure */
2285  pgstat_init_function_usage(fcinfo, &fcusage);
2286  retval = FunctionCallInvoke(fcinfo);
2287  pgstat_end_function_usage(&fcusage, true);
2288 
2289  /* Handle the procedure's outputs */
2290  if (fexpr->funcresulttype == VOIDOID)
2291  {
2292  /* do nothing */
2293  }
2294  else if (fexpr->funcresulttype == RECORDOID)
2295  {
2296  /* send tuple to client */
2297  HeapTupleHeader td;
2298  Oid tupType;
2299  int32 tupTypmod;
2300  TupleDesc retdesc;
2301  HeapTupleData rettupdata;
2302  TupOutputState *tstate;
2303  TupleTableSlot *slot;
2304 
2305  if (fcinfo->isnull)
2306  elog(ERROR, "procedure returned null record");
2307 
2308  /*
2309  * Ensure there's an active snapshot whilst we execute whatever's
2310  * involved here. Note that this is *not* sufficient to make the
2311  * world safe for TOAST pointers to be included in the returned data:
2312  * the referenced data could have gone away while we didn't hold a
2313  * snapshot. Hence, it's incumbent on PLs that can do COMMIT/ROLLBACK
2314  * to not return TOAST pointers, unless those pointers were fetched
2315  * after the last COMMIT/ROLLBACK in the procedure.
2316  *
2317  * XXX that is a really nasty, hard-to-test requirement. Is there a
2318  * way to remove it?
2319  */
2321 
2322  td = DatumGetHeapTupleHeader(retval);
2323  tupType = HeapTupleHeaderGetTypeId(td);
2324  tupTypmod = HeapTupleHeaderGetTypMod(td);
2325  retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
2326 
2327  tstate = begin_tup_output_tupdesc(dest, retdesc,
2328  &TTSOpsHeapTuple);
2329 
2330  rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
2331  ItemPointerSetInvalid(&(rettupdata.t_self));
2332  rettupdata.t_tableOid = InvalidOid;
2333  rettupdata.t_data = td;
2334 
2335  slot = ExecStoreHeapTuple(&rettupdata, tstate->slot, false);
2336  tstate->dest->receiveSlot(slot, tstate->dest);
2337 
2338  end_tup_output(tstate);
2339 
2340  ReleaseTupleDesc(retdesc);
2341  }
2342  else
2343  elog(ERROR, "unexpected result type for procedure: %u",
2344  fexpr->funcresulttype);
2345 
2346  FreeExecutorState(estate);
2347 }
signed int int32
Definition: c.h:430
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1016
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:747
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2333
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1352
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:84
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2255
EState * CreateExecutorState(void)
Definition: execUtils.c:92
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:305
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:336
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:462
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:452
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:446
long val
Definition: informix.c:664
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1590
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
#define makeNode(_type_)
Definition: nodes.h:165
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
#define FUNC_MAX_ARGS
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
void EnsurePortalSnapshotExists(void)
Definition: pquery.c:1780
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:251
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:683
void PopActiveSnapshot(void)
Definition: snapmgr.c:778
ParamListInfo es_param_list_info
Definition: execnodes.h:650
Definition: fmgr.h:57
List * args
Definition: primnodes.h:606
Oid inputcollid
Definition: primnodes.h:605
Oid funcresulttype
Definition: primnodes.h:599
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66
TupleTableSlot * slot
Definition: executor.h:494
DestReceiver * dest
Definition: executor.h:495
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:119
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FuncExpr::args, Assert(), CallContext::atomic, begin_tup_output_tupdesc(), CreateExecutorState(), CreateExprContext(), DatumGetHeapTupleHeader, generate_unaccent_rules::dest, TupOutputState::dest, elog(), end_tup_output(), EnsurePortalSnapshotExists(), ereport, errcode(), errmsg_plural(), ERROR, EState::es_param_list_info, ExecEvalExprSwitchContext(), ExecPrepareExpr(), ExecStoreHeapTuple(), fmgr_info(), fmgr_info_set_expr, FreeExecutorState(), FUNC_MAX_ARGS, CallStmt::funcexpr, FuncExpr::funcid, FuncExpr::funcresulttype, FunctionCallInvoke, get_func_name(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), heap_attisnull(), HeapTupleHeaderGetDatumLength, HeapTupleHeaderGetTypeId, HeapTupleHeaderGetTypMod, HeapTupleIsValid, i, InitFunctionCallInfoData, FuncExpr::inputcollid, InvalidOid, InvokeFunctionExecuteHook, IsA, ItemPointerSetInvalid(), lfirst, list_length(), LOCAL_FCINFO, lookup_rowtype_tupdesc(), makeNode, object_aclcheck(), OBJECT_PROCEDURE, ObjectIdGetDatum(), pgstat_end_function_usage(), pgstat_init_function_usage(), PopActiveSnapshot(), PROCOID, PushActiveSnapshot(), _DestReceiver::receiveSlot, ReleaseSysCache(), ReleaseTupleDesc, SearchSysCache1(), TupOutputState::slot, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TTSOpsHeapTuple, and val.

Referenced by standard_ProcessUtility().

◆ ExecuteDoStmt()

void ExecuteDoStmt ( ParseState pstate,
DoStmt stmt,
bool  atomic 
)

Definition at line 2054 of file functioncmds.c.

2055 {
2057  ListCell *arg;
2058  DefElem *as_item = NULL;
2059  DefElem *language_item = NULL;
2060  char *language;
2061  Oid laninline;
2062  HeapTuple languageTuple;
2063  Form_pg_language languageStruct;
2064 
2065  /* Process options we got from gram.y */
2066  foreach(arg, stmt->args)
2067  {
2068  DefElem *defel = (DefElem *) lfirst(arg);
2069 
2070  if (strcmp(defel->defname, "as") == 0)
2071  {
2072  if (as_item)
2073  errorConflictingDefElem(defel, pstate);
2074  as_item = defel;
2075  }
2076  else if (strcmp(defel->defname, "language") == 0)
2077  {
2078  if (language_item)
2079  errorConflictingDefElem(defel, pstate);
2080  language_item = defel;
2081  }
2082  else
2083  elog(ERROR, "option \"%s\" not recognized",
2084  defel->defname);
2085  }
2086 
2087  if (as_item)
2088  codeblock->source_text = strVal(as_item->arg);
2089  else
2090  ereport(ERROR,
2091  (errcode(ERRCODE_SYNTAX_ERROR),
2092  errmsg("no inline code specified")));
2093 
2094  /* if LANGUAGE option wasn't specified, use the default */
2095  if (language_item)
2096  language = strVal(language_item->arg);
2097  else
2098  language = "plpgsql";
2099 
2100  /* Look up the language and validate permissions */
2101  languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2102  if (!HeapTupleIsValid(languageTuple))
2103  ereport(ERROR,
2104  (errcode(ERRCODE_UNDEFINED_OBJECT),
2105  errmsg("language \"%s\" does not exist", language),
2106  (extension_file_exists(language) ?
2107  errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
2108 
2109  languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2110  codeblock->langOid = languageStruct->oid;
2111  codeblock->langIsTrusted = languageStruct->lanpltrusted;
2112  codeblock->atomic = atomic;
2113 
2114  if (languageStruct->lanpltrusted)
2115  {
2116  /* if trusted language, need USAGE privilege */
2117  AclResult aclresult;
2118 
2119  aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(),
2120  ACL_USAGE);
2121  if (aclresult != ACLCHECK_OK)
2122  aclcheck_error(aclresult, OBJECT_LANGUAGE,
2123  NameStr(languageStruct->lanname));
2124  }
2125  else
2126  {
2127  /* if untrusted language, must be superuser */
2128  if (!superuser())
2130  NameStr(languageStruct->lanname));
2131  }
2132 
2133  /* get the handler function's OID */
2134  laninline = languageStruct->laninline;
2135  if (!OidIsValid(laninline))
2136  ereport(ERROR,
2137  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2138  errmsg("language \"%s\" does not support inline code execution",
2139  NameStr(languageStruct->lanname))));
2140 
2141  ReleaseSysCache(languageTuple);
2142 
2143  /* execute the inline handler */
2144  OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2145 }
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:680
void * arg
List * args
Definition: parsenodes.h:3120
char * source_text
Definition: parsenodes.h:3128

References ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, arg, DefElem::arg, DoStmt::args, InlineCodeBlock::atomic, DefElem::defname, elog(), ereport, errcode(), errhint(), errmsg(), ERROR, errorConflictingDefElem(), extension_file_exists(), GETSTRUCT, GetUserId(), HeapTupleIsValid, InlineCodeBlock::langIsTrusted, LANGNAME, InlineCodeBlock::langOid, lfirst, makeNode, NameStr, object_aclcheck(), OBJECT_LANGUAGE, OidFunctionCall1, OidIsValid, PointerGetDatum(), ReleaseSysCache(), SearchSysCache1(), InlineCodeBlock::source_text, strVal, and superuser().

Referenced by standard_ProcessUtility().

◆ get_transform_oid()

Oid get_transform_oid ( Oid  type_id,
Oid  lang_id,
bool  missing_ok 
)

Definition at line 2007 of file functioncmds.c.

2008 {
2009  Oid oid;
2010 
2011  oid = GetSysCacheOid2(TRFTYPELANG, Anum_pg_transform_oid,
2012  ObjectIdGetDatum(type_id),
2013  ObjectIdGetDatum(lang_id));
2014  if (!OidIsValid(oid) && !missing_ok)
2015  ereport(ERROR,
2016  (errcode(ERRCODE_UNDEFINED_OBJECT),
2017  errmsg("transform for type %s language \"%s\" does not exist",
2018  format_type_be(type_id),
2019  get_language_name(lang_id, false))));
2020  return oid;
2021 }
char * get_language_name(Oid langoid, bool missing_ok)
Definition: lsyscache.c:1165
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:199

References ereport, errcode(), errmsg(), ERROR, format_type_be(), get_language_name(), GetSysCacheOid2, ObjectIdGetDatum(), OidIsValid, and TRFTYPELANG.

Referenced by CreateFunction(), get_object_address(), and ProcedureCreate().

◆ interpret_AS_clause()

static void interpret_AS_clause ( Oid  languageOid,
const char *  languageName,
char *  funcname,
List as,
Node sql_body_in,
List parameterTypes,
List inParameterNames,
char **  prosrc_str_p,
char **  probin_str_p,
Node **  sql_body_out,
const char *  queryString 
)
static

Definition at line 856 of file functioncmds.c.

862 {
863  if (!sql_body_in && !as)
864  ereport(ERROR,
865  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
866  errmsg("no function body specified")));
867 
868  if (sql_body_in && as)
869  ereport(ERROR,
870  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
871  errmsg("duplicate function body specified")));
872 
873  if (sql_body_in && languageOid != SQLlanguageId)
874  ereport(ERROR,
875  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
876  errmsg("inline SQL function body only valid for language SQL")));
877 
878  *sql_body_out = NULL;
879 
880  if (languageOid == ClanguageId)
881  {
882  /*
883  * For "C" language, store the file name in probin and, when given,
884  * the link symbol name in prosrc. If link symbol is omitted,
885  * substitute procedure name. We also allow link symbol to be
886  * specified as "-", since that was the habit in PG versions before
887  * 8.4, and there might be dump files out there that don't translate
888  * that back to "omitted".
889  */
890  *probin_str_p = strVal(linitial(as));
891  if (list_length(as) == 1)
892  *prosrc_str_p = funcname;
893  else
894  {
895  *prosrc_str_p = strVal(lsecond(as));
896  if (strcmp(*prosrc_str_p, "-") == 0)
897  *prosrc_str_p = funcname;
898  }
899  }
900  else if (sql_body_in)
901  {
903 
905 
906  pinfo->fname = funcname;
907  pinfo->nargs = list_length(parameterTypes);
908  pinfo->argtypes = (Oid *) palloc(pinfo->nargs * sizeof(Oid));
909  pinfo->argnames = (char **) palloc(pinfo->nargs * sizeof(char *));
910  for (int i = 0; i < list_length(parameterTypes); i++)
911  {
912  char *s = strVal(list_nth(inParameterNames, i));
913 
914  pinfo->argtypes[i] = list_nth_oid(parameterTypes, i);
915  if (IsPolymorphicType(pinfo->argtypes[i]))
916  ereport(ERROR,
917  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
918  errmsg("SQL function with unquoted function body cannot have polymorphic arguments")));
919 
920  if (s[0] != '\0')
921  pinfo->argnames[i] = s;
922  else
923  pinfo->argnames[i] = NULL;
924  }
925 
926  if (IsA(sql_body_in, List))
927  {
928  List *stmts = linitial_node(List, castNode(List, sql_body_in));
929  ListCell *lc;
930  List *transformed_stmts = NIL;
931 
932  foreach(lc, stmts)
933  {
934  Node *stmt = lfirst(lc);
935  Query *q;
936  ParseState *pstate = make_parsestate(NULL);
937 
938  pstate->p_sourcetext = queryString;
939  sql_fn_parser_setup(pstate, pinfo);
940  q = transformStmt(pstate, stmt);
941  if (q->commandType == CMD_UTILITY)
942  ereport(ERROR,
943  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
944  errmsg("%s is not yet supported in unquoted SQL function body",
946  transformed_stmts = lappend(transformed_stmts, q);
947  free_parsestate(pstate);
948  }
949 
950  *sql_body_out = (Node *) list_make1(transformed_stmts);
951  }
952  else
953  {
954  Query *q;
955  ParseState *pstate = make_parsestate(NULL);
956 
957  pstate->p_sourcetext = queryString;
958  sql_fn_parser_setup(pstate, pinfo);
959  q = transformStmt(pstate, sql_body_in);
960  if (q->commandType == CMD_UTILITY)
961  ereport(ERROR,
962  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
963  errmsg("%s is not yet supported in unquoted SQL function body",
965  free_parsestate(pstate);
966 
967  *sql_body_out = (Node *) q;
968  }
969 
970  /*
971  * We must put something in prosrc. For the moment, just record an
972  * empty string. It might be useful to store the original text of the
973  * CREATE FUNCTION statement --- but to make actual use of that in
974  * error reports, we'd also have to adjust readfuncs.c to not throw
975  * away node location fields when reading prosqlbody.
976  */
977  *prosrc_str_p = pstrdup("");
978 
979  /* But we definitely don't need probin. */
980  *probin_str_p = NULL;
981  }
982  else
983  {
984  /* Everything else wants the given string in prosrc. */
985  *prosrc_str_p = strVal(linitial(as));
986  *probin_str_p = NULL;
987 
988  if (list_length(as) != 1)
989  ereport(ERROR,
990  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
991  errmsg("only one AS item needed for language \"%s\"",
992  languageName)));
993 
994  if (languageOid == INTERNALlanguageId)
995  {
996  /*
997  * In PostgreSQL versions before 6.5, the SQL name of the created
998  * function could not be different from the internal name, and
999  * "prosrc" wasn't used. So there is code out there that does
1000  * CREATE FUNCTION xyz AS '' LANGUAGE internal. To preserve some
1001  * modicum of backwards compatibility, accept an empty "prosrc"
1002  * value as meaning the supplied SQL function name.
1003  */
1004  if (strlen(*prosrc_str_p) == 0)
1005  *prosrc_str_p = funcname;
1006  }
1007  }
1008 }
const char * GetCommandTagName(CommandTag commandTag)
Definition: cmdtag.c:45
void sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
Definition: functions.c:265
SQLFunctionParseInfo * SQLFunctionParseInfoPtr
Definition: functions.h:35
char * pstrdup(const char *in)
Definition: mcxt.c:1483
void * palloc0(Size size)
Definition: mcxt.c:1230
@ CMD_UTILITY
Definition: nodes.h:270
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:76
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:313
#define linitial_node(type, l)
Definition: pg_list.h:179
static Oid list_nth_oid(const List *list, int n)
Definition: pg_list.h:319
#define list_make1(x1)
Definition: pg_list.h:210
#define linitial(l)
Definition: pg_list.h:176
#define lsecond(l)
Definition: pg_list.h:181
static void * list_nth(const List *list, int n)
Definition: pg_list.h:297
CmdType commandType
Definition: parsenodes.h:124
Node * utilityStmt
Definition: parsenodes.h:136
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2353

References SQLFunctionParseInfo::argnames, SQLFunctionParseInfo::argtypes, castNode, CMD_UTILITY, Query::commandType, CreateCommandTag(), ereport, errcode(), errmsg(), ERROR, SQLFunctionParseInfo::fname, free_parsestate(), GetCommandTagName(), i, IsA, lappend(), lfirst, linitial, linitial_node, list_length(), list_make1, list_nth(), list_nth_oid(), lsecond, make_parsestate(), SQLFunctionParseInfo::nargs, NIL, ParseState::p_sourcetext, palloc(), palloc0(), pstrdup(), sql_fn_parser_setup(), strVal, transformStmt(), and Query::utilityStmt.

Referenced by CreateFunction().

◆ interpret_func_parallel()

static char interpret_func_parallel ( DefElem defel)
static

Definition at line 625 of file functioncmds.c.

626 {
627  char *str = strVal(defel->arg);
628 
629  if (strcmp(str, "safe") == 0)
630  return PROPARALLEL_SAFE;
631  else if (strcmp(str, "unsafe") == 0)
632  return PROPARALLEL_UNSAFE;
633  else if (strcmp(str, "restricted") == 0)
634  return PROPARALLEL_RESTRICTED;
635  else
636  {
637  ereport(ERROR,
638  (errcode(ERRCODE_SYNTAX_ERROR),
639  errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
640  return PROPARALLEL_UNSAFE; /* keep compiler quiet */
641  }
642 }

References DefElem::arg, ereport, errcode(), errmsg(), ERROR, generate_unaccent_rules::str, and strVal.

Referenced by AlterFunction(), and compute_function_attributes().

◆ interpret_func_support()

static Oid interpret_func_support ( DefElem defel)
static

Definition at line 675 of file functioncmds.c.

676 {
677  List *procName = defGetQualifiedName(defel);
678  Oid procOid;
679  Oid argList[1];
680 
681  /*
682  * Support functions always take one INTERNAL argument and return
683  * INTERNAL.
684  */
685  argList[0] = INTERNALOID;
686 
687  procOid = LookupFuncName(procName, 1, argList, true);
688  if (!OidIsValid(procOid))
689  ereport(ERROR,
690  (errcode(ERRCODE_UNDEFINED_FUNCTION),
691  errmsg("function %s does not exist",
692  func_signature_string(procName, 1, NIL, argList))));
693 
694  if (get_func_rettype(procOid) != INTERNALOID)
695  ereport(ERROR,
696  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
697  errmsg("support function %s must return type %s",
698  NameListToString(procName), "internal")));
699 
700  /*
701  * Someday we might want an ACL check here; but for now, we insist that
702  * you be superuser to specify a support function, so privilege on the
703  * support function is moot.
704  */
705  if (!superuser())
706  ereport(ERROR,
707  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
708  errmsg("must be superuser to specify a support function")));
709 
710  return procOid;
711 }
List * defGetQualifiedName(DefElem *def)
Definition: define.c:253
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1637
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2032
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2146

References defGetQualifiedName(), ereport, errcode(), errmsg(), ERROR, func_signature_string(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and superuser().

Referenced by AlterFunction(), and compute_function_attributes().

◆ interpret_func_volatility()

static char interpret_func_volatility ( DefElem defel)
static

Definition at line 607 of file functioncmds.c.

608 {
609  char *str = strVal(defel->arg);
610 
611  if (strcmp(str, "immutable") == 0)
612  return PROVOLATILE_IMMUTABLE;
613  else if (strcmp(str, "stable") == 0)
614  return PROVOLATILE_STABLE;
615  else if (strcmp(str, "volatile") == 0)
616  return PROVOLATILE_VOLATILE;
617  else
618  {
619  elog(ERROR, "invalid volatility \"%s\"", str);
620  return 0; /* keep compiler quiet */
621  }
622 }

References DefElem::arg, elog(), ERROR, generate_unaccent_rules::str, and strVal.

Referenced by AlterFunction(), and compute_function_attributes().

◆ interpret_function_parameter_list()

void interpret_function_parameter_list ( ParseState pstate,
List parameters,
Oid  languageOid,
ObjectType  objtype,
oidvector **  parameterTypes,
List **  parameterTypes_list,
ArrayType **  allParameterTypes,
ArrayType **  parameterModes,
ArrayType **  parameterNames,
List **  inParameterNames_list,
List **  parameterDefaults,
Oid variadicArgType,
Oid requiredResultType 
)

Definition at line 188 of file functioncmds.c.

201 {
202  int parameterCount = list_length(parameters);
203  Oid *inTypes;
204  int inCount = 0;
205  Datum *allTypes;
206  Datum *paramModes;
207  Datum *paramNames;
208  int outCount = 0;
209  int varCount = 0;
210  bool have_names = false;
211  bool have_defaults = false;
212  ListCell *x;
213  int i;
214 
215  *variadicArgType = InvalidOid; /* default result */
216  *requiredResultType = InvalidOid; /* default result */
217 
218  inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
219  allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
220  paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
221  paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
222  *parameterDefaults = NIL;
223 
224  /* Scan the list and extract data into work arrays */
225  i = 0;
226  foreach(x, parameters)
227  {
229  TypeName *t = fp->argType;
230  FunctionParameterMode fpmode = fp->mode;
231  bool isinput = false;
232  Oid toid;
233  Type typtup;
234  AclResult aclresult;
235 
236  /* For our purposes here, a defaulted mode spec is identical to IN */
237  if (fpmode == FUNC_PARAM_DEFAULT)
238  fpmode = FUNC_PARAM_IN;
239 
240  typtup = LookupTypeName(NULL, t, NULL, false);
241  if (typtup)
242  {
243  if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
244  {
245  /* As above, hard error if language is SQL */
246  if (languageOid == SQLlanguageId)
247  ereport(ERROR,
248  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
249  errmsg("SQL function cannot accept shell type %s",
250  TypeNameToString(t))));
251  /* We don't allow creating aggregates on shell types either */
252  else if (objtype == OBJECT_AGGREGATE)
253  ereport(ERROR,
254  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
255  errmsg("aggregate cannot accept shell type %s",
256  TypeNameToString(t))));
257  else
258  ereport(NOTICE,
259  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
260  errmsg("argument type %s is only a shell",
261  TypeNameToString(t))));
262  }
263  toid = typeTypeId(typtup);
264  ReleaseSysCache(typtup);
265  }
266  else
267  {
268  ereport(ERROR,
269  (errcode(ERRCODE_UNDEFINED_OBJECT),
270  errmsg("type %s does not exist",
271  TypeNameToString(t))));
272  toid = InvalidOid; /* keep compiler quiet */
273  }
274 
275  aclresult = object_aclcheck(TypeRelationId, toid, GetUserId(), ACL_USAGE);
276  if (aclresult != ACLCHECK_OK)
277  aclcheck_error_type(aclresult, toid);
278 
279  if (t->setof)
280  {
281  if (objtype == OBJECT_AGGREGATE)
282  ereport(ERROR,
283  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
284  errmsg("aggregates cannot accept set arguments")));
285  else if (objtype == OBJECT_PROCEDURE)
286  ereport(ERROR,
287  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
288  errmsg("procedures cannot accept set arguments")));
289  else
290  ereport(ERROR,
291  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
292  errmsg("functions cannot accept set arguments")));
293  }
294 
295  /* handle input parameters */
296  if (fpmode != FUNC_PARAM_OUT && fpmode != FUNC_PARAM_TABLE)
297  {
298  /* other input parameters can't follow a VARIADIC parameter */
299  if (varCount > 0)
300  ereport(ERROR,
301  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
302  errmsg("VARIADIC parameter must be the last input parameter")));
303  inTypes[inCount++] = toid;
304  isinput = true;
305  if (parameterTypes_list)
306  *parameterTypes_list = lappend_oid(*parameterTypes_list, toid);
307  }
308 
309  /* handle output parameters */
310  if (fpmode != FUNC_PARAM_IN && fpmode != FUNC_PARAM_VARIADIC)
311  {
312  if (objtype == OBJECT_PROCEDURE)
313  {
314  /*
315  * We disallow OUT-after-VARIADIC only for procedures. While
316  * such a case causes no confusion in ordinary function calls,
317  * it would cause confusion in a CALL statement.
318  */
319  if (varCount > 0)
320  ereport(ERROR,
321  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
322  errmsg("VARIADIC parameter must be the last parameter")));
323  /* Procedures with output parameters always return RECORD */
324  *requiredResultType = RECORDOID;
325  }
326  else if (outCount == 0) /* save first output param's type */
327  *requiredResultType = toid;
328  outCount++;
329  }
330 
331  if (fpmode == FUNC_PARAM_VARIADIC)
332  {
333  *variadicArgType = toid;
334  varCount++;
335  /* validate variadic parameter type */
336  switch (toid)
337  {
338  case ANYARRAYOID:
339  case ANYCOMPATIBLEARRAYOID:
340  case ANYOID:
341  /* okay */
342  break;
343  default:
344  if (!OidIsValid(get_element_type(toid)))
345  ereport(ERROR,
346  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
347  errmsg("VARIADIC parameter must be an array")));
348  break;
349  }
350  }
351 
352  allTypes[i] = ObjectIdGetDatum(toid);
353 
354  paramModes[i] = CharGetDatum(fpmode);
355 
356  if (fp->name && fp->name[0])
357  {
358  ListCell *px;
359 
360  /*
361  * As of Postgres 9.0 we disallow using the same name for two
362  * input or two output function parameters. Depending on the
363  * function's language, conflicting input and output names might
364  * be bad too, but we leave it to the PL to complain if so.
365  */
366  foreach(px, parameters)
367  {
369  FunctionParameterMode prevfpmode;
370 
371  if (prevfp == fp)
372  break;
373  /* as above, default mode is IN */
374  prevfpmode = prevfp->mode;
375  if (prevfpmode == FUNC_PARAM_DEFAULT)
376  prevfpmode = FUNC_PARAM_IN;
377  /* pure in doesn't conflict with pure out */
378  if ((fpmode == FUNC_PARAM_IN ||
379  fpmode == FUNC_PARAM_VARIADIC) &&
380  (prevfpmode == FUNC_PARAM_OUT ||
381  prevfpmode == FUNC_PARAM_TABLE))
382  continue;
383  if ((prevfpmode == FUNC_PARAM_IN ||
384  prevfpmode == FUNC_PARAM_VARIADIC) &&
385  (fpmode == FUNC_PARAM_OUT ||
386  fpmode == FUNC_PARAM_TABLE))
387  continue;
388  if (prevfp->name && prevfp->name[0] &&
389  strcmp(prevfp->name, fp->name) == 0)
390  ereport(ERROR,
391  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
392  errmsg("parameter name \"%s\" used more than once",
393  fp->name)));
394  }
395 
396  paramNames[i] = CStringGetTextDatum(fp->name);
397  have_names = true;
398  }
399 
400  if (inParameterNames_list)
401  *inParameterNames_list = lappend(*inParameterNames_list, makeString(fp->name ? fp->name : pstrdup("")));
402 
403  if (fp->defexpr)
404  {
405  Node *def;
406 
407  if (!isinput)
408  ereport(ERROR,
409  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
410  errmsg("only input parameters can have default values")));
411 
412  def = transformExpr(pstate, fp->defexpr,
414  def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
415  assign_expr_collations(pstate, def);
416 
417  /*
418  * Make sure no variables are referred to (this is probably dead
419  * code now that add_missing_from is history).
420  */
421  if (pstate->p_rtable != NIL ||
422  contain_var_clause(def))
423  ereport(ERROR,
424  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
425  errmsg("cannot use table references in parameter default value")));
426 
427  /*
428  * transformExpr() should have already rejected subqueries,
429  * aggregates, and window functions, based on the EXPR_KIND_ for a
430  * default expression.
431  *
432  * It can't return a set either --- but coerce_to_specific_type
433  * already checked that for us.
434  *
435  * Note: the point of these restrictions is to ensure that an
436  * expression that, on its face, hasn't got subplans, aggregates,
437  * etc cannot suddenly have them after function default arguments
438  * are inserted.
439  */
440 
441  *parameterDefaults = lappend(*parameterDefaults, def);
442  have_defaults = true;
443  }
444  else
445  {
446  if (isinput && have_defaults)
447  ereport(ERROR,
448  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
449  errmsg("input parameters after one with a default value must also have defaults")));
450 
451  /*
452  * For procedures, we also can't allow OUT parameters after one
453  * with a default, because the same sort of confusion arises in a
454  * CALL statement.
455  */
456  if (objtype == OBJECT_PROCEDURE && have_defaults)
457  ereport(ERROR,
458  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
459  errmsg("procedure OUT parameters cannot appear after one with a default value")));
460  }
461 
462  i++;
463  }
464 
465  /* Now construct the proper outputs as needed */
466  *parameterTypes = buildoidvector(inTypes, inCount);
467 
468  if (outCount > 0 || varCount > 0)
469  {
470  *allParameterTypes = construct_array_builtin(allTypes, parameterCount, OIDOID);
471  *parameterModes = construct_array_builtin(paramModes, parameterCount, CHAROID);
472  if (outCount > 1)
473  *requiredResultType = RECORDOID;
474  /* otherwise we set requiredResultType correctly above */
475  }
476  else
477  {
478  *allParameterTypes = NULL;
479  *parameterModes = NULL;
480  }
481 
482  if (have_names)
483  {
484  for (i = 0; i < parameterCount; i++)
485  {
486  if (paramNames[i] == PointerGetDatum(NULL))
487  paramNames[i] = CStringGetTextDatum("");
488  }
489  *parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
490  }
491  else
492  *parameterNames = NULL;
493 }
#define CStringGetTextDatum(s)
Definition: builtins.h:85
void px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
int x
Definition: isn.c:71
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:167
Node * coerce_to_specific_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:92
@ EXPR_KIND_FUNCTION_DEFAULT
Definition: parse_node.h:70
FunctionParameterMode
Definition: parsenodes.h:3083
@ FUNC_PARAM_IN
Definition: parsenodes.h:3085
@ FUNC_PARAM_DEFAULT
Definition: parsenodes.h:3091
@ FUNC_PARAM_OUT
Definition: parsenodes.h:3086
@ FUNC_PARAM_TABLE
Definition: parsenodes.h:3089
@ FUNC_PARAM_VARIADIC
Definition: parsenodes.h:3088
@ OBJECT_AGGREGATE
Definition: parsenodes.h:1889
static Datum CharGetDatum(char X)
Definition: postgres.h:470
TypeName * argType
Definition: parsenodes.h:3098
FunctionParameterMode mode
Definition: parsenodes.h:3099
List * p_rtable
Definition: parse_node.h:186
String * makeString(char *str)
Definition: value.c:63
bool contain_var_clause(Node *node)
Definition: var.c:393

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, FunctionParameter::argType, assign_expr_collations(), buildoidvector(), CharGetDatum(), coerce_to_specific_type(), construct_array_builtin(), contain_var_clause(), CStringGetTextDatum, FunctionParameter::defexpr, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_FUNCTION_DEFAULT, FUNC_PARAM_DEFAULT, FUNC_PARAM_IN, FUNC_PARAM_OUT, FUNC_PARAM_TABLE, FUNC_PARAM_VARIADIC, get_element_type(), GETSTRUCT, GetUserId(), i, InvalidOid, lappend(), lappend_oid(), lfirst, list_length(), LookupTypeName(), makeString(), FunctionParameter::mode, FunctionParameter::name, NIL, NOTICE, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_PROCEDURE, ObjectIdGetDatum(), OidIsValid, ParseState::p_rtable, palloc(), palloc0(), PointerGetDatum(), pstrdup(), px(), ReleaseSysCache(), TypeName::setof, transformExpr(), TypeNameToString(), typeTypeId(), and x.

Referenced by CreateFunction(), and DefineAggregate().

◆ IsThereFunctionInNamespace()

void IsThereFunctionInNamespace ( const char *  proname,
int  pronargs,
oidvector proargtypes,
Oid  nspOid 
)

Definition at line 2031 of file functioncmds.c.

2033 {
2034  /* check for duplicate name (more friendly than unique-index failure) */
2037  PointerGetDatum(proargtypes),
2038  ObjectIdGetDatum(nspOid)))
2039  ereport(ERROR,
2040  (errcode(ERRCODE_DUPLICATE_FUNCTION),
2041  errmsg("function %s already exists in schema \"%s\"",
2043  NIL, proargtypes->values),
2044  get_namespace_name(nspOid))));
2045 }
const char * funcname_signature_string(const char *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1995
int16 pronargs
Definition: pg_proc.h:81
NameData proname
Definition: pg_proc.h:35
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:698
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:669
@ PROCNAMEARGSNSP
Definition: syscache.h:78
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:192

References CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, funcname_signature_string(), get_namespace_name(), NIL, ObjectIdGetDatum(), PointerGetDatum(), PROCNAMEARGSNSP, proname, pronargs, SearchSysCacheExists3, and oidvector::values.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

◆ RemoveFunctionById()

void RemoveFunctionById ( Oid  funcOid)

Definition at line 1298 of file functioncmds.c.

1299 {
1300  Relation relation;
1301  HeapTuple tup;
1302  char prokind;
1303 
1304  /*
1305  * Delete the pg_proc tuple.
1306  */
1307  relation = table_open(ProcedureRelationId, RowExclusiveLock);
1308 
1309  tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1310  if (!HeapTupleIsValid(tup)) /* should not happen */
1311  elog(ERROR, "cache lookup failed for function %u", funcOid);
1312 
1313  prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
1314 
1315  CatalogTupleDelete(relation, &tup->t_self);
1316 
1317  ReleaseSysCache(tup);
1318 
1319  table_close(relation, RowExclusiveLock);
1320 
1321  pgstat_drop_function(funcOid);
1322 
1323  /*
1324  * If there's a pg_aggregate tuple, delete that too.
1325  */
1326  if (prokind == PROKIND_AGGREGATE)
1327  {
1328  relation = table_open(AggregateRelationId, RowExclusiveLock);
1329 
1330  tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1331  if (!HeapTupleIsValid(tup)) /* should not happen */
1332  elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1333 
1334  CatalogTupleDelete(relation, &tup->t_self);
1335 
1336  ReleaseSysCache(tup);
1337 
1338  table_close(relation, RowExclusiveLock);
1339  }
1340 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
void pgstat_drop_function(Oid proid)
@ AGGFNOID
Definition: syscache.h:34

References AGGFNOID, CatalogTupleDelete(), elog(), ERROR, GETSTRUCT, HeapTupleIsValid, ObjectIdGetDatum(), pgstat_drop_function(), PROCOID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ update_proconfig_value()

static ArrayType* update_proconfig_value ( ArrayType a,
List set_items 
)
static

Definition at line 650 of file functioncmds.c.

651 {
652  ListCell *l;
653 
654  foreach(l, set_items)
655  {
657 
658  if (sstmt->kind == VAR_RESET_ALL)
659  a = NULL;
660  else
661  {
662  char *valuestr = ExtractSetVariableArgs(sstmt);
663 
664  if (valuestr)
665  a = GUCArrayAdd(a, sstmt->name, valuestr);
666  else /* RESET */
667  a = GUCArrayDelete(a, sstmt->name);
668  }
669  }
670 
671  return a;
672 }
ArrayType * GUCArrayAdd(ArrayType *array, const char *name, const char *value)
Definition: guc.c:6265
ArrayType * GUCArrayDelete(ArrayType *array, const char *name)
Definition: guc.c:6343
char * ExtractSetVariableArgs(VariableSetStmt *stmt)
Definition: guc_funcs.c:167
@ VAR_RESET_ALL
Definition: parsenodes.h:2249
VariableSetKind kind
Definition: parsenodes.h:2255

References a, ExtractSetVariableArgs(), GUCArrayAdd(), GUCArrayDelete(), VariableSetStmt::kind, lfirst_node, VariableSetStmt::name, and VAR_RESET_ALL.

Referenced by AlterFunction(), and compute_function_attributes().