PostgreSQL Source Code  git master
defrem.h File Reference
#include "catalog/objectaddress.h"
#include "nodes/params.h"
#include "parser/parse_node.h"
#include "tcop/dest.h"
#include "utils/array.h"
Include dependency graph for defrem.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void RemoveObjects (DropStmt *stmt)
 
ObjectAddress DefineIndex (Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
 
void ExecReindex (ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
 
char * makeObjectName (const char *name1, const char *name2, const char *label)
 
char * ChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
 
bool CheckIndexCompatible (Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames)
 
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
 
Oid ResolveOpClass (const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
 
ObjectAddress CreateFunction (ParseState *pstate, CreateFunctionStmt *stmt)
 
void RemoveFunctionById (Oid funcOid)
 
ObjectAddress AlterFunction (ParseState *pstate, AlterFunctionStmt *stmt)
 
ObjectAddress CreateCast (CreateCastStmt *stmt)
 
ObjectAddress CreateTransform (CreateTransformStmt *stmt)
 
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)
 
Oid get_transform_oid (Oid type_id, Oid lang_id, bool missing_ok)
 
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)
 
ObjectAddress DefineOperator (List *names, List *parameters)
 
void RemoveOperatorById (Oid operOid)
 
ObjectAddress AlterOperator (AlterOperatorStmt *stmt)
 
ObjectAddress CreateStatistics (CreateStatsStmt *stmt)
 
ObjectAddress AlterStatistics (AlterStatsStmt *stmt)
 
void RemoveStatisticsById (Oid statsOid)
 
void RemoveStatisticsDataById (Oid statsOid, bool inh)
 
Oid StatisticsGetRelation (Oid statId, bool missing_ok)
 
ObjectAddress DefineAggregate (ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters, bool replace)
 
ObjectAddress DefineOpClass (CreateOpClassStmt *stmt)
 
ObjectAddress DefineOpFamily (CreateOpFamilyStmt *stmt)
 
Oid AlterOpFamily (AlterOpFamilyStmt *stmt)
 
void IsThereOpClassInNamespace (const char *opcname, Oid opcmethod, Oid opcnamespace)
 
void IsThereOpFamilyInNamespace (const char *opfname, Oid opfmethod, Oid opfnamespace)
 
Oid get_opclass_oid (Oid amID, List *opclassname, bool missing_ok)
 
Oid get_opfamily_oid (Oid amID, List *opfamilyname, bool missing_ok)
 
ObjectAddress DefineTSParser (List *names, List *parameters)
 
ObjectAddress DefineTSDictionary (List *names, List *parameters)
 
ObjectAddress AlterTSDictionary (AlterTSDictionaryStmt *stmt)
 
ObjectAddress DefineTSTemplate (List *names, List *parameters)
 
ObjectAddress DefineTSConfiguration (List *names, List *parameters, ObjectAddress *copied)
 
void RemoveTSConfigurationById (Oid cfgId)
 
ObjectAddress AlterTSConfiguration (AlterTSConfigurationStmt *stmt)
 
textserialize_deflist (List *deflist)
 
Listdeserialize_deflist (Datum txt)
 
ObjectAddress AlterForeignServerOwner (const char *name, Oid newOwnerId)
 
void AlterForeignServerOwner_oid (Oid, Oid newOwnerId)
 
ObjectAddress AlterForeignDataWrapperOwner (const char *name, Oid newOwnerId)
 
void AlterForeignDataWrapperOwner_oid (Oid fwdId, Oid newOwnerId)
 
ObjectAddress CreateForeignDataWrapper (ParseState *pstate, CreateFdwStmt *stmt)
 
ObjectAddress AlterForeignDataWrapper (ParseState *pstate, AlterFdwStmt *stmt)
 
ObjectAddress CreateForeignServer (CreateForeignServerStmt *stmt)
 
ObjectAddress AlterForeignServer (AlterForeignServerStmt *stmt)
 
ObjectAddress CreateUserMapping (CreateUserMappingStmt *stmt)
 
ObjectAddress AlterUserMapping (AlterUserMappingStmt *stmt)
 
Oid RemoveUserMapping (DropUserMappingStmt *stmt)
 
void CreateForeignTable (CreateForeignTableStmt *stmt, Oid relid)
 
void ImportForeignSchema (ImportForeignSchemaStmt *stmt)
 
Datum transformGenericOptions (Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
 
ObjectAddress CreateAccessMethod (CreateAmStmt *stmt)
 
Oid get_index_am_oid (const char *amname, bool missing_ok)
 
Oid get_table_am_oid (const char *amname, bool missing_ok)
 
Oid get_am_oid (const char *amname, bool missing_ok)
 
char * get_am_name (Oid amOid)
 
char * defGetString (DefElem *def)
 
double defGetNumeric (DefElem *def)
 
bool defGetBoolean (DefElem *def)
 
int32 defGetInt32 (DefElem *def)
 
int64 defGetInt64 (DefElem *def)
 
Oid defGetObjectId (DefElem *def)
 
ListdefGetQualifiedName (DefElem *def)
 
TypeNamedefGetTypeName (DefElem *def)
 
int defGetTypeLength (DefElem *def)
 
ListdefGetStringList (DefElem *def)
 
void errorConflictingDefElem (DefElem *defel, ParseState *pstate) pg_attribute_noreturn()
 

Function Documentation

◆ AlterForeignDataWrapper()

ObjectAddress AlterForeignDataWrapper ( ParseState pstate,
AlterFdwStmt stmt 
)

Definition at line 674 of file foreigncmds.c.

675 {
676  Relation rel;
677  HeapTuple tp;
679  Datum repl_val[Natts_pg_foreign_data_wrapper];
680  bool repl_null[Natts_pg_foreign_data_wrapper];
681  bool repl_repl[Natts_pg_foreign_data_wrapper];
682  Oid fdwId;
683  bool isnull;
684  Datum datum;
685  bool handler_given;
686  bool validator_given;
687  Oid fdwhandler;
688  Oid fdwvalidator;
689  ObjectAddress myself;
690 
691  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
692 
693  /* Must be superuser */
694  if (!superuser())
695  ereport(ERROR,
696  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
697  errmsg("permission denied to alter foreign-data wrapper \"%s\"",
698  stmt->fdwname),
699  errhint("Must be superuser to alter a foreign-data wrapper.")));
700 
701  tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
702  CStringGetDatum(stmt->fdwname));
703 
704  if (!HeapTupleIsValid(tp))
705  ereport(ERROR,
706  (errcode(ERRCODE_UNDEFINED_OBJECT),
707  errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
708 
709  fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
710  fdwId = fdwForm->oid;
711 
712  memset(repl_val, 0, sizeof(repl_val));
713  memset(repl_null, false, sizeof(repl_null));
714  memset(repl_repl, false, sizeof(repl_repl));
715 
716  parse_func_options(pstate, stmt->func_options,
717  &handler_given, &fdwhandler,
718  &validator_given, &fdwvalidator);
719 
720  if (handler_given)
721  {
722  repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
723  repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
724 
725  /*
726  * It could be that the behavior of accessing foreign table changes
727  * with the new handler. Warn about this.
728  */
730  (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
731  }
732 
733  if (validator_given)
734  {
735  repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
736  repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
737 
738  /*
739  * It could be that existing options for the FDW or dependent SERVER,
740  * USER MAPPING or FOREIGN TABLE objects are no longer valid according
741  * to the new validator. Warn about this.
742  */
743  if (OidIsValid(fdwvalidator))
745  (errmsg("changing the foreign-data wrapper validator can cause "
746  "the options for dependent objects to become invalid")));
747  }
748  else
749  {
750  /*
751  * Validator is not changed, but we need it for validating options.
752  */
753  fdwvalidator = fdwForm->fdwvalidator;
754  }
755 
756  /*
757  * If options specified, validate and update.
758  */
759  if (stmt->options)
760  {
761  /* Extract the current options */
762  datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
763  tp,
764  Anum_pg_foreign_data_wrapper_fdwoptions,
765  &isnull);
766  if (isnull)
767  datum = PointerGetDatum(NULL);
768 
769  /* Transform the options */
770  datum = transformGenericOptions(ForeignDataWrapperRelationId,
771  datum,
772  stmt->options,
773  fdwvalidator);
774 
775  if (PointerIsValid(DatumGetPointer(datum)))
776  repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
777  else
778  repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
779 
780  repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
781  }
782 
783  /* Everything looks good - update the tuple */
784  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
785  repl_val, repl_null, repl_repl);
786 
787  CatalogTupleUpdate(rel, &tp->t_self, tp);
788 
789  heap_freetuple(tp);
790 
791  ObjectAddressSet(myself, ForeignDataWrapperRelationId, fdwId);
792 
793  /* Update function dependencies if we changed them */
794  if (handler_given || validator_given)
795  {
796  ObjectAddress referenced;
797 
798  /*
799  * Flush all existing dependency records of this FDW on functions; we
800  * assume there can be none other than the ones we are fixing.
801  */
802  deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
803  fdwId,
804  ProcedureRelationId,
806 
807  /* And build new ones. */
808 
809  if (OidIsValid(fdwhandler))
810  {
811  referenced.classId = ProcedureRelationId;
812  referenced.objectId = fdwhandler;
813  referenced.objectSubId = 0;
814  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
815  }
816 
817  if (OidIsValid(fdwvalidator))
818  {
819  referenced.classId = ProcedureRelationId;
820  referenced.objectId = fdwvalidator;
821  referenced.objectSubId = 0;
822  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
823  }
824  }
825 
826  InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
827 
829 
830  return myself;
831 }
#define PointerIsValid(pointer)
Definition: c.h:763
#define OidIsValid(objectId)
Definition: c.h:775
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static void parse_func_options(ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator)
Definition: foreigncmds.c:518
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:110
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
bool superuser(void)
Definition: superuser.c:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References CatalogTupleUpdate(), ObjectAddress::classId, CStringGetDatum(), DatumGetPointer(), deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, parse_func_options(), PointerGetDatum(), PointerIsValid, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ AlterForeignDataWrapperOwner()

ObjectAddress AlterForeignDataWrapperOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 275 of file foreigncmds.c.

276 {
277  Oid fdwId;
278  HeapTuple tup;
279  Relation rel;
280  ObjectAddress address;
282 
283 
284  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
285 
286  tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
287 
288  if (!HeapTupleIsValid(tup))
289  ereport(ERROR,
290  (errcode(ERRCODE_UNDEFINED_OBJECT),
291  errmsg("foreign-data wrapper \"%s\" does not exist", name)));
292 
294  fdwId = form->oid;
295 
296  AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
297 
298  ObjectAddressSet(address, ForeignDataWrapperRelationId, fdwId);
299 
300  heap_freetuple(tup);
301 
303 
304  return address;
305 }
static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:205
const char * name

References AlterForeignDataWrapperOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, name, ObjectAddressSet, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignDataWrapperOwner_oid()

void AlterForeignDataWrapperOwner_oid ( Oid  fwdId,
Oid  newOwnerId 
)

Definition at line 313 of file foreigncmds.c.

314 {
315  HeapTuple tup;
316  Relation rel;
317 
318  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
319 
320  tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
321 
322  if (!HeapTupleIsValid(tup))
323  ereport(ERROR,
324  (errcode(ERRCODE_UNDEFINED_OBJECT),
325  errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
326 
327  AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
328 
329  heap_freetuple(tup);
330 
332 }

References AlterForeignDataWrapperOwner_internal(), ereport, errcode(), errmsg(), ERROR, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned_Owner().

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)

Definition at line 974 of file foreigncmds.c.

975 {
976  Relation rel;
977  HeapTuple tp;
978  Datum repl_val[Natts_pg_foreign_server];
979  bool repl_null[Natts_pg_foreign_server];
980  bool repl_repl[Natts_pg_foreign_server];
981  Oid srvId;
982  Form_pg_foreign_server srvForm;
983  ObjectAddress address;
984 
985  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
986 
987  tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
988  CStringGetDatum(stmt->servername));
989 
990  if (!HeapTupleIsValid(tp))
991  ereport(ERROR,
992  (errcode(ERRCODE_UNDEFINED_OBJECT),
993  errmsg("server \"%s\" does not exist", stmt->servername)));
994 
995  srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
996  srvId = srvForm->oid;
997 
998  /*
999  * Only owner or a superuser can ALTER a SERVER.
1000  */
1001  if (!object_ownercheck(ForeignServerRelationId, srvId, GetUserId()))
1003  stmt->servername);
1004 
1005  memset(repl_val, 0, sizeof(repl_val));
1006  memset(repl_null, false, sizeof(repl_null));
1007  memset(repl_repl, false, sizeof(repl_repl));
1008 
1009  if (stmt->has_version)
1010  {
1011  /*
1012  * Change the server VERSION string.
1013  */
1014  if (stmt->version)
1015  repl_val[Anum_pg_foreign_server_srvversion - 1] =
1016  CStringGetTextDatum(stmt->version);
1017  else
1018  repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
1019 
1020  repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
1021  }
1022 
1023  if (stmt->options)
1024  {
1025  ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
1026  Datum datum;
1027  bool isnull;
1028 
1029  /* Extract the current srvoptions */
1030  datum = SysCacheGetAttr(FOREIGNSERVEROID,
1031  tp,
1032  Anum_pg_foreign_server_srvoptions,
1033  &isnull);
1034  if (isnull)
1035  datum = PointerGetDatum(NULL);
1036 
1037  /* Prepare the options array */
1038  datum = transformGenericOptions(ForeignServerRelationId,
1039  datum,
1040  stmt->options,
1041  fdw->fdwvalidator);
1042 
1043  if (PointerIsValid(DatumGetPointer(datum)))
1044  repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
1045  else
1046  repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
1047 
1048  repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
1049  }
1050 
1051  /* Everything looks good - update the tuple */
1052  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1053  repl_val, repl_null, repl_repl);
1054 
1055  CatalogTupleUpdate(rel, &tp->t_self, tp);
1056 
1057  InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
1058 
1059  ObjectAddressSet(address, ForeignServerRelationId, srvId);
1060 
1061  heap_freetuple(tp);
1062 
1064 
1065  return address;
1066 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2700
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4142
#define CStringGetTextDatum(s)
Definition: builtins.h:97
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:37
Oid GetUserId(void)
Definition: miscinit.c:514
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2265
FormData_pg_foreign_server * Form_pg_foreign_server

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, OBJECT_FOREIGN_SERVER, object_ownercheck(), ObjectAddressSet, PointerGetDatum(), PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and transformGenericOptions().

Referenced by ProcessUtilitySlow().

◆ AlterForeignServerOwner()

ObjectAddress AlterForeignServerOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 415 of file foreigncmds.c.

416 {
417  Oid servOid;
418  HeapTuple tup;
419  Relation rel;
420  ObjectAddress address;
422 
423  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
424 
425  tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
426 
427  if (!HeapTupleIsValid(tup))
428  ereport(ERROR,
429  (errcode(ERRCODE_UNDEFINED_OBJECT),
430  errmsg("server \"%s\" does not exist", name)));
431 
432  form = (Form_pg_foreign_server) GETSTRUCT(tup);
433  servOid = form->oid;
434 
435  AlterForeignServerOwner_internal(rel, tup, newOwnerId);
436 
437  ObjectAddressSet(address, ForeignServerRelationId, servOid);
438 
439  heap_freetuple(tup);
440 
442 
443  return address;
444 }
static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:338

References AlterForeignServerOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, name, ObjectAddressSet, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignServerOwner_oid()

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)

Definition at line 450 of file foreigncmds.c.

451 {
452  HeapTuple tup;
453  Relation rel;
454 
455  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
456 
457  tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
458 
459  if (!HeapTupleIsValid(tup))
460  ereport(ERROR,
461  (errcode(ERRCODE_UNDEFINED_OBJECT),
462  errmsg("foreign server with OID %u does not exist", srvId)));
463 
464  AlterForeignServerOwner_internal(rel, tup, newOwnerId);
465 
466  heap_freetuple(tup);
467 
469 }

References AlterForeignServerOwner_internal(), ereport, errcode(), errmsg(), ERROR, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned_Owner().

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)

Definition at line 1343 of file functioncmds.c.

1344 {
1345  HeapTuple tup;
1346  Oid funcOid;
1347  Form_pg_proc procForm;
1348  bool is_procedure;
1349  Relation rel;
1350  ListCell *l;
1351  DefElem *volatility_item = NULL;
1352  DefElem *strict_item = NULL;
1353  DefElem *security_def_item = NULL;
1354  DefElem *leakproof_item = NULL;
1355  List *set_items = NIL;
1356  DefElem *cost_item = NULL;
1357  DefElem *rows_item = NULL;
1358  DefElem *support_item = NULL;
1359  DefElem *parallel_item = NULL;
1360  ObjectAddress address;
1361 
1362  rel = table_open(ProcedureRelationId, RowExclusiveLock);
1363 
1364  funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1365 
1366  ObjectAddressSet(address, ProcedureRelationId, funcOid);
1367 
1368  tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1369  if (!HeapTupleIsValid(tup)) /* should not happen */
1370  elog(ERROR, "cache lookup failed for function %u", funcOid);
1371 
1372  procForm = (Form_pg_proc) GETSTRUCT(tup);
1373 
1374  /* Permission check: must own function */
1375  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
1377  NameListToString(stmt->func->objname));
1378 
1379  if (procForm->prokind == PROKIND_AGGREGATE)
1380  ereport(ERROR,
1381  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1382  errmsg("\"%s\" is an aggregate function",
1383  NameListToString(stmt->func->objname))));
1384 
1385  is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1386 
1387  /* Examine requested actions. */
1388  foreach(l, stmt->actions)
1389  {
1390  DefElem *defel = (DefElem *) lfirst(l);
1391 
1392  if (compute_common_attribute(pstate,
1393  is_procedure,
1394  defel,
1395  &volatility_item,
1396  &strict_item,
1397  &security_def_item,
1398  &leakproof_item,
1399  &set_items,
1400  &cost_item,
1401  &rows_item,
1402  &support_item,
1403  &parallel_item) == false)
1404  elog(ERROR, "option \"%s\" not recognized", defel->defname);
1405  }
1406 
1407  if (volatility_item)
1408  procForm->provolatile = interpret_func_volatility(volatility_item);
1409  if (strict_item)
1410  procForm->proisstrict = boolVal(strict_item->arg);
1411  if (security_def_item)
1412  procForm->prosecdef = boolVal(security_def_item->arg);
1413  if (leakproof_item)
1414  {
1415  procForm->proleakproof = boolVal(leakproof_item->arg);
1416  if (procForm->proleakproof && !superuser())
1417  ereport(ERROR,
1418  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1419  errmsg("only superuser can define a leakproof function")));
1420  }
1421  if (cost_item)
1422  {
1423  procForm->procost = defGetNumeric(cost_item);
1424  if (procForm->procost <= 0)
1425  ereport(ERROR,
1426  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1427  errmsg("COST must be positive")));
1428  }
1429  if (rows_item)
1430  {
1431  procForm->prorows = defGetNumeric(rows_item);
1432  if (procForm->prorows <= 0)
1433  ereport(ERROR,
1434  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1435  errmsg("ROWS must be positive")));
1436  if (!procForm->proretset)
1437  ereport(ERROR,
1438  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1439  errmsg("ROWS is not applicable when function does not return a set")));
1440  }
1441  if (support_item)
1442  {
1443  /* interpret_func_support handles the privilege check */
1444  Oid newsupport = interpret_func_support(support_item);
1445 
1446  /* Add or replace dependency on support function */
1447  if (OidIsValid(procForm->prosupport))
1448  {
1449  if (changeDependencyFor(ProcedureRelationId, funcOid,
1450  ProcedureRelationId, procForm->prosupport,
1451  newsupport) != 1)
1452  elog(ERROR, "could not change support dependency for function %s",
1453  get_func_name(funcOid));
1454  }
1455  else
1456  {
1457  ObjectAddress referenced;
1458 
1459  referenced.classId = ProcedureRelationId;
1460  referenced.objectId = newsupport;
1461  referenced.objectSubId = 0;
1462  recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
1463  }
1464 
1465  procForm->prosupport = newsupport;
1466  }
1467  if (parallel_item)
1468  procForm->proparallel = interpret_func_parallel(parallel_item);
1469  if (set_items)
1470  {
1471  Datum datum;
1472  bool isnull;
1473  ArrayType *a;
1474  Datum repl_val[Natts_pg_proc];
1475  bool repl_null[Natts_pg_proc];
1476  bool repl_repl[Natts_pg_proc];
1477 
1478  /* extract existing proconfig setting */
1479  datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
1480  a = isnull ? NULL : DatumGetArrayTypeP(datum);
1481 
1482  /* update according to each SET or RESET item, left to right */
1483  a = update_proconfig_value(a, set_items);
1484 
1485  /* update the tuple */
1486  memset(repl_repl, false, sizeof(repl_repl));
1487  repl_repl[Anum_pg_proc_proconfig - 1] = true;
1488 
1489  if (a == NULL)
1490  {
1491  repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
1492  repl_null[Anum_pg_proc_proconfig - 1] = true;
1493  }
1494  else
1495  {
1496  repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
1497  repl_null[Anum_pg_proc_proconfig - 1] = false;
1498  }
1499 
1500  tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1501  repl_val, repl_null, repl_repl);
1502  }
1503  /* DO NOT put more touches of procForm below here; it's now dangling. */
1504 
1505  /* Do the update */
1506  CatalogTupleUpdate(rel, &tup->t_self, tup);
1507 
1508  InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
1509 
1510  table_close(rel, NoLock);
1511  heap_freetuple(tup);
1512 
1513  return address;
1514 }
#define DatumGetArrayTypeP(X)
Definition: array.h:261
double defGetNumeric(DefElem *def)
Definition: define.c:81
#define elog(elevel,...)
Definition: elog.h:225
static ArrayType * update_proconfig_value(ArrayType *a, List *set_items)
Definition: functioncmds.c:645
static Oid interpret_func_support(DefElem *defel)
Definition: functioncmds.c:670
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:500
static char interpret_func_volatility(DefElem *defel)
Definition: functioncmds.c:602
static char interpret_func_parallel(DefElem *defel)
Definition: functioncmds.c:620
int a
Definition: isn.c:69
#define NoLock
Definition: lockdefs.h:34
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
char * NameListToString(const List *names)
Definition: namespace.c:3579
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2206
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:458
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
char * defname
Definition: parsenodes.h:815
Node * arg
Definition: parsenodes.h:816
Definition: pg_list.h:54
#define boolVal(v)
Definition: value.h:81

References a, aclcheck_error(), ACLCHECK_NOT_OWNER, DefElem::arg, boolVal, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, compute_common_attribute(), DatumGetArrayTypeP, defGetNumeric(), DefElem::defname, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg(), ERROR, get_func_name(), 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, OidIsValid, PointerGetDatum(), recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and update_proconfig_value().

Referenced by ProcessUtilitySlow().

◆ AlterOperator()

ObjectAddress AlterOperator ( AlterOperatorStmt stmt)

Definition at line 462 of file operatorcmds.c.

463 {
464  ObjectAddress address;
465  Oid oprId;
466  Relation catalog;
467  HeapTuple tup;
468  Form_pg_operator oprForm;
469  int i;
470  ListCell *pl;
471  Datum values[Natts_pg_operator];
472  bool nulls[Natts_pg_operator];
473  bool replaces[Natts_pg_operator];
474  List *restrictionName = NIL; /* optional restrict. sel. function */
475  bool updateRestriction = false;
476  Oid restrictionOid;
477  List *joinName = NIL; /* optional join sel. function */
478  bool updateJoin = false;
479  Oid joinOid;
480  List *commutatorName = NIL; /* optional commutator operator name */
481  Oid commutatorOid;
482  List *negatorName = NIL; /* optional negator operator name */
483  Oid negatorOid;
484  bool canMerge = false;
485  bool updateMerges = false;
486  bool canHash = false;
487  bool updateHashes = false;
488 
489  /* Look up the operator */
490  oprId = LookupOperWithArgs(stmt->opername, false);
491  catalog = table_open(OperatorRelationId, RowExclusiveLock);
492  tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
493  if (!HeapTupleIsValid(tup))
494  elog(ERROR, "cache lookup failed for operator %u", oprId);
495  oprForm = (Form_pg_operator) GETSTRUCT(tup);
496 
497  /* Process options */
498  foreach(pl, stmt->options)
499  {
500  DefElem *defel = (DefElem *) lfirst(pl);
501  List *param;
502 
503  if (defel->arg == NULL)
504  param = NIL; /* NONE, removes the function */
505  else
506  param = defGetQualifiedName(defel);
507 
508  if (strcmp(defel->defname, "restrict") == 0)
509  {
510  restrictionName = param;
511  updateRestriction = true;
512  }
513  else if (strcmp(defel->defname, "join") == 0)
514  {
515  joinName = param;
516  updateJoin = true;
517  }
518  else if (strcmp(defel->defname, "commutator") == 0)
519  {
520  commutatorName = defGetQualifiedName(defel);
521  }
522  else if (strcmp(defel->defname, "negator") == 0)
523  {
524  negatorName = defGetQualifiedName(defel);
525  }
526  else if (strcmp(defel->defname, "merges") == 0)
527  {
528  canMerge = defGetBoolean(defel);
529  updateMerges = true;
530  }
531  else if (strcmp(defel->defname, "hashes") == 0)
532  {
533  canHash = defGetBoolean(defel);
534  updateHashes = true;
535  }
536 
537  /*
538  * The rest of the options that CREATE accepts cannot be changed.
539  * Check for them so that we can give a meaningful error message.
540  */
541  else if (strcmp(defel->defname, "leftarg") == 0 ||
542  strcmp(defel->defname, "rightarg") == 0 ||
543  strcmp(defel->defname, "function") == 0 ||
544  strcmp(defel->defname, "procedure") == 0)
545  {
546  ereport(ERROR,
547  (errcode(ERRCODE_SYNTAX_ERROR),
548  errmsg("operator attribute \"%s\" cannot be changed",
549  defel->defname)));
550  }
551  else
552  ereport(ERROR,
553  (errcode(ERRCODE_SYNTAX_ERROR),
554  errmsg("operator attribute \"%s\" not recognized",
555  defel->defname)));
556  }
557 
558  /* Check permissions. Must be owner. */
559  if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
561  NameStr(oprForm->oprname));
562 
563  /*
564  * Look up OIDs for any parameters specified
565  */
566  if (restrictionName)
567  restrictionOid = ValidateRestrictionEstimator(restrictionName);
568  else
569  restrictionOid = InvalidOid;
570  if (joinName)
571  joinOid = ValidateJoinEstimator(joinName);
572  else
573  joinOid = InvalidOid;
574 
575  if (commutatorName)
576  {
577  /* commutator has reversed arg types */
578  commutatorOid = ValidateOperatorReference(commutatorName,
579  oprForm->oprright,
580  oprForm->oprleft);
581 
582  /*
583  * We don't need to do anything extra for a self commutator as in
584  * OperatorCreate, since the operator surely exists already.
585  */
586  }
587  else
588  commutatorOid = InvalidOid;
589 
590  if (negatorName)
591  {
592  negatorOid = ValidateOperatorReference(negatorName,
593  oprForm->oprleft,
594  oprForm->oprright);
595 
596  /* Must reject self-negation */
597  if (negatorOid == oprForm->oid)
598  ereport(ERROR,
599  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
600  errmsg("operator cannot be its own negator")));
601  }
602  else
603  {
604  negatorOid = InvalidOid;
605  }
606 
607  /*
608  * Check that we're not changing any attributes that might be depended on
609  * by plans, while allowing no-op updates.
610  */
611  if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
612  commutatorOid != oprForm->oprcom)
613  ereport(ERROR,
614  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
615  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
616  "commutator")));
617 
618  if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
619  negatorOid != oprForm->oprnegate)
620  ereport(ERROR,
621  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
622  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
623  "negator")));
624 
625  if (updateMerges && oprForm->oprcanmerge && !canMerge)
626  ereport(ERROR,
627  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
628  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
629  "merges")));
630 
631  if (updateHashes && oprForm->oprcanhash && !canHash)
632  ereport(ERROR,
633  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
634  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
635  "hashes")));
636 
637  /* Perform additional checks, like OperatorCreate does */
638  OperatorValidateParams(oprForm->oprleft,
639  oprForm->oprright,
640  oprForm->oprresult,
641  OidIsValid(commutatorOid),
642  OidIsValid(negatorOid),
643  OidIsValid(restrictionOid),
644  OidIsValid(joinOid),
645  canMerge,
646  canHash);
647 
648  /* Update the tuple */
649  for (i = 0; i < Natts_pg_operator; ++i)
650  {
651  values[i] = (Datum) 0;
652  replaces[i] = false;
653  nulls[i] = false;
654  }
655  if (updateRestriction)
656  {
657  replaces[Anum_pg_operator_oprrest - 1] = true;
658  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
659  }
660  if (updateJoin)
661  {
662  replaces[Anum_pg_operator_oprjoin - 1] = true;
663  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
664  }
665  if (OidIsValid(commutatorOid))
666  {
667  replaces[Anum_pg_operator_oprcom - 1] = true;
668  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
669  }
670  if (OidIsValid(negatorOid))
671  {
672  replaces[Anum_pg_operator_oprnegate - 1] = true;
673  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
674  }
675  if (updateMerges)
676  {
677  replaces[Anum_pg_operator_oprcanmerge - 1] = true;
678  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
679  }
680  if (updateHashes)
681  {
682  replaces[Anum_pg_operator_oprcanhash - 1] = true;
683  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
684  }
685 
686  tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
687  values, nulls, replaces);
688 
689  CatalogTupleUpdate(catalog, &tup->t_self, tup);
690 
691  address = makeOperatorDependencies(tup, false, true);
692 
693  if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
694  OperatorUpd(oprId, commutatorOid, negatorOid, false);
695 
696  InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
697 
698  table_close(catalog, NoLock);
699 
700  return address;
701 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define NameStr(name)
Definition: c.h:746
bool defGetBoolean(DefElem *def)
Definition: define.c:107
List * defGetQualifiedName(DefElem *def)
Definition: define.c:252
int i
Definition: isn.c:73
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:310
static Oid ValidateOperatorReference(List *name, Oid leftTypeId, Oid rightTypeId)
Definition: operatorcmds.c:372
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:275
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:133
@ OBJECT_OPERATOR
Definition: parsenodes.h:2273
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
Definition: pg_operator.c:556
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
Definition: pg_operator.c:853
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:684
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
#define InvalidOid
Definition: postgres_ext.h:36

References aclcheck_error(), ACLCHECK_NOT_OWNER, DefElem::arg, BoolGetDatum(), CatalogTupleUpdate(), defGetBoolean(), defGetQualifiedName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetUserId(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst, LookupOperWithArgs(), makeOperatorDependencies(), NameStr, NIL, NoLock, OBJECT_OPERATOR, object_ownercheck(), ObjectIdGetDatum(), OidIsValid, OperatorUpd(), OperatorValidateParams(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, HeapTupleData::t_self, table_close(), table_open(), ValidateJoinEstimator(), ValidateOperatorReference(), ValidateRestrictionEstimator(), and values.

Referenced by ProcessUtilitySlow().

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 816 of file opclasscmds.c.

817 {
818  Oid amoid, /* our AM's oid */
819  opfamilyoid; /* oid of opfamily */
820  int maxOpNumber, /* amstrategies value */
821  optsProcNumber, /* amoptsprocnum value */
822  maxProcNumber; /* amsupport value */
823  HeapTuple tup;
824  Form_pg_am amform;
825  IndexAmRoutine *amroutine;
826 
827  /* Get necessary info about access method */
828  tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
829  if (!HeapTupleIsValid(tup))
830  ereport(ERROR,
831  (errcode(ERRCODE_UNDEFINED_OBJECT),
832  errmsg("access method \"%s\" does not exist",
833  stmt->amname)));
834 
835  amform = (Form_pg_am) GETSTRUCT(tup);
836  amoid = amform->oid;
837  amroutine = GetIndexAmRoutineByAmId(amoid, false);
838  ReleaseSysCache(tup);
839 
840  maxOpNumber = amroutine->amstrategies;
841  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
842  if (maxOpNumber <= 0)
843  maxOpNumber = SHRT_MAX;
844  maxProcNumber = amroutine->amsupport;
845  optsProcNumber = amroutine->amoptsprocnum;
846 
847  /* XXX Should we make any privilege check against the AM? */
848 
849  /* Look up the opfamily */
850  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
851 
852  /*
853  * Currently, we require superuser privileges to alter an opfamily.
854  *
855  * XXX re-enable NOT_USED code sections below if you remove this test.
856  */
857  if (!superuser())
858  ereport(ERROR,
859  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
860  errmsg("must be superuser to alter an operator family")));
861 
862  /*
863  * ADD and DROP cases need separate code from here on down.
864  */
865  if (stmt->isDrop)
866  AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
867  maxOpNumber, maxProcNumber, stmt->items);
868  else
869  AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
870  maxOpNumber, maxProcNumber, optsProcNumber,
871  stmt->items);
872 
873  return opfamilyoid;
874 }
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:1029
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:138
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int optsProcNumber, List *items)
Definition: opclasscmds.c:880
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
uint16 amoptsprocnum
Definition: amapi.h:222
uint16 amsupport
Definition: amapi.h:220
uint16 amstrategies
Definition: amapi.h:218
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, ReleaseSysCache(), SearchSysCache1(), stmt, and superuser().

Referenced by ProcessUtilitySlow().

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)

Definition at line 599 of file statscmds.c.

600 {
601  Relation rel;
602  Oid stxoid;
603  HeapTuple oldtup;
604  HeapTuple newtup;
605  Datum repl_val[Natts_pg_statistic_ext];
606  bool repl_null[Natts_pg_statistic_ext];
607  bool repl_repl[Natts_pg_statistic_ext];
608  ObjectAddress address;
609  int newtarget = 0;
610  bool newtarget_default;
611 
612  /* -1 was used in previous versions for the default setting */
613  if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
614  {
615  newtarget = intVal(stmt->stxstattarget);
616  newtarget_default = false;
617  }
618  else
619  newtarget_default = true;
620 
621  if (!newtarget_default)
622  {
623  /* Limit statistics target to a sane range */
624  if (newtarget < 0)
625  {
626  ereport(ERROR,
627  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
628  errmsg("statistics target %d is too low",
629  newtarget)));
630  }
631  else if (newtarget > MAX_STATISTICS_TARGET)
632  {
633  newtarget = MAX_STATISTICS_TARGET;
635  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
636  errmsg("lowering statistics target to %d",
637  newtarget)));
638  }
639  }
640 
641  /* lookup OID of the statistics object */
642  stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
643 
644  /*
645  * If we got here and the OID is not valid, it means the statistics object
646  * does not exist, but the command specified IF EXISTS. So report this as
647  * a simple NOTICE and we're done.
648  */
649  if (!OidIsValid(stxoid))
650  {
651  char *schemaname;
652  char *statname;
653 
654  Assert(stmt->missing_ok);
655 
656  DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
657 
658  if (schemaname)
659  ereport(NOTICE,
660  (errmsg("statistics object \"%s.%s\" does not exist, skipping",
661  schemaname, statname)));
662  else
663  ereport(NOTICE,
664  (errmsg("statistics object \"%s\" does not exist, skipping",
665  statname)));
666 
667  return InvalidObjectAddress;
668  }
669 
670  /* Search pg_statistic_ext */
671  rel = table_open(StatisticExtRelationId, RowExclusiveLock);
672 
673  oldtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxoid));
674  if (!HeapTupleIsValid(oldtup))
675  elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
676 
677  /* Must be owner of the existing statistics object */
678  if (!object_ownercheck(StatisticExtRelationId, stxoid, GetUserId()))
680  NameListToString(stmt->defnames));
681 
682  /* Build new tuple. */
683  memset(repl_val, 0, sizeof(repl_val));
684  memset(repl_null, false, sizeof(repl_null));
685  memset(repl_repl, false, sizeof(repl_repl));
686 
687  /* replace the stxstattarget column */
688  repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
689  if (!newtarget_default)
690  repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget);
691  else
692  repl_null[Anum_pg_statistic_ext_stxstattarget - 1] = true;
693 
694  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
695  repl_val, repl_null, repl_repl);
696 
697  /* Update system catalog. */
698  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
699 
700  InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0);
701 
702  ObjectAddressSet(address, StatisticExtRelationId, stxoid);
703 
704  /*
705  * NOTE: because we only support altering the statistics target, not the
706  * other fields, there is no need to update dependencies.
707  */
708 
709  heap_freetuple(newtup);
710  ReleaseSysCache(oldtup);
711 
713 
714  return address;
715 }
#define Assert(condition)
Definition: c.h:858
#define NOTICE
Definition: elog.h:35
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2560
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:3286
const ObjectAddress InvalidObjectAddress
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2287
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
#define MAX_STATISTICS_TARGET
Definition: vacuum.h:305
#define intVal(v)
Definition: value.h:79

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, CatalogTupleUpdate(), DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, get_statistics_object_oid(), GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), intVal, InvalidObjectAddress, InvokeObjectPostAlterHook, MAX_STATISTICS_TARGET, NameListToString(), NOTICE, object_ownercheck(), OBJECT_STATISTIC_EXT, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), stmt, HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ AlterTSConfiguration()

ObjectAddress AlterTSConfiguration ( AlterTSConfigurationStmt stmt)

Definition at line 1156 of file tsearchcmds.c.

1157 {
1158  HeapTuple tup;
1159  Oid cfgId;
1160  Relation relMap;
1161  ObjectAddress address;
1162 
1163  /* Find the configuration */
1164  tup = GetTSConfigTuple(stmt->cfgname);
1165  if (!HeapTupleIsValid(tup))
1166  ereport(ERROR,
1167  (errcode(ERRCODE_UNDEFINED_OBJECT),
1168  errmsg("text search configuration \"%s\" does not exist",
1169  NameListToString(stmt->cfgname))));
1170 
1171  cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid;
1172 
1173  /* must be owner */
1174  if (!object_ownercheck(TSConfigRelationId, cfgId, GetUserId()))
1176  NameListToString(stmt->cfgname));
1177 
1178  relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);
1179 
1180  /* Add or drop mappings */
1181  if (stmt->dicts)
1182  MakeConfigurationMapping(stmt, tup, relMap);
1183  else if (stmt->tokentype)
1184  DropConfigurationMapping(stmt, tup, relMap);
1185 
1186  /* Update dependencies */
1187  makeConfigurationDependencies(tup, true, relMap);
1188 
1189  InvokeObjectPostAlterHook(TSConfigRelationId, cfgId, 0);
1190 
1191  ObjectAddressSet(address, TSConfigRelationId, cfgId);
1192 
1193  table_close(relMap, RowExclusiveLock);
1194 
1195  ReleaseSysCache(tup);
1196 
1197  return address;
1198 }
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2293
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:48
static ObjectAddress makeConfigurationDependencies(HeapTuple tuple, bool removeOld, Relation mapRel)
Definition: tsearchcmds.c:812
static HeapTuple GetTSConfigTuple(List *names)
Definition: tsearchcmds.c:787
static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)
Definition: tsearchcmds.c:1491
static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)
Definition: tsearchcmds.c:1288

References aclcheck_error(), ACLCHECK_NOT_OWNER, DropConfigurationMapping(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetTSConfigTuple(), GetUserId(), HeapTupleIsValid, InvokeObjectPostAlterHook, makeConfigurationDependencies(), MakeConfigurationMapping(), NameListToString(), object_ownercheck(), OBJECT_TSCONFIGURATION, ObjectAddressSet, ReleaseSysCache(), RowExclusiveLock, stmt, table_close(), and table_open().

Referenced by ProcessUtilitySlow().

◆ AlterTSDictionary()

ObjectAddress AlterTSDictionary ( AlterTSDictionaryStmt stmt)

Definition at line 493 of file tsearchcmds.c.

494 {
495  HeapTuple tup,
496  newtup;
497  Relation rel;
498  Oid dictId;
499  ListCell *pl;
500  List *dictoptions;
501  Datum opt;
502  bool isnull;
503  Datum repl_val[Natts_pg_ts_dict];
504  bool repl_null[Natts_pg_ts_dict];
505  bool repl_repl[Natts_pg_ts_dict];
506  ObjectAddress address;
507 
508  dictId = get_ts_dict_oid(stmt->dictname, false);
509 
510  rel = table_open(TSDictionaryRelationId, RowExclusiveLock);
511 
512  tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
513 
514  if (!HeapTupleIsValid(tup))
515  elog(ERROR, "cache lookup failed for text search dictionary %u",
516  dictId);
517 
518  /* must be owner */
519  if (!object_ownercheck(TSDictionaryRelationId, dictId, GetUserId()))
521  NameListToString(stmt->dictname));
522 
523  /* deserialize the existing set of options */
524  opt = SysCacheGetAttr(TSDICTOID, tup,
525  Anum_pg_ts_dict_dictinitoption,
526  &isnull);
527  if (isnull)
528  dictoptions = NIL;
529  else
530  dictoptions = deserialize_deflist(opt);
531 
532  /*
533  * Modify the options list as per specified changes
534  */
535  foreach(pl, stmt->options)
536  {
537  DefElem *defel = (DefElem *) lfirst(pl);
538  ListCell *cell;
539 
540  /*
541  * Remove any matches ...
542  */
543  foreach(cell, dictoptions)
544  {
545  DefElem *oldel = (DefElem *) lfirst(cell);
546 
547  if (strcmp(oldel->defname, defel->defname) == 0)
548  dictoptions = foreach_delete_current(dictoptions, cell);
549  }
550 
551  /*
552  * and add new value if it's got one
553  */
554  if (defel->arg)
555  dictoptions = lappend(dictoptions, defel);
556  }
557 
558  /*
559  * Validate
560  */
561  verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
562  dictoptions);
563 
564  /*
565  * Looks good, update
566  */
567  memset(repl_val, 0, sizeof(repl_val));
568  memset(repl_null, false, sizeof(repl_null));
569  memset(repl_repl, false, sizeof(repl_repl));
570 
571  if (dictoptions)
572  repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
573  PointerGetDatum(serialize_deflist(dictoptions));
574  else
575  repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true;
576  repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true;
577 
578  newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
579  repl_val, repl_null, repl_repl);
580 
581  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
582 
583  InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
584 
585  ObjectAddressSet(address, TSDictionaryRelationId, dictId);
586 
587  /*
588  * NOTE: because we only support altering the options, not the template,
589  * there is no need to update dependencies. This might have to change if
590  * the options ever reference inside-the-database objects.
591  */
592 
593  heap_freetuple(newtup);
594  ReleaseSysCache(tup);
595 
597 
598  return address;
599 }
List * lappend(List *list, void *datum)
Definition: list.c:339
Oid get_ts_dict_oid(List *names, bool missing_ok)
Definition: namespace.c:2846
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2294
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
FormData_pg_ts_dict * Form_pg_ts_dict
Definition: pg_ts_dict.h:52
List * deserialize_deflist(Datum txt)
Definition: tsearchcmds.c:1621
static void verify_dictoptions(Oid tmplId, List *dictoptions)
Definition: tsearchcmds.c:342
text * serialize_deflist(List *deflist)
Definition: tsearchcmds.c:1565

References aclcheck_error(), ACLCHECK_NOT_OWNER, DefElem::arg, CatalogTupleUpdate(), DefElem::defname, deserialize_deflist(), elog, ERROR, foreach_delete_current, get_ts_dict_oid(), GETSTRUCT, GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, lappend(), lfirst, NameListToString(), NIL, object_ownercheck(), OBJECT_TSDICTIONARY, ObjectAddressSet, ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), serialize_deflist(), stmt, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), and verify_dictoptions().

Referenced by ProcessUtilitySlow().

◆ AlterUserMapping()

ObjectAddress AlterUserMapping ( AlterUserMappingStmt stmt)

Definition at line 1226 of file foreigncmds.c.

1227 {
1228  Relation rel;
1229  HeapTuple tp;
1230  Datum repl_val[Natts_pg_user_mapping];
1231  bool repl_null[Natts_pg_user_mapping];
1232  bool repl_repl[Natts_pg_user_mapping];
1233  Oid useId;
1234  Oid umId;
1235  ForeignServer *srv;
1236  ObjectAddress address;
1237  RoleSpec *role = (RoleSpec *) stmt->user;
1238 
1239  rel = table_open(UserMappingRelationId, RowExclusiveLock);
1240 
1241  if (role->roletype == ROLESPEC_PUBLIC)
1242  useId = ACL_ID_PUBLIC;
1243  else
1244  useId = get_rolespec_oid(stmt->user, false);
1245 
1246  srv = GetForeignServerByName(stmt->servername, false);
1247 
1248  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1249  ObjectIdGetDatum(useId),
1250  ObjectIdGetDatum(srv->serverid));
1251  if (!OidIsValid(umId))
1252  ereport(ERROR,
1253  (errcode(ERRCODE_UNDEFINED_OBJECT),
1254  errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1255  MappingUserName(useId), stmt->servername)));
1256 
1257  user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1258 
1259  tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
1260 
1261  if (!HeapTupleIsValid(tp))
1262  elog(ERROR, "cache lookup failed for user mapping %u", umId);
1263 
1264  memset(repl_val, 0, sizeof(repl_val));
1265  memset(repl_null, false, sizeof(repl_null));
1266  memset(repl_repl, false, sizeof(repl_repl));
1267 
1268  if (stmt->options)
1269  {
1270  ForeignDataWrapper *fdw;
1271  Datum datum;
1272  bool isnull;
1273 
1274  /*
1275  * Process the options.
1276  */
1277 
1278  fdw = GetForeignDataWrapper(srv->fdwid);
1279 
1280  datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
1281  tp,
1282  Anum_pg_user_mapping_umoptions,
1283  &isnull);
1284  if (isnull)
1285  datum = PointerGetDatum(NULL);
1286 
1287  /* Prepare the options array */
1288  datum = transformGenericOptions(UserMappingRelationId,
1289  datum,
1290  stmt->options,
1291  fdw->fdwvalidator);
1292 
1293  if (PointerIsValid(DatumGetPointer(datum)))
1294  repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
1295  else
1296  repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
1297 
1298  repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
1299  }
1300 
1301  /* Everything looks good - update the tuple */
1302  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1303  repl_val, repl_null, repl_repl);
1304 
1305  CatalogTupleUpdate(rel, &tp->t_self, tp);
1306 
1307  InvokeObjectPostAlterHook(UserMappingRelationId,
1308  umId, 0);
1309 
1310  ObjectAddressSet(address, UserMappingRelationId, umId);
1311 
1312  heap_freetuple(tp);
1313 
1315 
1316  return address;
1317 }
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5454
#define ACL_ID_PUBLIC
Definition: acl.h:46
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition: foreign.c:182
#define MappingUserName(userid)
Definition: foreign.h:20
static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
Definition: foreigncmds.c:1075
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:398
Oid serverid
Definition: foreign.h:36
RoleSpecType roletype
Definition: parsenodes.h:404
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:106

References ACL_ID_PUBLIC, CatalogTupleUpdate(), DatumGetPointer(), elog, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, get_rolespec_oid(), GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, MappingUserName, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), PointerIsValid, RelationGetDescr, ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, stmt, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), and user_mapping_ddl_aclcheck().

Referenced by ProcessUtilitySlow().

◆ CallStmtResultDesc()

TupleDesc CallStmtResultDesc ( CallStmt stmt)

Definition at line 2365 of file functioncmds.c.

2366 {
2367  FuncExpr *fexpr;
2368  HeapTuple tuple;
2369  TupleDesc tupdesc;
2370 
2371  fexpr = stmt->funcexpr;
2372 
2373  tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2374  if (!HeapTupleIsValid(tuple))
2375  elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
2376 
2377  tupdesc = build_function_result_tupdesc_t(tuple);
2378 
2379  ReleaseSysCache(tuple);
2380 
2381  /*
2382  * The result of build_function_result_tupdesc_t has the right column
2383  * names, but it just has the declared output argument types, which is the
2384  * wrong thing in polymorphic cases. Get the correct types by examining
2385  * stmt->outargs. We intentionally keep the atttypmod as -1 and the
2386  * attcollation as the type's default, since that's always the appropriate
2387  * thing for function outputs; there's no point in considering any
2388  * additional info available from outargs. Note that tupdesc is null if
2389  * there are no outargs.
2390  */
2391  if (tupdesc)
2392  {
2393  Assert(tupdesc->natts == list_length(stmt->outargs));
2394  for (int i = 0; i < tupdesc->natts; i++)
2395  {
2396  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2397  Node *outarg = (Node *) list_nth(stmt->outargs, i);
2398 
2399  TupleDescInitEntry(tupdesc,
2400  i + 1,
2401  NameStr(att->attname),
2402  exprType(outarg),
2403  -1,
2404  0);
2405  }
2406  }
2407 
2408  return tupdesc;
2409 }
TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple)
Definition: funcapi.c:1705
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static int list_length(const List *l)
Definition: pg_list.h:152
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
Oid funcid
Definition: primnodes.h:750
Definition: nodes.h:129
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References Assert, build_function_result_tupdesc_t(), elog, ERROR, exprType(), FuncExpr::funcid, HeapTupleIsValid, i, list_length(), list_nth(), NameStr, TupleDescData::natts, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache1(), stmt, TupleDescAttr, and TupleDescInitEntry().

Referenced by UtilityTupleDescriptor().

◆ CheckIndexCompatible()

bool CheckIndexCompatible ( Oid  oldId,
const char *  accessMethodName,
const List attributeList,
const List exclusionOpNames 
)

Definition at line 174 of file indexcmds.c.

178 {
179  bool isconstraint;
180  Oid *typeIds;
181  Oid *collationIds;
182  Oid *opclassIds;
183  Datum *opclassOptions;
184  Oid accessMethodId;
185  Oid relationId;
186  HeapTuple tuple;
187  Form_pg_index indexForm;
188  Form_pg_am accessMethodForm;
189  IndexAmRoutine *amRoutine;
190  bool amcanorder;
191  bool amsummarizing;
192  int16 *coloptions;
193  IndexInfo *indexInfo;
194  int numberOfAttributes;
195  int old_natts;
196  bool ret = true;
197  oidvector *old_indclass;
198  oidvector *old_indcollation;
199  Relation irel;
200  int i;
201  Datum d;
202 
203  /* Caller should already have the relation locked in some way. */
204  relationId = IndexGetRelation(oldId, false);
205 
206  /*
207  * We can pretend isconstraint = false unconditionally. It only serves to
208  * decide the text of an error message that should never happen for us.
209  */
210  isconstraint = false;
211 
212  numberOfAttributes = list_length(attributeList);
213  Assert(numberOfAttributes > 0);
214  Assert(numberOfAttributes <= INDEX_MAX_KEYS);
215 
216  /* look up the access method */
217  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
218  if (!HeapTupleIsValid(tuple))
219  ereport(ERROR,
220  (errcode(ERRCODE_UNDEFINED_OBJECT),
221  errmsg("access method \"%s\" does not exist",
222  accessMethodName)));
223  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
224  accessMethodId = accessMethodForm->oid;
225  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
226  ReleaseSysCache(tuple);
227 
228  amcanorder = amRoutine->amcanorder;
229  amsummarizing = amRoutine->amsummarizing;
230 
231  /*
232  * Compute the operator classes, collations, and exclusion operators for
233  * the new index, so we can test whether it's compatible with the existing
234  * one. Note that ComputeIndexAttrs might fail here, but that's OK:
235  * DefineIndex would have failed later. Our attributeList contains only
236  * key attributes, thus we're filling ii_NumIndexAttrs and
237  * ii_NumIndexKeyAttrs with same value.
238  */
239  indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes,
240  accessMethodId, NIL, NIL, false, false,
241  false, false, amsummarizing);
242  typeIds = palloc_array(Oid, numberOfAttributes);
243  collationIds = palloc_array(Oid, numberOfAttributes);
244  opclassIds = palloc_array(Oid, numberOfAttributes);
245  opclassOptions = palloc_array(Datum, numberOfAttributes);
246  coloptions = palloc_array(int16, numberOfAttributes);
247  ComputeIndexAttrs(indexInfo,
248  typeIds, collationIds, opclassIds, opclassOptions,
249  coloptions, attributeList,
250  exclusionOpNames, relationId,
251  accessMethodName, accessMethodId,
252  amcanorder, isconstraint, InvalidOid, 0, NULL);
253 
254 
255  /* Get the soon-obsolete pg_index tuple. */
256  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId));
257  if (!HeapTupleIsValid(tuple))
258  elog(ERROR, "cache lookup failed for index %u", oldId);
259  indexForm = (Form_pg_index) GETSTRUCT(tuple);
260 
261  /*
262  * We don't assess expressions or predicates; assume incompatibility.
263  * Also, if the index is invalid for any reason, treat it as incompatible.
264  */
265  if (!(heap_attisnull(tuple, Anum_pg_index_indpred, NULL) &&
266  heap_attisnull(tuple, Anum_pg_index_indexprs, NULL) &&
267  indexForm->indisvalid))
268  {
269  ReleaseSysCache(tuple);
270  return false;
271  }
272 
273  /* Any change in operator class or collation breaks compatibility. */
274  old_natts = indexForm->indnkeyatts;
275  Assert(old_natts == numberOfAttributes);
276 
277  d = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indcollation);
278  old_indcollation = (oidvector *) DatumGetPointer(d);
279 
280  d = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
281  old_indclass = (oidvector *) DatumGetPointer(d);
282 
283  ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
284  memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
285 
286  ReleaseSysCache(tuple);
287 
288  if (!ret)
289  return false;
290 
291  /* For polymorphic opcintype, column type changes break compatibility. */
292  irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
293  for (i = 0; i < old_natts; i++)
294  {
295  if (IsPolymorphicType(get_opclass_input_type(opclassIds[i])) &&
296  TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
297  {
298  ret = false;
299  break;
300  }
301  }
302 
303  /* Any change in opclass options break compatibility. */
304  if (ret)
305  {
306  Datum *oldOpclassOptions = palloc_array(Datum, old_natts);
307 
308  for (i = 0; i < old_natts; i++)
309  oldOpclassOptions[i] = get_attoptions(oldId, i + 1);
310 
311  ret = CompareOpclassOptions(oldOpclassOptions, opclassOptions, old_natts);
312 
313  pfree(oldOpclassOptions);
314  }
315 
316  /* Any change in exclusion operator selections breaks compatibility. */
317  if (ret && indexInfo->ii_ExclusionOps != NULL)
318  {
319  Oid *old_operators,
320  *old_procs;
321  uint16 *old_strats;
322 
323  RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
324  ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
325  old_natts * sizeof(Oid)) == 0;
326 
327  /* Require an exact input type match for polymorphic operators. */
328  if (ret)
329  {
330  for (i = 0; i < old_natts && ret; i++)
331  {
332  Oid left,
333  right;
334 
335  op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
336  if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
337  TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
338  {
339  ret = false;
340  break;
341  }
342  }
343  }
344  }
345 
346  index_close(irel, NoLock);
347  return ret;
348 }
IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition: amapi.c:33
unsigned short uint16
Definition: c.h:505
signed short int16
Definition: c.h:493
#define palloc_array(type, count)
Definition: fe_memutils.h:64
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:455
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3525
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *typeOids, Oid *collationOids, Oid *opclassOids, Datum *opclassOptions, int16 *colOptions, const List *attList, const List *exclusionOpNames, Oid relId, const char *accessMethodName, Oid accessMethodId, bool amcanorder, bool isconstraint, Oid ddl_userid, int ddl_sec_context, int *ddl_save_nestlevel)
Definition: indexcmds.c:1845
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition: indexcmds.c:357
#define AccessShareLock
Definition: lockdefs.h:36
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1212
Datum get_attoptions(Oid relid, int16 attnum)
Definition: lsyscache.c:970
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1358
IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing)
Definition: makefuncs.c:761
void pfree(void *pointer)
Definition: mcxt.c:1521
#define INDEX_MAX_KEYS
FormData_pg_index * Form_pg_index
Definition: pg_index.h:70
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition: relcache.c:5591
bool amsummarizing
Definition: amapi.h:254
bool amcanorder
Definition: amapi.h:224
Oid * ii_ExclusionOps
Definition: execnodes.h:193
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:726
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:733
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510

References AccessShareLock, IndexAmRoutine::amcanorder, IndexAmRoutine::amsummarizing, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer(), elog, ereport, errcode(), errmsg(), ERROR, get_attoptions(), get_opclass_input_type(), GetIndexAmRoutine(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), InvalidOid, list_length(), makeIndexInfo(), NIL, NoLock, ObjectIdGetDatum(), op_input_types(), palloc_array, pfree(), PointerGetDatum(), RelationData::rd_att, RelationGetExclusionInfo(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttrNotNull(), TupleDescAttr, and oidvector::values.

Referenced by TryReuseIndex().

◆ ChooseRelationName()

char* ChooseRelationName ( const char *  name1,
const char *  name2,
const char *  label,
Oid  namespaceid,
bool  isconstraint 
)

Definition at line 2499 of file indexcmds.c.

2502 {
2503  int pass = 0;
2504  char *relname = NULL;
2505  char modlabel[NAMEDATALEN];
2506 
2507  /* try the unmodified label first */
2508  strlcpy(modlabel, label, sizeof(modlabel));
2509 
2510  for (;;)
2511  {
2512  relname = makeObjectName(name1, name2, modlabel);
2513 
2514  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2515  {
2516  if (!isconstraint ||
2517  !ConstraintNameExists(relname, namespaceid))
2518  break;
2519  }
2520 
2521  /* found a conflict, so try a new name component */
2522  pfree(relname);
2523  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2524  }
2525 
2526  return relname;
2527 }
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2413
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
static char * label
NameData relname
Definition: pg_class.h:38
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45

References ConstraintNameExists(), get_relname_relid(), label, makeObjectName(), NAMEDATALEN, OidIsValid, pfree(), relname, snprintf, and strlcpy().

Referenced by ChooseIndexName(), generateSerialExtraStmts(), and ReindexRelationConcurrently().

◆ CreateAccessMethod()

ObjectAddress CreateAccessMethod ( CreateAmStmt stmt)

Definition at line 43 of file amcmds.c.

44 {
45  Relation rel;
46  ObjectAddress myself;
47  ObjectAddress referenced;
48  Oid amoid;
49  Oid amhandler;
50  bool nulls[Natts_pg_am];
51  Datum values[Natts_pg_am];
52  HeapTuple tup;
53 
54  rel = table_open(AccessMethodRelationId, RowExclusiveLock);
55 
56  /* Must be superuser */
57  if (!superuser())
58  ereport(ERROR,
59  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
60  errmsg("permission denied to create access method \"%s\"",
61  stmt->amname),
62  errhint("Must be superuser to create an access method.")));
63 
64  /* Check if name is used */
65  amoid = GetSysCacheOid1(AMNAME, Anum_pg_am_oid,
66  CStringGetDatum(stmt->amname));
67  if (OidIsValid(amoid))
68  {
69  ereport(ERROR,
71  errmsg("access method \"%s\" already exists",
72  stmt->amname)));
73  }
74 
75  /*
76  * Get the handler function oid, verifying the AM type while at it.
77  */
78  amhandler = lookup_am_handler_func(stmt->handler_name, stmt->amtype);
79 
80  /*
81  * Insert tuple into pg_am.
82  */
83  memset(values, 0, sizeof(values));
84  memset(nulls, false, sizeof(nulls));
85 
86  amoid = GetNewOidWithIndex(rel, AmOidIndexId, Anum_pg_am_oid);
87  values[Anum_pg_am_oid - 1] = ObjectIdGetDatum(amoid);
88  values[Anum_pg_am_amname - 1] =
90  values[Anum_pg_am_amhandler - 1] = ObjectIdGetDatum(amhandler);
91  values[Anum_pg_am_amtype - 1] = CharGetDatum(stmt->amtype);
92 
93  tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
94 
95  CatalogTupleInsert(rel, tup);
96  heap_freetuple(tup);
97 
98  myself.classId = AccessMethodRelationId;
99  myself.objectId = amoid;
100  myself.objectSubId = 0;
101 
102  /* Record dependency on handler function */
103  referenced.classId = ProcedureRelationId;
104  referenced.objectId = amhandler;
105  referenced.objectSubId = 0;
106 
107  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
108 
109  recordDependencyOnCurrentExtension(&myself, false);
110 
111  InvokeObjectPostCreateHook(AccessMethodRelationId, amoid, 0);
112 
114 
115  return myself;
116 }
static Oid lookup_am_handler_func(List *handler_name, char amtype)
Definition: amcmds.c:234
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:412
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:194
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:104

References CatalogTupleInsert(), CharGetDatum(), ObjectAddress::classId, CStringGetDatum(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, GetNewOidWithIndex(), GetSysCacheOid1, heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, lookup_am_handler_func(), namein(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), recordDependencyOnCurrentExtension(), RelationGetDescr, RowExclusiveLock, stmt, superuser(), table_close(), table_open(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateCast()

ObjectAddress CreateCast ( CreateCastStmt stmt)

Definition at line 1521 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignDataWrapper()

ObjectAddress CreateForeignDataWrapper ( ParseState pstate,
CreateFdwStmt stmt 
)

Definition at line 558 of file foreigncmds.c.

559 {
560  Relation rel;
561  Datum values[Natts_pg_foreign_data_wrapper];
562  bool nulls[Natts_pg_foreign_data_wrapper];
563  HeapTuple tuple;
564  Oid fdwId;
565  bool handler_given;
566  bool validator_given;
567  Oid fdwhandler;
568  Oid fdwvalidator;
569  Datum fdwoptions;
570  Oid ownerId;
571  ObjectAddress myself;
572  ObjectAddress referenced;
573 
574  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
575 
576  /* Must be superuser */
577  if (!superuser())
578  ereport(ERROR,
579  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
580  errmsg("permission denied to create foreign-data wrapper \"%s\"",
581  stmt->fdwname),
582  errhint("Must be superuser to create a foreign-data wrapper.")));
583 
584  /* For now the owner cannot be specified on create. Use effective user ID. */
585  ownerId = GetUserId();
586 
587  /*
588  * Check that there is no other foreign-data wrapper by this name.
589  */
590  if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
591  ereport(ERROR,
593  errmsg("foreign-data wrapper \"%s\" already exists",
594  stmt->fdwname)));
595 
596  /*
597  * Insert tuple into pg_foreign_data_wrapper.
598  */
599  memset(values, 0, sizeof(values));
600  memset(nulls, false, sizeof(nulls));
601 
602  fdwId = GetNewOidWithIndex(rel, ForeignDataWrapperOidIndexId,
603  Anum_pg_foreign_data_wrapper_oid);
604  values[Anum_pg_foreign_data_wrapper_oid - 1] = ObjectIdGetDatum(fdwId);
605  values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
607  values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
608 
609  /* Lookup handler and validator functions, if given */
610  parse_func_options(pstate, stmt->func_options,
611  &handler_given, &fdwhandler,
612  &validator_given, &fdwvalidator);
613 
614  values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
615  values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
616 
617  nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
618 
619  fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
620  PointerGetDatum(NULL),
621  stmt->options,
622  fdwvalidator);
623 
624  if (PointerIsValid(DatumGetPointer(fdwoptions)))
625  values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
626  else
627  nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
628 
629  tuple = heap_form_tuple(rel->rd_att, values, nulls);
630 
631  CatalogTupleInsert(rel, tuple);
632 
633  heap_freetuple(tuple);
634 
635  /* record dependencies */
636  myself.classId = ForeignDataWrapperRelationId;
637  myself.objectId = fdwId;
638  myself.objectSubId = 0;
639 
640  if (OidIsValid(fdwhandler))
641  {
642  referenced.classId = ProcedureRelationId;
643  referenced.objectId = fdwhandler;
644  referenced.objectSubId = 0;
645  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
646  }
647 
648  if (OidIsValid(fdwvalidator))
649  {
650  referenced.classId = ProcedureRelationId;
651  referenced.objectId = fdwvalidator;
652  referenced.objectSubId = 0;
653  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
654  }
655 
656  recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
657 
658  /* dependency on extension */
659  recordDependencyOnCurrentExtension(&myself, false);
660 
661  /* Post creation hook for new foreign data wrapper */
662  InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
663 
665 
666  return myself;
667 }
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition: foreign.c:96
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168

References CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum(), DatumGetPointer(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, namein(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, parse_func_options(), PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, stmt, superuser(), table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateForeignServer()

ObjectAddress CreateForeignServer ( CreateForeignServerStmt stmt)

Definition at line 838 of file foreigncmds.c.

839 {
840  Relation rel;
841  Datum srvoptions;
842  Datum values[Natts_pg_foreign_server];
843  bool nulls[Natts_pg_foreign_server];
844  HeapTuple tuple;
845  Oid srvId;
846  Oid ownerId;
847  AclResult aclresult;
848  ObjectAddress myself;
849  ObjectAddress referenced;
850  ForeignDataWrapper *fdw;
851 
852  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
853 
854  /* For now the owner cannot be specified on create. Use effective user ID. */
855  ownerId = GetUserId();
856 
857  /*
858  * Check that there is no other foreign server by this name. If there is
859  * one, do nothing if IF NOT EXISTS was specified.
860  */
861  srvId = get_foreign_server_oid(stmt->servername, true);
862  if (OidIsValid(srvId))
863  {
864  if (stmt->if_not_exists)
865  {
866  /*
867  * If we are in an extension script, insist that the pre-existing
868  * object be a member of the extension, to avoid security risks.
869  */
870  ObjectAddressSet(myself, ForeignServerRelationId, srvId);
872 
873  /* OK to skip */
874  ereport(NOTICE,
876  errmsg("server \"%s\" already exists, skipping",
877  stmt->servername)));
879  return InvalidObjectAddress;
880  }
881  else
882  ereport(ERROR,
884  errmsg("server \"%s\" already exists",
885  stmt->servername)));
886  }
887 
888  /*
889  * Check that the FDW exists and that we have USAGE on it. Also get the
890  * actual FDW for option validation etc.
891  */
892  fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
893 
894  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdw->fdwid, ownerId, ACL_USAGE);
895  if (aclresult != ACLCHECK_OK)
896  aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
897 
898  /*
899  * Insert tuple into pg_foreign_server.
900  */
901  memset(values, 0, sizeof(values));
902  memset(nulls, false, sizeof(nulls));
903 
904  srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId,
905  Anum_pg_foreign_server_oid);
906  values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId);
907  values[Anum_pg_foreign_server_srvname - 1] =
909  values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
910  values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
911 
912  /* Add server type if supplied */
913  if (stmt->servertype)
914  values[Anum_pg_foreign_server_srvtype - 1] =
915  CStringGetTextDatum(stmt->servertype);
916  else
917  nulls[Anum_pg_foreign_server_srvtype - 1] = true;
918 
919  /* Add server version if supplied */
920  if (stmt->version)
921  values[Anum_pg_foreign_server_srvversion - 1] =
922  CStringGetTextDatum(stmt->version);
923  else
924  nulls[Anum_pg_foreign_server_srvversion - 1] = true;
925 
926  /* Start with a blank acl */
927  nulls[Anum_pg_foreign_server_srvacl - 1] = true;
928 
929  /* Add server options */
930  srvoptions = transformGenericOptions(ForeignServerRelationId,
931  PointerGetDatum(NULL),
932  stmt->options,
933  fdw->fdwvalidator);
934 
935  if (PointerIsValid(DatumGetPointer(srvoptions)))
936  values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
937  else
938  nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
939 
940  tuple = heap_form_tuple(rel->rd_att, values, nulls);
941 
942  CatalogTupleInsert(rel, tuple);
943 
944  heap_freetuple(tuple);
945 
946  /* record dependencies */
947  myself.classId = ForeignServerRelationId;
948  myself.objectId = srvId;
949  myself.objectSubId = 0;
950 
951  referenced.classId = ForeignDataWrapperRelationId;
952  referenced.objectId = fdw->fdwid;
953  referenced.objectSubId = 0;
954  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
955 
956  recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
957 
958  /* dependency on extension */
959  recordDependencyOnCurrentExtension(&myself, false);
960 
961  /* Post creation hook for new foreign server */
962  InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
963 
965 
966  return myself;
967 }
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:704
@ OBJECT_FDW
Definition: parsenodes.h:2264
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:259
char * fdwname
Definition: foreign.h:28

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), checkMembershipInCurrentExtension(), ObjectAddress::classId, CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, ForeignDataWrapper::fdwvalidator, get_foreign_server_oid(), GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, namein(), NOTICE, object_aclcheck(), OBJECT_FDW, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, stmt, table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateForeignTable()

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1404 of file foreigncmds.c.

1405 {
1406  Relation ftrel;
1407  Datum ftoptions;
1408  Datum values[Natts_pg_foreign_table];
1409  bool nulls[Natts_pg_foreign_table];
1410  HeapTuple tuple;
1411  AclResult aclresult;
1412  ObjectAddress myself;
1413  ObjectAddress referenced;
1414  Oid ownerId;
1415  ForeignDataWrapper *fdw;
1416  ForeignServer *server;
1417 
1418  /*
1419  * Advance command counter to ensure the pg_attribute tuple is visible;
1420  * the tuple might be updated to add constraints in previous step.
1421  */
1423 
1424  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
1425 
1426  /*
1427  * For now the owner cannot be specified on create. Use effective user ID.
1428  */
1429  ownerId = GetUserId();
1430 
1431  /*
1432  * Check that the foreign server exists and that we have USAGE on it. Also
1433  * get the actual FDW for option validation etc.
1434  */
1435  server = GetForeignServerByName(stmt->servername, false);
1436  aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, ownerId, ACL_USAGE);
1437  if (aclresult != ACLCHECK_OK)
1438  aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1439 
1440  fdw = GetForeignDataWrapper(server->fdwid);
1441 
1442  /*
1443  * Insert tuple into pg_foreign_table.
1444  */
1445  memset(values, 0, sizeof(values));
1446  memset(nulls, false, sizeof(nulls));
1447 
1448  values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
1449  values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
1450  /* Add table generic options */
1451  ftoptions = transformGenericOptions(ForeignTableRelationId,
1452  PointerGetDatum(NULL),
1453  stmt->options,
1454  fdw->fdwvalidator);
1455 
1456  if (PointerIsValid(DatumGetPointer(ftoptions)))
1457  values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
1458  else
1459  nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1460 
1461  tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1462 
1463  CatalogTupleInsert(ftrel, tuple);
1464 
1465  heap_freetuple(tuple);
1466 
1467  /* Add pg_class dependency on the server */
1468  myself.classId = RelationRelationId;
1469  myself.objectId = relid;
1470  myself.objectSubId = 0;
1471 
1472  referenced.classId = ForeignServerRelationId;
1473  referenced.objectId = server->serverid;
1474  referenced.objectSubId = 0;
1475  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1476 
1477  table_close(ftrel, RowExclusiveLock);
1478 }
char * servername
Definition: foreign.h:39
void CommandCounterIncrement(void)
Definition: xact.c:1099

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetPointer(), DEPENDENCY_NORMAL, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_form_tuple(), heap_freetuple(), object_aclcheck(), OBJECT_FOREIGN_SERVER, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, stmt, table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateFunction()

ObjectAddress CreateFunction ( ParseState pstate,
CreateFunctionStmt stmt 
)

Definition at line 1011 of file functioncmds.c.

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

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(), funcname, get_base_element_type(), get_namespace_name(), get_transform_oid(), GETSTRUCT, GetUserId(), HeapTupleIsValid, i, interpret_AS_clause(), interpret_function_parameter_list(), InvalidOid, lappend_oid(), lfirst_node, lfirst_oid, list_length(), NameStr, NIL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_PROCEDURE, OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, ParseState::p_sourcetext, palloc(), PointerGetDatum(), ProcedureCreate(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), SearchSysCache1(), stmt, superuser(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ CreateStatistics()

ObjectAddress CreateStatistics ( CreateStatsStmt stmt)

Definition at line 62 of file statscmds.c.

63 {
64  int16 attnums[STATS_MAX_DIMENSIONS];
65  int nattnums = 0;
66  int numcols;
67  char *namestr;
68  NameData stxname;
69  Oid statoid;
70  Oid namespaceId;
71  Oid stxowner = GetUserId();
72  HeapTuple htup;
73  Datum values[Natts_pg_statistic_ext];
74  bool nulls[Natts_pg_statistic_ext];
75  int2vector *stxkeys;
76  List *stxexprs = NIL;
77  Datum exprsDatum;
78  Relation statrel;
79  Relation rel = NULL;
80  Oid relid;
81  ObjectAddress parentobject,
82  myself;
83  Datum types[4]; /* one for each possible type of statistic */
84  int ntypes;
85  ArrayType *stxkind;
86  bool build_ndistinct;
87  bool build_dependencies;
88  bool build_mcv;
89  bool build_expressions;
90  bool requested_type = false;
91  int i;
92  ListCell *cell;
93  ListCell *cell2;
94 
96 
97  /*
98  * Examine the FROM clause. Currently, we only allow it to be a single
99  * simple table, but later we'll probably allow multiple tables and JOIN
100  * syntax. The grammar is already prepared for that, so we have to check
101  * here that what we got is what we can support.
102  */
103  if (list_length(stmt->relations) != 1)
104  ereport(ERROR,
105  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
106  errmsg("only a single relation is allowed in CREATE STATISTICS")));
107 
108  foreach(cell, stmt->relations)
109  {
110  Node *rln = (Node *) lfirst(cell);
111 
112  if (!IsA(rln, RangeVar))
113  ereport(ERROR,
114  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
115  errmsg("only a single relation is allowed in CREATE STATISTICS")));
116 
117  /*
118  * CREATE STATISTICS will influence future execution plans but does
119  * not interfere with currently executing plans. So it should be
120  * enough to take only ShareUpdateExclusiveLock on relation,
121  * conflicting with ANALYZE and other DDL that sets statistical
122  * information, but not with normal queries.
123  */
125 
126  /* Restrict to allowed relation types */
127  if (rel->rd_rel->relkind != RELKIND_RELATION &&
128  rel->rd_rel->relkind != RELKIND_MATVIEW &&
129  rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
130  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
131  ereport(ERROR,
132  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
133  errmsg("cannot define statistics for relation \"%s\"",
135  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
136 
137  /* You must own the relation to create stats on it */
138  if (!object_ownercheck(RelationRelationId, RelationGetRelid(rel), stxowner))
141 
142  /* Creating statistics on system catalogs is not allowed */
144  ereport(ERROR,
145  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
146  errmsg("permission denied: \"%s\" is a system catalog",
147  RelationGetRelationName(rel))));
148  }
149 
150  Assert(rel);
151  relid = RelationGetRelid(rel);
152 
153  /*
154  * If the node has a name, split it up and determine creation namespace.
155  * If not, put the object in the same namespace as the relation, and cons
156  * up a name for it. (This can happen either via "CREATE STATISTICS ..."
157  * or via "CREATE TABLE ... (LIKE)".)
158  */
159  if (stmt->defnames)
160  namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames,
161  &namestr);
162  else
163  {
164  namespaceId = RelationGetNamespace(rel);
167  "stat",
168  namespaceId);
169  }
170  namestrcpy(&stxname, namestr);
171 
172  /*
173  * Deal with the possibility that the statistics object already exists.
174  */
175  if (SearchSysCacheExists2(STATEXTNAMENSP,
176  CStringGetDatum(namestr),
177  ObjectIdGetDatum(namespaceId)))
178  {
179  if (stmt->if_not_exists)
180  {
181  /*
182  * Since stats objects aren't members of extensions (see comments
183  * below), no need for checkMembershipInCurrentExtension here.
184  */
185  ereport(NOTICE,
187  errmsg("statistics object \"%s\" already exists, skipping",
188  namestr)));
189  relation_close(rel, NoLock);
190  return InvalidObjectAddress;
191  }
192 
193  ereport(ERROR,
195  errmsg("statistics object \"%s\" already exists", namestr)));
196  }
197 
198  /*
199  * Make sure no more than STATS_MAX_DIMENSIONS columns are used. There
200  * might be duplicates and so on, but we'll deal with those later.
201  */
202  numcols = list_length(stmt->exprs);
203  if (numcols > STATS_MAX_DIMENSIONS)
204  ereport(ERROR,
205  (errcode(ERRCODE_TOO_MANY_COLUMNS),
206  errmsg("cannot have more than %d columns in statistics",
208 
209  /*
210  * Convert the expression list to a simple array of attnums, but also keep
211  * a list of more complex expressions. While at it, enforce some
212  * constraints - we don't allow extended statistics on system attributes,
213  * and we require the data type to have a less-than operator.
214  *
215  * There are many ways to "mask" a simple attribute reference as an
216  * expression, for example "(a+0)" etc. We can't possibly detect all of
217  * them, but we handle at least the simple case with the attribute in
218  * parens. There'll always be a way around this, if the user is determined
219  * (like the "(a+0)" example), but this makes it somewhat consistent with
220  * how indexes treat attributes/expressions.
221  */
222  foreach(cell, stmt->exprs)
223  {
224  StatsElem *selem = lfirst_node(StatsElem, cell);
225 
226  if (selem->name) /* column reference */
227  {
228  char *attname;
229  HeapTuple atttuple;
230  Form_pg_attribute attForm;
232 
233  attname = selem->name;
234 
235  atttuple = SearchSysCacheAttName(relid, attname);
236  if (!HeapTupleIsValid(atttuple))
237  ereport(ERROR,
238  (errcode(ERRCODE_UNDEFINED_COLUMN),
239  errmsg("column \"%s\" does not exist",
240  attname)));
241  attForm = (Form_pg_attribute) GETSTRUCT(atttuple);
242 
243  /* Disallow use of system attributes in extended stats */
244  if (attForm->attnum <= 0)
245  ereport(ERROR,
246  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
247  errmsg("statistics creation on system columns is not supported")));
248 
249  /* Disallow data types without a less-than operator */
250  type = lookup_type_cache(attForm->atttypid, TYPECACHE_LT_OPR);
251  if (type->lt_opr == InvalidOid)
252  ereport(ERROR,
253  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
254  errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
255  attname, format_type_be(attForm->atttypid))));
256 
257  attnums[nattnums] = attForm->attnum;
258  nattnums++;
259  ReleaseSysCache(atttuple);
260  }
261  else if (IsA(selem->expr, Var)) /* column reference in parens */
262  {
263  Var *var = (Var *) selem->expr;
265 
266  /* Disallow use of system attributes in extended stats */
267  if (var->varattno <= 0)
268  ereport(ERROR,
269  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
270  errmsg("statistics creation on system columns is not supported")));
271 
272  /* Disallow data types without a less-than operator */
273  type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
274  if (type->lt_opr == InvalidOid)
275  ereport(ERROR,
276  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
277  errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
278  get_attname(relid, var->varattno, false), format_type_be(var->vartype))));
279 
280  attnums[nattnums] = var->varattno;
281  nattnums++;
282  }
283  else /* expression */
284  {
285  Node *expr = selem->expr;
286  Oid atttype;
288  Bitmapset *attnums = NULL;
289  int k;
290 
291  Assert(expr != NULL);
292 
293  /* Disallow expressions referencing system attributes. */
294  pull_varattnos(expr, 1, &attnums);
295 
296  k = -1;
297  while ((k = bms_next_member(attnums, k)) >= 0)
298  {
300 
301  if (attnum <= 0)
302  ereport(ERROR,
303  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
304  errmsg("statistics creation on system columns is not supported")));
305  }
306 
307  /*
308  * Disallow data types without a less-than operator.
309  *
310  * We ignore this for statistics on a single expression, in which
311  * case we'll build the regular statistics only (and that code can
312  * deal with such data types).
313  */
314  if (list_length(stmt->exprs) > 1)
315  {
316  atttype = exprType(expr);
318  if (type->lt_opr == InvalidOid)
319  ereport(ERROR,
320  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
321  errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
322  format_type_be(atttype))));
323  }
324 
325  stxexprs = lappend(stxexprs, expr);
326  }
327  }
328 
329  /*
330  * Parse the statistics kinds.
331  *
332  * First check that if this is the case with a single expression, there
333  * are no statistics kinds specified (we don't allow that for the simple
334  * CREATE STATISTICS form).
335  */
336  if ((list_length(stmt->exprs) == 1) && (list_length(stxexprs) == 1))
337  {
338  /* statistics kinds not specified */
339  if (stmt->stat_types != NIL)
340  ereport(ERROR,
341  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
342  errmsg("when building statistics on a single expression, statistics kinds may not be specified")));
343  }
344 
345  /* OK, let's check that we recognize the statistics kinds. */
346  build_ndistinct = false;
347  build_dependencies = false;
348  build_mcv = false;
349  foreach(cell, stmt->stat_types)
350  {
351  char *type = strVal(lfirst(cell));
352 
353  if (strcmp(type, "ndistinct") == 0)
354  {
355  build_ndistinct = true;
356  requested_type = true;
357  }
358  else if (strcmp(type, "dependencies") == 0)
359  {
360  build_dependencies = true;
361  requested_type = true;
362  }
363  else if (strcmp(type, "mcv") == 0)
364  {
365  build_mcv = true;
366  requested_type = true;
367  }
368  else
369  ereport(ERROR,
370  (errcode(ERRCODE_SYNTAX_ERROR),
371  errmsg("unrecognized statistics kind \"%s\"",
372  type)));
373  }
374 
375  /*
376  * If no statistic type was specified, build them all (but only when the
377  * statistics is defined on more than one column/expression).
378  */
379  if ((!requested_type) && (numcols >= 2))
380  {
381  build_ndistinct = true;
382  build_dependencies = true;
383  build_mcv = true;
384  }
385 
386  /*
387  * When there are non-trivial expressions, build the expression stats
388  * automatically. This allows calculating good estimates for stats that
389  * consider per-clause estimates (e.g. functional dependencies).
390  */
391  build_expressions = (stxexprs != NIL);
392 
393  /*
394  * Check that at least two columns were specified in the statement, or
395  * that we're building statistics on a single expression.
396  */
397  if ((numcols < 2) && (list_length(stxexprs) != 1))
398  ereport(ERROR,
399  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
400  errmsg("extended statistics require at least 2 columns")));
401 
402  /*
403  * Sort the attnums, which makes detecting duplicates somewhat easier, and
404  * it does not hurt (it does not matter for the contents, unlike for
405  * indexes, for example).
406  */
407  qsort(attnums, nattnums, sizeof(int16), compare_int16);
408 
409  /*
410  * Check for duplicates in the list of columns. The attnums are sorted so
411  * just check consecutive elements.
412  */
413  for (i = 1; i < nattnums; i++)
414  {
415  if (attnums[i] == attnums[i - 1])
416  ereport(ERROR,
417  (errcode(ERRCODE_DUPLICATE_COLUMN),
418  errmsg("duplicate column name in statistics definition")));
419  }
420 
421  /*
422  * Check for duplicate expressions. We do two loops, counting the
423  * occurrences of each expression. This is O(N^2) but we only allow small
424  * number of expressions and it's not executed often.
425  *
426  * XXX We don't cross-check attributes and expressions, because it does
427  * not seem worth it. In principle we could check that expressions don't
428  * contain trivial attribute references like "(a)", but the reasoning is
429  * similar to why we don't bother with extracting columns from
430  * expressions. It's either expensive or very easy to defeat for
431  * determined user, and there's no risk if we allow such statistics (the
432  * statistics is useless, but harmless).
433  */
434  foreach(cell, stxexprs)
435  {
436  Node *expr1 = (Node *) lfirst(cell);
437  int cnt = 0;
438 
439  foreach(cell2, stxexprs)
440  {
441  Node *expr2 = (Node *) lfirst(cell2);
442 
443  if (equal(expr1, expr2))
444  cnt += 1;
445  }
446 
447  /* every expression should find at least itself */
448  Assert(cnt >= 1);
449 
450  if (cnt > 1)
451  ereport(ERROR,
452  (errcode(ERRCODE_DUPLICATE_COLUMN),
453  errmsg("duplicate expression in statistics definition")));
454  }
455 
456  /* Form an int2vector representation of the sorted column list */
457  stxkeys = buildint2vector(attnums, nattnums);
458 
459  /* construct the char array of enabled statistic types */
460  ntypes = 0;
461  if (build_ndistinct)
462  types[ntypes++] = CharGetDatum(STATS_EXT_NDISTINCT);
463  if (build_dependencies)
464  types[ntypes++] = CharGetDatum(STATS_EXT_DEPENDENCIES);
465  if (build_mcv)
466  types[ntypes++] = CharGetDatum(STATS_EXT_MCV);
467  if (build_expressions)
468  types[ntypes++] = CharGetDatum(STATS_EXT_EXPRESSIONS);
469  Assert(ntypes > 0 && ntypes <= lengthof(types));
470  stxkind = construct_array_builtin(types, ntypes, CHAROID);
471 
472  /* convert the expressions (if any) to a text datum */
473  if (stxexprs != NIL)
474  {
475  char *exprsString;
476 
477  exprsString = nodeToString(stxexprs);
478  exprsDatum = CStringGetTextDatum(exprsString);
479  pfree(exprsString);
480  }
481  else
482  exprsDatum = (Datum) 0;
483 
484  statrel = table_open(StatisticExtRelationId, RowExclusiveLock);
485 
486  /*
487  * Everything seems fine, so let's build the pg_statistic_ext tuple.
488  */
489  memset(values, 0, sizeof(values));
490  memset(nulls, false, sizeof(nulls));
491 
492  statoid = GetNewOidWithIndex(statrel, StatisticExtOidIndexId,
493  Anum_pg_statistic_ext_oid);
494  values[Anum_pg_statistic_ext_oid - 1] = ObjectIdGetDatum(statoid);
495  values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
496  values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
497  values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
498  values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
499  values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
500  nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
501  values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
502 
503  values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum;
504  if (exprsDatum == (Datum) 0)
505  nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
506 
507  /* insert it into pg_statistic_ext */
508  htup = heap_form_tuple(statrel->rd_att, values, nulls);
509  CatalogTupleInsert(statrel, htup);
510  heap_freetuple(htup);
511 
513 
514  /*
515  * We used to create the pg_statistic_ext_data tuple too, but it's not
516  * clear what value should the stxdinherit flag have (it depends on
517  * whether the rel is partitioned, contains data, etc.)
518  */
519 
520  InvokeObjectPostCreateHook(StatisticExtRelationId, statoid, 0);
521 
522  /*
523  * Invalidate relcache so that others see the new statistics object.
524  */
526 
527  relation_close(rel, NoLock);
528 
529  /*
530  * Add an AUTO dependency on each column used in the stats, so that the
531  * stats object goes away if any or all of them get dropped.
532  */
533  ObjectAddressSet(myself, StatisticExtRelationId, statoid);
534 
535  /* add dependencies for plain column references */
536  for (i = 0; i < nattnums; i++)
537  {
538  ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
539  recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
540  }
541 
542  /*
543  * If there are no dependencies on a column, give the statistics object an
544  * auto dependency on the whole table. In most cases, this will be
545  * redundant, but it might not be if the statistics expressions contain no
546  * Vars (which might seem strange but possible). This is consistent with
547  * what we do for indexes in index_create.
548  *
549  * XXX We intentionally don't consider the expressions before adding this
550  * dependency, because recordDependencyOnSingleRelExpr may not create any
551  * dependencies for whole-row Vars.
552  */
553  if (!nattnums)
554  {
555  ObjectAddressSet(parentobject, RelationRelationId, relid);
556  recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
557  }
558 
559  /*
560  * Store dependencies on anything mentioned in statistics expressions,
561  * just like we do for index expressions.
562  */
563  if (stxexprs)
565  (Node *) stxexprs,
566  relid,
568  DEPENDENCY_AUTO, false);
569 
570  /*
571  * Also add dependencies on namespace and owner. These are required
572  * because the stats object might have a different namespace and/or owner
573  * than the underlying table(s).
574  */
575  ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
576  recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
577 
578  recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
579 
580  /*
581  * XXX probably there should be a recordDependencyOnCurrentExtension call
582  * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
583  * STATISTICS, which is more work than it seems worth.
584  */
585 
586  /* Add any requested comment */
587  if (stmt->stxcomment != NULL)
588  CreateComments(statoid, StatisticExtRelationId, 0,
589  stmt->stxcomment);
590 
591  /* Return stats object's address */
592  return myself;
593 }
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define lengthof(array)
Definition: c.h:788
bool IsSystemRelation(Relation relation)
Definition: catalog.c:73
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
struct typedefs * types
Definition: ecpg.c:29
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
bool allowSystemTableMods
Definition: globals.c:129
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1360
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
char * nodeToString(const void *obj)
Definition: outfuncs.c:791
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define qsort(a, b, c, d)
Definition: port.h:447
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:137
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:851
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:809
static int compare_int16(const void *a, const void *b)
Definition: statscmds.c:49
Form_pg_class rd_rel
Definition: rel.h:111
char * name
Definition: parsenodes.h:3396
Node * expr
Definition: parsenodes.h:3397
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
Definition: c.h:715
Definition: c.h:741
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:359
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:97
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:356
#define TYPECACHE_LT_OPR
Definition: typcache.h:138
#define strVal(v)
Definition: value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:291
const char * type

References aclcheck_error(), ACLCHECK_NOT_OWNER, allowSystemTableMods, Assert, attname, attnum, bms_next_member(), buildint2vector(), CacheInvalidateRelcache(), CatalogTupleInsert(), CharGetDatum(), ChooseExtendedStatisticName(), ChooseExtendedStatisticNameAddition(), compare_int16(), construct_array_builtin(), CreateComments(), CStringGetDatum(), CStringGetTextDatum, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, equal(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail_relkind_not_supported(), errmsg(), ERROR, StatsElem::expr, exprType(), FirstLowInvalidHeapAttributeNumber, format_type_be(), get_attname(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, if(), InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHook, IsA, IsSystemRelation(), lappend(), lengthof, lfirst, lfirst_node, list_length(), lookup_type_cache(), StatsElem::name, NameGetDatum(), namestrcpy(), NIL, nodeToString(), NoLock, NOTICE, object_ownercheck(), ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), pfree(), PointerGetDatum(), pull_varattnos(), qsort, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnOwner(), recordDependencyOnSingleRelExpr(), relation_close(), relation_openrv(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RowExclusiveLock, SearchSysCacheAttName(), SearchSysCacheExists2, ShareUpdateExclusiveLock, STATS_MAX_DIMENSIONS, stmt, strVal, table_open(), type, TYPECACHE_LT_OPR, types, values, and Var::varattno.

Referenced by ATExecAddStatistics(), and ProcessUtilitySlow().

◆ CreateTransform()

ObjectAddress CreateTransform ( CreateTransformStmt stmt)

Definition at line 1814 of file functioncmds.c.

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

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(), get_language_oid(), get_typtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostCreateHook, LookupFuncWithArgs(), NameListToString(), new_object_addresses(), object_aclcheck(), OBJECT_FUNCTION, OBJECT_LANGUAGE, object_ownercheck(), ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, record_object_address_dependencies(), recordDependencyOnCurrentExtension(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCache2(), stmt, HeapTupleData::t_self, table_close(), table_open(), TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateUserMapping()

ObjectAddress CreateUserMapping ( CreateUserMappingStmt stmt)

Definition at line 1100 of file foreigncmds.c.

1101 {
1102  Relation rel;
1103  Datum useoptions;
1104  Datum values[Natts_pg_user_mapping];
1105  bool nulls[Natts_pg_user_mapping];
1106  HeapTuple tuple;
1107  Oid useId;
1108  Oid umId;
1109  ObjectAddress myself;
1110  ObjectAddress referenced;
1111  ForeignServer *srv;
1112  ForeignDataWrapper *fdw;
1113  RoleSpec *role = (RoleSpec *) stmt->user;
1114 
1115  rel = table_open(UserMappingRelationId, RowExclusiveLock);
1116 
1117  if (role->roletype == ROLESPEC_PUBLIC)
1118  useId = ACL_ID_PUBLIC;
1119  else
1120  useId = get_rolespec_oid(stmt->user, false);
1121 
1122  /* Check that the server exists. */
1123  srv = GetForeignServerByName(stmt->servername, false);
1124 
1125  user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1126 
1127  /*
1128  * Check that the user mapping is unique within server.
1129  */
1130  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1131  ObjectIdGetDatum(useId),
1132  ObjectIdGetDatum(srv->serverid));
1133 
1134  if (OidIsValid(umId))
1135  {
1136  if (stmt->if_not_exists)
1137  {
1138  /*
1139  * Since user mappings aren't members of extensions (see comments
1140  * below), no need for checkMembershipInCurrentExtension here.
1141  */
1142  ereport(NOTICE,
1144  errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
1145  MappingUserName(useId),
1146  stmt->servername)));
1147 
1149  return InvalidObjectAddress;
1150  }
1151  else
1152  ereport(ERROR,
1154  errmsg("user mapping for \"%s\" already exists for server \"%s\"",
1155  MappingUserName(useId),
1156  stmt->servername)));
1157  }
1158 
1159  fdw = GetForeignDataWrapper(srv->fdwid);
1160 
1161  /*
1162  * Insert tuple into pg_user_mapping.
1163  */
1164  memset(values, 0, sizeof(values));
1165  memset(nulls, false, sizeof(nulls));
1166 
1167  umId = GetNewOidWithIndex(rel, UserMappingOidIndexId,
1168  Anum_pg_user_mapping_oid);
1169  values[Anum_pg_user_mapping_oid - 1] = ObjectIdGetDatum(umId);
1170  values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
1171  values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
1172 
1173  /* Add user options */
1174  useoptions = transformGenericOptions(UserMappingRelationId,
1175  PointerGetDatum(NULL),
1176  stmt->options,
1177  fdw->fdwvalidator);
1178 
1179  if (PointerIsValid(DatumGetPointer(useoptions)))
1180  values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
1181  else
1182  nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1183 
1184  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1185 
1186  CatalogTupleInsert(rel, tuple);
1187 
1188  heap_freetuple(tuple);
1189 
1190  /* Add dependency on the server */
1191  myself.classId = UserMappingRelationId;
1192  myself.objectId = umId;
1193  myself.objectSubId = 0;
1194 
1195  referenced.classId = ForeignServerRelationId;
1196  referenced.objectId = srv->serverid;
1197  referenced.objectSubId = 0;
1198  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1199 
1200  if (OidIsValid(useId))
1201  {
1202  /* Record the mapped user dependency */
1203  recordDependencyOnOwner(UserMappingRelationId, umId, useId);
1204  }
1205 
1206  /*
1207  * Perhaps someday there should be a recordDependencyOnCurrentExtension
1208  * call here; but since roles aren't members of extensions, it seems like
1209  * user mappings shouldn't be either. Note that the grammar and pg_dump
1210  * would need to be extended too if we change this.
1211  */
1212 
1213  /* Post creation hook for new user mapping */
1214  InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
1215 
1217 
1218  return myself;
1219 }

References ACL_ID_PUBLIC, CatalogTupleInsert(), ObjectAddress::classId, DatumGetPointer(), DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, get_rolespec_oid(), GetForeignDataWrapper(), GetForeignServerByName(), GetNewOidWithIndex(), GetSysCacheOid2, heap_form_tuple(), heap_freetuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, MappingUserName, NOTICE, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, ForeignServer::serverid, stmt, table_close(), table_open(), transformGenericOptions(), user_mapping_ddl_aclcheck(), and values.

Referenced by ProcessUtilitySlow().

◆ defGetBoolean()

bool defGetBoolean ( DefElem def)

Definition at line 107 of file define.c.

108 {
109  /*
110  * If no parameter value given, assume "true" is meant.
111  */
112  if (def->arg == NULL)
113  return true;
114 
115  /*
116  * Allow 0, 1, "true", "false", "on", "off"
117  */
118  switch (nodeTag(def->arg))
119  {
120  case T_Integer:
121  switch (intVal(def->arg))
122  {
123  case 0:
124  return false;
125  case 1:
126  return true;
127  default:
128  /* otherwise, error out below */
129  break;
130  }
131  break;
132  default:
133  {
134  char *sval = defGetString(def);
135 
136  /*
137  * The set of strings accepted here should match up with the
138  * grammar's opt_boolean_or_string production.
139  */
140  if (pg_strcasecmp(sval, "true") == 0)
141  return true;
142  if (pg_strcasecmp(sval, "false") == 0)
143  return false;
144  if (pg_strcasecmp(sval, "on") == 0)
145  return true;
146  if (pg_strcasecmp(sval, "off") == 0)
147  return false;
148  }
149  break;
150  }
151  ereport(ERROR,
152  (errcode(ERRCODE_SYNTAX_ERROR),
153  errmsg("%s requires a Boolean value",
154  def->defname)));
155  return false; /* keep compiler quiet */
156 }
char * defGetString(DefElem *def)
Definition: define.c:48
#define nodeTag(nodeptr)
Definition: nodes.h:133
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

References DefElem::arg, defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, and pg_strcasecmp().

Referenced by AlterDatabase(), AlterOperator(), AlterReplicationSlot(), apply_server_options(), apply_table_options(), cluster(), createdb(), CreateExtension(), DefineAggregate(), DefineCollation(), DefineOperator(), DefineType(), dintdict_init(), dsimple_init(), dsynonym_init(), dxsyn_init(), ExecReindex(), ExecVacuum(), ExplainQuery(), file_fdw_validator(), get_file_fdw_attribute_options(), get_vacoptval_from_boolean(), GetCommandLogLevel(), make_new_connection(), parse_basebackup_options(), parse_output_parameters(), parse_publication_options(), parse_subscription_options(), parseCreateReplSlotOptions(), postgres_fdw_validator(), postgresExecForeignTruncate(), postgresImportForeignSchema(), postgresIsForeignRelUpdatable(), ProcessCopyOptions(), transformExplainStmt(), transformRelOptions(), and UserMappingPasswordRequired().

◆ defGetInt32()

int32 defGetInt32 ( DefElem def)

Definition at line 162 of file define.c.

163 {
164  if (def->arg == NULL)
165  ereport(ERROR,
166  (errcode(ERRCODE_SYNTAX_ERROR),
167  errmsg("%s requires an integer value",
168  def->defname)));
169  switch (nodeTag(def->arg))
170  {
171  case T_Integer:
172  return (int32) intVal(def->arg);
173  default:
174  ereport(ERROR,
175  (errcode(ERRCODE_SYNTAX_ERROR),
176  errmsg("%s requires an integer value",
177  def->defname)));
178  }
179  return 0; /* keep compiler quiet */
180 }
signed int int32
Definition: c.h:494

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, intVal, and nodeTag.

Referenced by AlterDatabase(), ATExecSetIdentity(), createdb(), DefineAggregate(), and ExecVacuum().

◆ defGetInt64()

int64 defGetInt64 ( DefElem def)

Definition at line 186 of file define.c.

187 {
188  if (def->arg == NULL)
189  ereport(ERROR,
190  (errcode(ERRCODE_SYNTAX_ERROR),
191  errmsg("%s requires a numeric value",
192  def->defname)));
193  switch (nodeTag(def->arg))
194  {
195  case T_Integer:
196  return (int64) intVal(def->arg);
197  case T_Float:
198 
199  /*
200  * Values too large for int4 will be represented as Float
201  * constants by the lexer. Accept these if they are valid int8
202  * strings.
203  */
205  CStringGetDatum(castNode(Float, def->arg)->fval)));
206  default:
207  ereport(ERROR,
208  (errcode(ERRCODE_SYNTAX_ERROR),
209  errmsg("%s requires a numeric value",
210  def->defname)));
211  }
212  return 0; /* keep compiler quiet */
213 }
Datum int8in(PG_FUNCTION_ARGS)
Definition: int8.c:50
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:385
Definition: value.h:48

References DefElem::arg, castNode, CStringGetDatum(), DatumGetInt64(), DefElem::defname, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, int8in(), intVal, and nodeTag.

Referenced by init_params(), and parse_basebackup_options().

◆ defGetNumeric()

double defGetNumeric ( DefElem def)

Definition at line 81 of file define.c.

82 {
83  if (def->arg == NULL)
84  ereport(ERROR,
85  (errcode(ERRCODE_SYNTAX_ERROR),
86  errmsg("%s requires a numeric value",
87  def->defname)));
88  switch (nodeTag(def->arg))
89  {
90  case T_Integer:
91  return (double) intVal(def->arg);
92  case T_Float:
93  return floatVal(def->arg);
94  default:
95  ereport(ERROR,
96  (errcode(ERRCODE_SYNTAX_ERROR),
97  errmsg("%s requires a numeric value",
98  def->defname)));
99  }
100  return 0; /* keep compiler quiet */
101 }
#define floatVal(v)
Definition: value.h:80

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, floatVal, intVal, and nodeTag.

Referenced by AlterFunction(), and compute_function_attributes().

◆ defGetObjectId()

Oid defGetObjectId ( DefElem def)

Definition at line 219 of file define.c.

220 {
221  if (def->arg == NULL)
222  ereport(ERROR,
223  (errcode(ERRCODE_SYNTAX_ERROR),
224  errmsg("%s requires a numeric value",
225  def->defname)));
226  switch (nodeTag(def->arg))
227  {
228  case T_Integer:
229  return (Oid) intVal(def->arg);
230  case T_Float:
231 
232  /*
233  * Values too large for int4 will be represented as Float
234  * constants by the lexer. Accept these if they are valid OID
235  * strings.
236  */
238  CStringGetDatum(castNode(Float, def->arg)->fval)));
239  default:
240  ereport(ERROR,
241  (errcode(ERRCODE_SYNTAX_ERROR),
242  errmsg("%s requires a numeric value",
243  def->defname)));
244  }
245  return 0; /* keep compiler quiet */
246 }
Datum oidin(PG_FUNCTION_ARGS)
Definition: oid.c:37
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242

References DefElem::arg, castNode, CStringGetDatum(), DatumGetObjectId(), DefElem::defname, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, and oidin().

Referenced by createdb().

◆ defGetQualifiedName()

List* defGetQualifiedName ( DefElem def)

Definition at line 252 of file define.c.

253 {
254  if (def->arg == NULL)
255  ereport(ERROR,
256  (errcode(ERRCODE_SYNTAX_ERROR),
257  errmsg("%s requires a parameter",
258  def->defname)));
259  switch (nodeTag(def->arg))
260  {
261  case T_TypeName:
262  return ((TypeName *) def->arg)->names;
263  case T_List:
264  return (List *) def->arg;
265  case T_String:
266  /* Allow quoted name for backwards compatibility */
267  return list_make1(def->arg);
268  default:
269  ereport(ERROR,
270  (errcode(ERRCODE_SYNTAX_ERROR),
271  errmsg("argument of %s must be a name",
272  def->defname)));
273  }
274  return NIL; /* keep compiler quiet */
275 }
#define list_make1(x1)
Definition: pg_list.h:212

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, NIL, and nodeTag.

Referenced by AlterOperator(), AlterType(), DefineAggregate(), DefineCollation(), DefineOperator(), DefineRange(), DefineTSConfiguration(), DefineTSDictionary(), DefineType(), get_ts_parser_func(), get_ts_template_func(), init_params(), and interpret_func_support().

◆ defGetString()

char* defGetString ( DefElem def)

Definition at line 48 of file define.c.

49 {
50  if (def->arg == NULL)
51  ereport(ERROR,
52  (errcode(ERRCODE_SYNTAX_ERROR),
53  errmsg("%s requires a parameter",
54  def->defname)));
55  switch (nodeTag(def->arg))
56  {
57  case T_Integer:
58  return psprintf("%ld", (long) intVal(def->arg));
59  case T_Float:
60  return castNode(Float, def->arg)->fval;
61  case T_Boolean:
62  return boolVal(def->arg) ? "true" : "false";
63  case T_String:
64  return strVal(def->arg);
65  case T_TypeName:
66  return TypeNameToString((TypeName *) def->arg);
67  case T_List:
68  return NameListToString((List *) def->arg);
69  case T_A_Star:
70  return pstrdup("*");
71  default:
72  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
73  }
74  return NULL; /* keep compiler quiet */
75 }
char * pstrdup(const char *in)
Definition: mcxt.c:1696
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

References DefElem::arg, boolVal, castNode, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, NameListToString(), nodeTag, psprintf(), pstrdup(), strVal, and TypeNameToString().

Referenced by AlterDatabase(), AlterType(), apply_server_options(), apply_table_options(), check_selective_binary_conversion(), createdb(), CreateExtension(), defGetBoolean(), defGetCopyHeaderChoice(), defGetCopyLogVerbosityChoice(), defGetCopyOnErrorChoice(), defGetStreamingMode(), defGetTypeLength(), DefineAggregate(), DefineCollation(), DefineType(), deparseAnalyzeSql(), deparseColumnRef(), deparseRelation(), dintdict_init(), dispell_init(), dsimple_init(), dsnowball_init(), dsynonym_init(), dxsyn_init(), ExecReindex(), ExecVacuum(), ExplainQuery(), ExplainResultDesc(), ExtractConnectionOptions(), extractModify(), file_fdw_validator(), fileGetOptions(), get_batch_size_option(), GrantRole(), optionListToArray(), parse_basebackup_options(), parse_output_parameters(), parse_publication_options(), parse_subscription_options(), parseCreateReplSlotOptions(), postgres_fdw_validator(), postgresAcquireSampleRowsFunc(), ProcessCopyOptions(), prsd_headline(), serialize_deflist(), thesaurus_init(), transformRelOptions(), and unaccent_init().

◆ defGetStringList()

List* defGetStringList ( DefElem def)

Definition at line 356 of file define.c.

357 {
358  ListCell *cell;
359 
360  if (def->arg == NULL)
361  ereport(ERROR,
362  (errcode(ERRCODE_SYNTAX_ERROR),
363  errmsg("%s requires a parameter",
364  def->defname)));
365  if (nodeTag(def->arg) != T_List)
366  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
367 
368  foreach(cell, (List *) def->arg)
369  {
370  Node *str = (Node *) lfirst(cell);
371 
372  if (!IsA(str, String))
373  elog(ERROR, "unexpected node type in name list: %d",
374  (int) nodeTag(str));
375  }
376 
377  return (List *) def->arg;
378 }
const char * str
Definition: value.h:64

References DefElem::arg, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, IsA, lfirst, nodeTag, and str.

◆ defGetTypeLength()

int defGetTypeLength ( DefElem def)

Definition at line 312 of file define.c.

313 {
314  if (def->arg == NULL)
315  ereport(ERROR,
316  (errcode(ERRCODE_SYNTAX_ERROR),
317  errmsg("%s requires a parameter",
318  def->defname)));
319  switch (nodeTag(def->arg))
320  {
321  case T_Integer:
322  return intVal(def->arg);
323  case T_Float:
324  ereport(ERROR,
325  (errcode(ERRCODE_SYNTAX_ERROR),
326  errmsg("%s requires an integer value",
327  def->defname)));
328  break;
329  case T_String:
330  if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
331  return -1; /* variable length */
332  break;
333  case T_TypeName:
334  /* cope if grammar chooses to believe "variable" is a typename */
336  "variable") == 0)
337  return -1; /* variable length */
338  break;
339  case T_List:
340  /* must be an operator name */
341  break;
342  default:
343  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
344  }
345  ereport(ERROR,
346  (errcode(ERRCODE_SYNTAX_ERROR),
347  errmsg("invalid argument for %s: \"%s\"",
348  def->defname, defGetString(def))));
349  return 0; /* keep compiler quiet */
350 }

References DefElem::arg, defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, pg_strcasecmp(), strVal, and TypeNameToString().

Referenced by DefineType().

◆ defGetTypeName()

TypeName* defGetTypeName ( DefElem def)

Definition at line 284 of file define.c.

285 {
286  if (def->arg == NULL)
287  ereport(ERROR,
288  (errcode(ERRCODE_SYNTAX_ERROR),
289  errmsg("%s requires a parameter",
290  def->defname)));
291  switch (nodeTag(def->arg))
292  {
293  case T_TypeName:
294  return (TypeName *) def->arg;
295  case T_String:
296  /* Allow quoted typename for backwards compatibility */
298  default:
299  ereport(ERROR,
300  (errcode(ERRCODE_SYNTAX_ERROR),
301  errmsg("argument of %s must be a type name",
302  def->defname)));
303  }
304  return NULL; /* keep compiler quiet */
305 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, makeTypeNameFromNameList(), and nodeTag.

Referenced by DefineAggregate(), DefineOperator(), DefineRange(), DefineType(), and init_params().

◆ DefineAggregate()

ObjectAddress DefineAggregate ( ParseState pstate,
List name,
List args,
bool  oldstyle,
List parameters,
bool  replace 
)

Definition at line 53 of file aggregatecmds.c.

59 {
60  char *aggName;
61  Oid aggNamespace;
62  AclResult aclresult;
63  char aggKind = AGGKIND_NORMAL;
64  List *transfuncName = NIL;
65  List *finalfuncName = NIL;
66  List *combinefuncName = NIL;
67  List *serialfuncName = NIL;
68  List *deserialfuncName = NIL;
69  List *mtransfuncName = NIL;
70  List *minvtransfuncName = NIL;
71  List *mfinalfuncName = NIL;
72  bool finalfuncExtraArgs = false;
73  bool mfinalfuncExtraArgs = false;
74  char finalfuncModify = 0;
75  char mfinalfuncModify = 0;
76  List *sortoperatorName = NIL;
77  TypeName *baseType = NULL;
78  TypeName *transType = NULL;
79  TypeName *mtransType = NULL;
80  int32 transSpace = 0;
81  int32 mtransSpace = 0;
82  char *initval = NULL;
83  char *minitval = NULL;
84  char *parallel = NULL;
85  int numArgs;
86  int numDirectArgs = 0;
87  oidvector *parameterTypes;
88  ArrayType *allParameterTypes;
89  ArrayType *parameterModes;
90  ArrayType *parameterNames;
91  List *parameterDefaults;
92  Oid variadicArgType;
93  Oid transTypeId;
94  Oid mtransTypeId = InvalidOid;
95  char transTypeType;
96  char mtransTypeType = 0;
97  char proparallel = PROPARALLEL_UNSAFE;
98  ListCell *pl;
99 
100  /* Convert list of names to a name and namespace */
101  aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
102 
103  /* Check we have creation rights in target namespace */
104  aclresult = object_aclcheck(NamespaceRelationId, aggNamespace, GetUserId(), ACL_CREATE);
105  if (aclresult != ACLCHECK_OK)
106  aclcheck_error(aclresult, OBJECT_SCHEMA,
107  get_namespace_name(aggNamespace));
108 
109  /* Deconstruct the output of the aggr_args grammar production */
110  if (!oldstyle)
111  {
112  Assert(list_length(args) == 2);
113  numDirectArgs = intVal(lsecond(args));
114  if (numDirectArgs >= 0)
115  aggKind = AGGKIND_ORDERED_SET;
116  else
117  numDirectArgs = 0;
119  }
120 
121  /* Examine aggregate's definition clauses */
122  foreach(pl, parameters)
123  {
124  DefElem *defel = lfirst_node(DefElem, pl);
125 
126  /*
127  * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
128  * for sfunc, stype, initcond.
129  */
130  if (strcmp(defel->defname, "sfunc") == 0)
131  transfuncName = defGetQualifiedName(defel);
132  else if (strcmp(defel->defname, "sfunc1") == 0)
133  transfuncName = defGetQualifiedName(defel);
134  else if (strcmp(defel->defname, "finalfunc") == 0)
135  finalfuncName = defGetQualifiedName(defel);
136  else if (strcmp(defel->defname, "combinefunc") == 0)
137  combinefuncName = defGetQualifiedName(defel);
138  else if (strcmp(defel->defname, "serialfunc") == 0)
139  serialfuncName = defGetQualifiedName(defel);
140  else if (strcmp(defel->defname, "deserialfunc") == 0)
141  deserialfuncName = defGetQualifiedName(defel);
142  else if (strcmp(defel->defname, "msfunc") == 0)
143  mtransfuncName = defGetQualifiedName(defel);
144  else if (strcmp(defel->defname, "minvfunc") == 0)
145  minvtransfuncName = defGetQualifiedName(defel);
146  else if (strcmp(defel->defname, "mfinalfunc") == 0)
147  mfinalfuncName = defGetQualifiedName(defel);
148  else if (strcmp(defel->defname, "finalfunc_extra") == 0)
149  finalfuncExtraArgs = defGetBoolean(defel);
150  else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
151  mfinalfuncExtraArgs = defGetBoolean(defel);
152  else if (strcmp(defel->defname, "finalfunc_modify") == 0)
153  finalfuncModify = extractModify(defel);
154  else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
155  mfinalfuncModify = extractModify(defel);
156  else if (strcmp(defel->defname, "sortop") == 0)
157  sortoperatorName = defGetQualifiedName(defel);
158  else if (strcmp(defel->defname, "basetype") == 0)
159  baseType = defGetTypeName(defel);
160  else if (strcmp(defel->defname, "hypothetical") == 0)
161  {
162  if (defGetBoolean(defel))
163  {
164  if (aggKind == AGGKIND_NORMAL)
165  ereport(ERROR,
166  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
167  errmsg("only ordered-set aggregates can be hypothetical")));
168  aggKind = AGGKIND_HYPOTHETICAL;
169  }
170  }
171  else if (strcmp(defel->defname, "stype") == 0)
172  transType = defGetTypeName(defel);
173  else if (strcmp(defel->defname, "stype1") == 0)
174  transType = defGetTypeName(defel);
175  else if (strcmp(defel->defname, "sspace") == 0)
176  transSpace = defGetInt32(defel);
177  else if (strcmp(defel->defname, "mstype") == 0)
178  mtransType = defGetTypeName(defel);
179  else if (strcmp(defel->defname, "msspace") == 0)
180  mtransSpace = defGetInt32(defel);
181  else if (strcmp(defel->defname, "initcond") == 0)
182  initval = defGetString(defel);
183  else if (strcmp(defel->defname, "initcond1") == 0)
184  initval = defGetString(defel);
185  else if (strcmp(defel->defname, "minitcond") == 0)
186  minitval = defGetString(defel);
187  else if (strcmp(defel->defname, "parallel") == 0)
188  parallel = defGetString(defel);
189  else
191  (errcode(ERRCODE_SYNTAX_ERROR),
192  errmsg("aggregate attribute \"%s\" not recognized",
193  defel->defname)));
194  }
195 
196  /*
197  * make sure we have our required definitions
198  */
199  if (transType == NULL)
200  ereport(ERROR,
201  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
202  errmsg("aggregate stype must be specified")));
203  if (transfuncName == NIL)
204  ereport(ERROR,
205  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
206  errmsg("aggregate sfunc must be specified")));
207 
208  /*
209  * if mtransType is given, mtransfuncName and minvtransfuncName must be as
210  * well; if not, then none of the moving-aggregate options should have
211  * been given.
212  */
213  if (mtransType != NULL)
214  {
215  if (mtransfuncName == NIL)
216  ereport(ERROR,
217  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
218  errmsg("aggregate msfunc must be specified when mstype is specified")));
219  if (minvtransfuncName == NIL)
220  ereport(ERROR,
221  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
222  errmsg("aggregate minvfunc must be specified when mstype is specified")));
223  }
224  else
225  {
226  if (mtransfuncName != NIL)
227  ereport(ERROR,
228  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229  errmsg("aggregate msfunc must not be specified without mstype")));
230  if (minvtransfuncName != NIL)
231  ereport(ERROR,
232  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233  errmsg("aggregate minvfunc must not be specified without mstype")));
234  if (mfinalfuncName != NIL)
235  ereport(ERROR,
236  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237  errmsg("aggregate mfinalfunc must not be specified without mstype")));
238  if (mtransSpace != 0)
239  ereport(ERROR,
240  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241  errmsg("aggregate msspace must not be specified without mstype")));
242  if (minitval != NULL)
243  ereport(ERROR,
244  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
245  errmsg("aggregate minitcond must not be specified without mstype")));
246  }
247 
248  /*
249  * Default values for modify flags can only be determined once we know the
250  * aggKind.
251  */
252  if (finalfuncModify == 0)
253  finalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
254  if (mfinalfuncModify == 0)
255  mfinalfuncModify = (aggKind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
256 
257  /*
258  * look up the aggregate's input datatype(s).
259  */
260  if (oldstyle)
261  {
262  /*
263  * Old style: use basetype parameter. This supports aggregates of
264  * zero or one input, with input type ANY meaning zero inputs.
265  *
266  * Historically we allowed the command to look like basetype = 'ANY'
267  * so we must do a case-insensitive comparison for the name ANY. Ugh.
268  */
269  Oid aggArgTypes[1];
270 
271  if (baseType == NULL)
272  ereport(ERROR,
273  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
274  errmsg("aggregate input type must be specified")));
275 
276  if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
277  {
278  numArgs = 0;
279  aggArgTypes[0] = InvalidOid;
280  }
281  else
282  {
283  numArgs = 1;
284  aggArgTypes[0] = typenameTypeId(NULL, baseType);
285  }
286  parameterTypes = buildoidvector(aggArgTypes, numArgs);
287  allParameterTypes = NULL;
288  parameterModes = NULL;
289  parameterNames = NULL;
290  parameterDefaults = NIL;
291  variadicArgType = InvalidOid;
292  }
293  else
294  {
295  /*
296  * New style: args is a list of FunctionParameters (possibly zero of
297  * 'em). We share functioncmds.c's code for processing them.
298  */
299  Oid requiredResultType;
300 
301  if (baseType != NULL)
302  ereport(ERROR,
303  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
304  errmsg("basetype is redundant with aggregate input type specification")));
305 
306  numArgs = list_length(args);
308  args,
309  InvalidOid,
311  &parameterTypes,
312  NULL,
313  &allParameterTypes,
314  &parameterModes,
315  &parameterNames,
316  NULL,
317  &parameterDefaults,
318  &variadicArgType,
319  &requiredResultType);
320  /* Parameter defaults are not currently allowed by the grammar */
321  Assert(parameterDefaults == NIL);
322  /* There shouldn't have been any OUT parameters, either */
323  Assert(requiredResultType == InvalidOid);
324  }
325 
326  /*
327  * look up the aggregate's transtype.
328  *
329  * transtype can't be a pseudo-type, since we need to be able to store
330  * values of the transtype. However, we can allow polymorphic transtype
331  * in some cases (AggregateCreate will check). Also, we allow "internal"
332  * for functions that want to pass pointers to private data structures;
333  * but allow that only to superusers, since you could crash the system (or
334  * worse) by connecting up incompatible internal-using functions in an
335  * aggregate.
336  */
337  transTypeId = typenameTypeId(NULL, transType);
338  transTypeType = get_typtype(transTypeId);
339  if (transTypeType == TYPTYPE_PSEUDO &&
340  !IsPolymorphicType(transTypeId))
341  {
342  if (transTypeId == INTERNALOID && superuser())
343  /* okay */ ;
344  else
345  ereport(ERROR,
346  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
347  errmsg("aggregate transition data type cannot be %s",
348  format_type_be(transTypeId))));
349  }
350 
351  if (serialfuncName && deserialfuncName)
352  {
353  /*
354  * Serialization is only needed/allowed for transtype INTERNAL.
355  */
356  if (transTypeId != INTERNALOID)
357  ereport(ERROR,
358  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
359  errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
360  format_type_be(INTERNALOID))));
361  }
362  else if (serialfuncName || deserialfuncName)
363  {
364  /*
365  * Cannot specify one function without the other.
366  */
367  ereport(ERROR,
368  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
369  errmsg("must specify both or neither of serialization and deserialization functions")));
370  }
371 
372  /*
373  * If a moving-aggregate transtype is specified, look that up. Same
374  * restrictions as for transtype.
375  */
376  if (mtransType)
377  {
378  mtransTypeId = typenameTypeId(NULL, mtransType);
379  mtransTypeType = get_typtype(mtransTypeId);
380  if (mtransTypeType == TYPTYPE_PSEUDO &&
381  !IsPolymorphicType(mtransTypeId))
382  {
383  if (mtransTypeId == INTERNALOID && superuser())
384  /* okay */ ;
385  else
386  ereport(ERROR,
387  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
388  errmsg("aggregate transition data type cannot be %s",
389  format_type_be(mtransTypeId))));
390  }
391  }
392 
393  /*
394  * If we have an initval, and it's not for a pseudotype (particularly a
395  * polymorphic type), make sure it's acceptable to the type's input
396  * function. We will store the initval as text, because the input
397  * function isn't necessarily immutable (consider "now" for timestamp),
398  * and we want to use the runtime not creation-time interpretation of the
399  * value. However, if it's an incorrect value it seems much more
400  * user-friendly to complain at CREATE AGGREGATE time.
401  */
402  if (initval && transTypeType != TYPTYPE_PSEUDO)
403  {
404  Oid typinput,
405  typioparam;
406 
407  getTypeInputInfo(transTypeId, &typinput, &typioparam);
408  (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
409  }
410 
411  /*
412  * Likewise for moving-aggregate initval.
413  */
414  if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
415  {
416  Oid typinput,
417  typioparam;
418 
419  getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
420  (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
421  }
422 
423  if (parallel)
424  {
425  if (strcmp(parallel, "safe") == 0)
426  proparallel = PROPARALLEL_SAFE;
427  else if (strcmp(parallel, "restricted") == 0)
428  proparallel = PROPARALLEL_RESTRICTED;
429  else if (strcmp(parallel, "unsafe") == 0)
430  proparallel = PROPARALLEL_UNSAFE;
431  else
432  ereport(ERROR,
433  (errcode(ERRCODE_SYNTAX_ERROR),
434  errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
435  }
436 
437  /*
438  * Most of the argument-checking is done inside of AggregateCreate
439  */
440  return AggregateCreate(aggName, /* aggregate name */
441  aggNamespace, /* namespace */
442  replace,
443  aggKind,
444  numArgs,
445  numDirectArgs,
446  parameterTypes,
447  PointerGetDatum(allParameterTypes),
448  PointerGetDatum(parameterModes),
449  PointerGetDatum(parameterNames),
450  parameterDefaults,
451  variadicArgType,
452  transfuncName, /* step function name */
453  finalfuncName, /* final function name */
454  combinefuncName, /* combine function name */
455  serialfuncName, /* serial function name */
456  deserialfuncName, /* deserial function name */
457  mtransfuncName, /* fwd trans function name */
458  minvtransfuncName, /* inv trans function name */
459  mfinalfuncName, /* final function name */
460  finalfuncExtraArgs,
461  mfinalfuncExtraArgs,
462  finalfuncModify,
463  mfinalfuncModify,
464  sortoperatorName, /* sort operator name */
465  transTypeId, /* transition data type */
466  transSpace, /* transition space */
467  mtransTypeId, /* transition data type */
468  mtransSpace, /* transition space */
469  initval, /* initial condition */
470  minitval, /* initial condition */
471  proparallel); /* parallel safe? */
472 }
static char extractModify(DefElem *defel)
int32 defGetInt32(DefElem *def)
Definition: define.c:162
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:284
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1754
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2249
ObjectAddress AggregateCreate(const char *aggName, Oid aggNamespace, bool replace, char aggKind, int numArgs, int numDirectArgs, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Oid variadicArgType, List *aggtransfnName, List *aggfinalfnName, List *aggcombinefnName, List *aggserialfnName, List *aggdeserialfnName, List *aggmtransfnName, List *aggminvtransfnName, List *aggmfinalfnName, bool finalfnExtraArgs, bool mfinalfnExtraArgs, char finalfnModify, char mfinalfnModify, List *aggsortopName, Oid aggTransType, int32 aggTransSpace, Oid aggmTransType, int32 aggmTransSpace, const char *agginitval, const char *aggminitval, char proparallel)
Definition: pg_aggregate.c:46
#define linitial_node(type, l)
Definition: pg_list.h:181
#define lsecond(l)
Definition: pg_list.h:183

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, AggregateCreate(), generate_unaccent_rules::args, Assert, buildoidvector(), defGetBoolean(), defGetInt32(), defGetQualifiedName(), defGetString(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, extractModify(), format_type_be(), get_namespace_name(), get_typtype(), getTypeInputInfo(), GetUserId(), interpret_function_parameter_list(), intVal, InvalidOid, lfirst_node, linitial_node, list_length(), lsecond, name, NIL, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_SCHEMA, OidInputFunctionCall(), pg_strcasecmp(), PointerGetDatum(), QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ DefineIndex()

ObjectAddress DefineIndex ( Oid  tableId,
IndexStmt stmt,
Oid  indexRelationId,
Oid  parentIndexId,
Oid  parentConstraintId,
int  total_parts,
bool  is_alter_table,
bool  check_rights,
bool  check_not_in_use,
bool  skip_build,
bool  quiet 
)

Definition at line 531 of file indexcmds.c.

542 {
543  bool concurrent;
544  char *indexRelationName;
545  char *accessMethodName;
546  Oid *typeIds;
547  Oid *collationIds;
548  Oid *opclassIds;
549  Datum *opclassOptions;
550  Oid accessMethodId;
551  Oid namespaceId;
552  Oid tablespaceId;
553  Oid createdConstraintId = InvalidOid;
554  List *indexColNames;
555  List *allIndexParams;
556  Relation rel;
557  HeapTuple tuple;
558  Form_pg_am accessMethodForm;
559  IndexAmRoutine *amRoutine;
560  bool amcanorder;
561  bool amissummarizing;
562  amoptions_function amoptions;
563  bool partitioned;
564  bool safe_index;
565  Datum reloptions;
566  int16 *coloptions;
567  IndexInfo *indexInfo;
568  bits16 flags;
569  bits16 constr_flags;
570  int numberOfAttributes;
571  int numberOfKeyAttributes;
572  TransactionId limitXmin;
573  ObjectAddress address;
574  LockRelId heaprelid;
575  LOCKTAG heaplocktag;
576  LOCKMODE lockmode;
577  Snapshot snapshot;
578  Oid root_save_userid;
579  int root_save_sec_context;
580  int root_save_nestlevel;
581 
582  root_save_nestlevel = NewGUCNestLevel();
583 
585 
586  /*
587  * Some callers need us to run with an empty default_tablespace; this is a
588  * necessary hack to be able to reproduce catalog state accurately when
589  * recreating indexes after table-rewriting ALTER TABLE.
590  */
591  if (stmt->reset_default_tblspc)
592  (void) set_config_option("default_tablespace", "",
594  GUC_ACTION_SAVE, true, 0, false);
595 
596  /*
597  * Force non-concurrent build on temporary relations, even if CONCURRENTLY
598  * was requested. Other backends can't access a temporary relation, so
599  * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
600  * is more efficient. Do this before any use of the concurrent option is
601  * done.
602  */
603  if (stmt->concurrent && get_rel_persistence(tableId) != RELPERSISTENCE_TEMP)
604  concurrent = true;
605  else
606  concurrent = false;
607 
608  /*
609  * Start progress report. If we're building a partition, this was already
610  * done.
611  */
612  if (!OidIsValid(parentIndexId))
613  {
616  concurrent ?
619  }
620 
621  /*
622  * No index OID to report yet
623  */
625  InvalidOid);
626 
627  /*
628  * count key attributes in index
629  */
630  numberOfKeyAttributes = list_length(stmt->indexParams);
631 
632  /*
633  * Calculate the new list of index columns including both key columns and
634  * INCLUDE columns. Later we can determine which of these are key
635  * columns, and which are just part of the INCLUDE list by checking the
636  * list position. A list item in a position less than ii_NumIndexKeyAttrs
637  * is part of the key columns, and anything equal to and over is part of
638  * the INCLUDE columns.
639  */
640  allIndexParams = list_concat_copy(stmt->indexParams,
641  stmt->indexIncludingParams);
642  numberOfAttributes = list_length(allIndexParams);
643 
644  if (numberOfKeyAttributes <= 0)
645  ereport(ERROR,
646  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
647  errmsg("must specify at least one column")));
648  if (numberOfAttributes > INDEX_MAX_KEYS)
649  ereport(ERROR,
650  (errcode(ERRCODE_TOO_MANY_COLUMNS),
651  errmsg("cannot use more than %d columns in an index",
652  INDEX_MAX_KEYS)));
653 
654  /*
655  * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
656  * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
657  * (but not VACUUM).
658  *
659  * NB: Caller is responsible for making sure that tableId refers to the
660  * relation on which the index should be built; except in bootstrap mode,
661  * this will typically require the caller to have already locked the
662  * relation. To avoid lock upgrade hazards, that lock should be at least
663  * as strong as the one we take here.
664  *
665  * NB: If the lock strength here ever changes, code that is run by
666  * parallel workers under the control of certain particular ambuild
667  * functions will need to be updated, too.
668  */
669  lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
670  rel = table_open(tableId, lockmode);
671 
672  /*
673  * Switch to the table owner's userid, so that any index functions are run
674  * as that user. Also lock down security-restricted operations. We
675  * already arranged to make GUC variable changes local to this command.
676  */
677  GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context);
678  SetUserIdAndSecContext(rel->rd_rel->relowner,
679  root_save_sec_context | SECURITY_RESTRICTED_OPERATION);
680 
681  namespaceId = RelationGetNamespace(rel);
682 
683  /