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 relationId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
 
void ExecReindex (ParseState *pstate, 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, List *attributeList, List *exclusionOpNames)
 
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
 
Oid ResolveOpClass (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)
 
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 
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 */
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:709
#define OidIsValid(objectId)
Definition: c.h:721
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1151
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define WARNING
Definition: elog.h:30
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
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, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:195
#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:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:293
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
#define CStringGetDatum(X)
Definition: postgres.h:622
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetPointer(X)
Definition: postgres.h:593
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define PointerGetDatum(X)
Definition: postgres.h:600
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:514
List * func_options
Definition: parsenodes.h:2748
List * options
Definition: parsenodes.h:2749
char * fdwname
Definition: parsenodes.h:2747
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:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ FOREIGNDATAWRAPPEROID
Definition: syscache.h:62
@ FOREIGNDATAWRAPPERNAME
Definition: syscache.h:61
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

References CatalogTupleUpdate(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, AlterFdwStmt::fdwname, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, AlterFdwStmt::func_options, GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, AlterFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, 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 
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 }
const char * name
Definition: encode.c:561
static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:205

References AlterForeignDataWrapperOwner_internal(), CStringGetDatum, ereport, errcode(), errmsg(), ERROR, FOREIGNDATAWRAPPERNAME, 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 
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, FOREIGNDATAWRAPPEROID, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned().

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)

Definition at line 965 of file foreigncmds.c.

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

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, FOREIGNSERVERNAME, FOREIGNSERVEROID, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), AlterForeignServerStmt::has_version, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, OBJECT_FOREIGN_SERVER, ObjectAddressSet, AlterForeignServerStmt::options, pg_foreign_server_ownercheck(), PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, AlterForeignServerStmt::servername, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), and AlterForeignServerStmt::version.

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 
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, FOREIGNSERVERNAME, 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 
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, FOREIGNSERVEROID, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned().

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)

Definition at line 1351 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterOperator()

ObjectAddress AlterOperator ( AlterOperatorStmt stmt)

Definition at line 409 of file operatorcmds.c.

410 {
411  ObjectAddress address;
412  Oid oprId;
413  Relation catalog;
414  HeapTuple tup;
415  Form_pg_operator oprForm;
416  int i;
417  ListCell *pl;
418  Datum values[Natts_pg_operator];
419  bool nulls[Natts_pg_operator];
420  bool replaces[Natts_pg_operator];
421  List *restrictionName = NIL; /* optional restrict. sel. function */
422  bool updateRestriction = false;
423  Oid restrictionOid;
424  List *joinName = NIL; /* optional join sel. function */
425  bool updateJoin = false;
426  Oid joinOid;
427 
428  /* Look up the operator */
429  oprId = LookupOperWithArgs(stmt->opername, false);
430  catalog = table_open(OperatorRelationId, RowExclusiveLock);
432  if (!HeapTupleIsValid(tup))
433  elog(ERROR, "cache lookup failed for operator %u", oprId);
434  oprForm = (Form_pg_operator) GETSTRUCT(tup);
435 
436  /* Process options */
437  foreach(pl, stmt->options)
438  {
439  DefElem *defel = (DefElem *) lfirst(pl);
440  List *param;
441 
442  if (defel->arg == NULL)
443  param = NIL; /* NONE, removes the function */
444  else
445  param = defGetQualifiedName(defel);
446 
447  if (strcmp(defel->defname, "restrict") == 0)
448  {
449  restrictionName = param;
450  updateRestriction = true;
451  }
452  else if (strcmp(defel->defname, "join") == 0)
453  {
454  joinName = param;
455  updateJoin = true;
456  }
457 
458  /*
459  * The rest of the options that CREATE accepts cannot be changed.
460  * Check for them so that we can give a meaningful error message.
461  */
462  else if (strcmp(defel->defname, "leftarg") == 0 ||
463  strcmp(defel->defname, "rightarg") == 0 ||
464  strcmp(defel->defname, "function") == 0 ||
465  strcmp(defel->defname, "procedure") == 0 ||
466  strcmp(defel->defname, "commutator") == 0 ||
467  strcmp(defel->defname, "negator") == 0 ||
468  strcmp(defel->defname, "hashes") == 0 ||
469  strcmp(defel->defname, "merges") == 0)
470  {
471  ereport(ERROR,
472  (errcode(ERRCODE_SYNTAX_ERROR),
473  errmsg("operator attribute \"%s\" cannot be changed",
474  defel->defname)));
475  }
476  else
477  ereport(ERROR,
478  (errcode(ERRCODE_SYNTAX_ERROR),
479  errmsg("operator attribute \"%s\" not recognized",
480  defel->defname)));
481  }
482 
483  /* Check permissions. Must be owner. */
484  if (!pg_oper_ownercheck(oprId, GetUserId()))
486  NameStr(oprForm->oprname));
487 
488  /*
489  * Look up restriction and join estimators if specified
490  */
491  if (restrictionName)
492  restrictionOid = ValidateRestrictionEstimator(restrictionName);
493  else
494  restrictionOid = InvalidOid;
495  if (joinName)
496  joinOid = ValidateJoinEstimator(joinName);
497  else
498  joinOid = InvalidOid;
499 
500  /* Perform additional checks, like OperatorCreate does */
501  if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
502  {
503  /* If it's not a binary op, these things mustn't be set: */
504  if (OidIsValid(joinOid))
505  ereport(ERROR,
506  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
507  errmsg("only binary operators can have join selectivity")));
508  }
509 
510  if (oprForm->oprresult != BOOLOID)
511  {
512  if (OidIsValid(restrictionOid))
513  ereport(ERROR,
514  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
515  errmsg("only boolean operators can have restriction selectivity")));
516  if (OidIsValid(joinOid))
517  ereport(ERROR,
518  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
519  errmsg("only boolean operators can have join selectivity")));
520  }
521 
522  /* Update the tuple */
523  for (i = 0; i < Natts_pg_operator; ++i)
524  {
525  values[i] = (Datum) 0;
526  replaces[i] = false;
527  nulls[i] = false;
528  }
529  if (updateRestriction)
530  {
531  replaces[Anum_pg_operator_oprrest - 1] = true;
532  values[Anum_pg_operator_oprrest - 1] = restrictionOid;
533  }
534  if (updateJoin)
535  {
536  replaces[Anum_pg_operator_oprjoin - 1] = true;
537  values[Anum_pg_operator_oprjoin - 1] = joinOid;
538  }
539 
540  tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
541  values, nulls, replaces);
542 
543  CatalogTupleUpdate(catalog, &tup->t_self, tup);
544 
545  address = makeOperatorDependencies(tup, false, true);
546 
547  InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
548 
549  table_close(catalog, NoLock);
550 
551  return address;
552 }
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:5223
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define NameStr(name)
Definition: c.h:692
List * defGetQualifiedName(DefElem *def)
Definition: define.c:220
int i
Definition: isn.c:73
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:308
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:273
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:145
@ OBJECT_OPERATOR
Definition: parsenodes.h:2160
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
Definition: pg_operator.c:777
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
#define InvalidOid
Definition: postgres_ext.h:36
ObjectWithArgs * opername
Definition: parsenodes.h:3465
@ OPEROID
Definition: syscache.h:72

References aclcheck_error(), ACLCHECK_NOT_OWNER, DefElem::arg, CatalogTupleUpdate(), 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, ObjectIdGetDatum, OidIsValid, AlterOperatorStmt::opername, OPEROID, AlterOperatorStmt::options, pg_oper_ownercheck(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), ValidateJoinEstimator(), ValidateRestrictionEstimator(), and values.

Referenced by ProcessUtilitySlow().

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 817 of file opclasscmds.c.

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

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AlterOpFamilyStmt::amname, AMNAME, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, AlterOpFamilyStmt::isDrop, AlterOpFamilyStmt::items, AlterOpFamilyStmt::opfamilyname, ReleaseSysCache(), SearchSysCache1(), 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 = stmt->stxstattarget;
610 
611  /* Limit statistics target to a sane range */
612  if (newtarget < -1)
613  {
614  ereport(ERROR,
615  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
616  errmsg("statistics target %d is too low",
617  newtarget)));
618  }
619  else if (newtarget > 10000)
620  {
621  newtarget = 10000;
623  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
624  errmsg("lowering statistics target to %d",
625  newtarget)));
626  }
627 
628  /* lookup OID of the statistics object */
629  stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
630 
631  /*
632  * If we got here and the OID is not valid, it means the statistics object
633  * does not exist, but the command specified IF EXISTS. So report this as
634  * a simple NOTICE and we're done.
635  */
636  if (!OidIsValid(stxoid))
637  {
638  char *schemaname;
639  char *statname;
640 
641  Assert(stmt->missing_ok);
642 
643  DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
644 
645  if (schemaname)
646  ereport(NOTICE,
647  (errmsg("statistics object \"%s.%s\" does not exist, skipping",
648  schemaname, statname)));
649  else
650  ereport(NOTICE,
651  (errmsg("statistics object \"%s\" does not exist, skipping",
652  statname)));
653 
654  return InvalidObjectAddress;
655  }
656 
657  /* Search pg_statistic_ext */
658  rel = table_open(StatisticExtRelationId, RowExclusiveLock);
659 
660  oldtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxoid));
661  if (!HeapTupleIsValid(oldtup))
662  elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
663 
664  /* Must be owner of the existing statistics object */
667  NameListToString(stmt->defnames));
668 
669  /* Build new tuple. */
670  memset(repl_val, 0, sizeof(repl_val));
671  memset(repl_null, false, sizeof(repl_null));
672  memset(repl_repl, false, sizeof(repl_repl));
673 
674  /* replace the stxstattarget column */
675  repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
676  repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int32GetDatum(newtarget);
677 
678  newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
679  repl_val, repl_null, repl_repl);
680 
681  /* Update system catalog. */
682  CatalogTupleUpdate(rel, &newtup->t_self, newtup);
683 
684  InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0);
685 
686  ObjectAddressSet(address, StatisticExtRelationId, stxoid);
687 
688  /*
689  * NOTE: because we only support altering the statistics target, not the
690  * other fields, there is no need to update dependencies.
691  */
692 
693  heap_freetuple(newtup);
694  ReleaseSysCache(oldtup);
695 
697 
698  return address;
699 }
bool pg_statistics_object_ownercheck(Oid stat_oid, Oid roleid)
Definition: aclchk.c:5761
#define NOTICE
Definition: elog.h:29
Assert(fmt[strlen(fmt) - 1] !='\n')
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2855
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2224
const ObjectAddress InvalidObjectAddress
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2174
#define Int32GetDatum(X)
Definition: postgres.h:523
@ STATEXTOID
Definition: syscache.h:96

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert(), CatalogTupleUpdate(), DeconstructQualifiedName(), AlterStatsStmt::defnames, elog(), ereport, errcode(), errmsg(), ERROR, get_statistics_object_oid(), GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, Int32GetDatum, InvalidObjectAddress, InvokeObjectPostAlterHook, AlterStatsStmt::missing_ok, NameListToString(), NOTICE, OBJECT_STATISTIC_EXT, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, pg_statistics_object_ownercheck(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), STATEXTOID, AlterStatsStmt::stxstattarget, HeapTupleData::t_self, table_close(), table_open(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ AlterTSConfiguration()

ObjectAddress AlterTSConfiguration ( AlterTSConfigurationStmt stmt)

Definition at line 1109 of file tsearchcmds.c.

1110 {
1111  HeapTuple tup;
1112  Oid cfgId;
1113  Relation relMap;
1114  ObjectAddress address;
1115 
1116  /* Find the configuration */
1117  tup = GetTSConfigTuple(stmt->cfgname);
1118  if (!HeapTupleIsValid(tup))
1119  ereport(ERROR,
1120  (errcode(ERRCODE_UNDEFINED_OBJECT),
1121  errmsg("text search configuration \"%s\" does not exist",
1122  NameListToString(stmt->cfgname))));
1123 
1124  cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid;
1125 
1126  /* must be owner */
1127  if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
1129  NameListToString(stmt->cfgname));
1130 
1131  relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);
1132 
1133  /* Add or drop mappings */
1134  if (stmt->dicts)
1135  MakeConfigurationMapping(stmt, tup, relMap);
1136  else if (stmt->tokentype)
1137  DropConfigurationMapping(stmt, tup, relMap);
1138 
1139  /* Update dependencies */
1140  makeConfigurationDependencies(tup, true, relMap);
1141 
1142  InvokeObjectPostAlterHook(TSConfigRelationId, cfgId, 0);
1143 
1144  ObjectAddressSet(address, TSConfigRelationId, cfgId);
1145 
1146  table_close(relMap, RowExclusiveLock);
1147 
1148  ReleaseSysCache(tup);
1149 
1150  return address;
1151 }
bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
Definition: aclchk.c:5481
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2180
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:806
static HeapTuple GetTSConfigTuple(List *names)
Definition: tsearchcmds.c:781
static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)
Definition: tsearchcmds.c:1376
static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)
Definition: tsearchcmds.c:1212

References aclcheck_error(), ACLCHECK_NOT_OWNER, AlterTSConfigurationStmt::cfgname, AlterTSConfigurationStmt::dicts, DropConfigurationMapping(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetTSConfigTuple(), GetUserId(), HeapTupleIsValid, InvokeObjectPostAlterHook, makeConfigurationDependencies(), MakeConfigurationMapping(), NameListToString(), OBJECT_TSCONFIGURATION, ObjectAddressSet, pg_ts_config_ownercheck(), ReleaseSysCache(), RowExclusiveLock, table_close(), table_open(), and AlterTSConfigurationStmt::tokentype.

Referenced by ProcessUtilitySlow().

◆ AlterTSDictionary()

ObjectAddress AlterTSDictionary ( AlterTSDictionaryStmt stmt)

Definition at line 487 of file tsearchcmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterUserMapping()

ObjectAddress AlterUserMapping ( AlterUserMappingStmt stmt)

Definition at line 1213 of file foreigncmds.c.

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

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, AlterUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationGetDescr, ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, AlterUserMappingStmt::servername, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), AlterUserMappingStmt::user, user_mapping_ddl_aclcheck(), and USERMAPPINGOID.

Referenced by ProcessUtilitySlow().

◆ CallStmtResultDesc()

TupleDesc CallStmtResultDesc ( CallStmt stmt)

Definition at line 2353 of file functioncmds.c.

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

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

Referenced by UtilityTupleDescriptor().

◆ CheckIndexCompatible()

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

Definition at line 167 of file indexcmds.c.

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

References AccessShareLock, IndexAmRoutine::amcanorder, AMNAME, Assert(), CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer, elog(), ereport, errcode(), errmsg(), ERROR, get_opclass_input_type(), GetIndexAmRoutine(), GETSTRUCT, heap_attisnull(), HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_OpclassOptions, index_close(), INDEX_MAX_KEYS, index_open(), IndexGetRelation(), INDEXRELID, InvalidOid, list_length(), makeIndexInfo(), NIL, NoLock, ObjectIdGetDatum, op_input_types(), palloc(), pfree(), PointerGetDatum, RelationData::rd_att, RelationGetExclusionInfo(), RelationGetIndexRawAttOptions(), ReleaseSysCache(), SearchSysCache1(), SysCacheGetAttr(), 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 2403 of file indexcmds.c.

2406 {
2407  int pass = 0;
2408  char *relname = NULL;
2409  char modlabel[NAMEDATALEN];
2410 
2411  /* try the unmodified label first */
2412  strlcpy(modlabel, label, sizeof(modlabel));
2413 
2414  for (;;)
2415  {
2416  relname = makeObjectName(name1, name2, modlabel);
2417 
2418  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2419  {
2420  if (!isconstraint ||
2421  !ConstraintNameExists(relname, namespaceid))
2422  break;
2423  }
2424 
2425  /* found a conflict, so try a new name component */
2426  pfree(relname);
2427  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2428  }
2429 
2430  return relname;
2431 }
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2317
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1866
static char * label
NameData relname
Definition: pg_class.h:38
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition: port.h:225
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:391
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:171
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:191
#define CharGetDatum(X)
Definition: postgres.h:460
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
List * handler_name
Definition: parsenodes.h:2880
char * amname
Definition: parsenodes.h:2879
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:197

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

Referenced by ProcessUtilitySlow().

◆ CreateCast()

ObjectAddress CreateCast ( CreateCastStmt stmt)

Definition at line 1525 of file functioncmds.c.

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

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, CastCreate(), COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, CreateCastStmt::context, DEPENDENCY_NORMAL, elog(), ereport, errcode(), errmsg(), ERROR, format_type_be(), CreateCastStmt::func, get_element_type(), get_typlenbyvalalign(), get_typtype(), GETSTRUCT, GetUserId(), HeapTupleIsValid, CreateCastStmt::inout, InvalidOid, IsBinaryCoercible(), LookupFuncWithArgs(), OBJECT_FUNCTION, ObjectIdGetDatum, OidIsValid, pg_type_aclcheck(), pg_type_ownercheck(), PROCOID, ReleaseSysCache(), SearchSysCache1(), CreateCastStmt::sourcetype, superuser(), CreateCastStmt::targettype, 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:95
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
List * func_options
Definition: parsenodes.h:2740
char * fdwname
Definition: parsenodes.h:2739
List * options
Definition: parsenodes.h:2741

References CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, CreateFdwStmt::fdwname, CreateFdwStmt::func_options, GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, namein(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, 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. Do nothing if
859  * IF NOT EXISTS was enforced.
860  */
861  if (GetForeignServerByName(stmt->servername, true) != NULL)
862  {
863  if (stmt->if_not_exists)
864  {
865  ereport(NOTICE,
867  errmsg("server \"%s\" already exists, skipping",
868  stmt->servername)));
870  return InvalidObjectAddress;
871  }
872  else
873  ereport(ERROR,
875  errmsg("server \"%s\" already exists",
876  stmt->servername)));
877  }
878 
879  /*
880  * Check that the FDW exists and that we have USAGE on it. Also get the
881  * actual FDW for option validation etc.
882  */
883  fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
884 
885  aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
886  if (aclresult != ACLCHECK_OK)
887  aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
888 
889  /*
890  * Insert tuple into pg_foreign_server.
891  */
892  memset(values, 0, sizeof(values));
893  memset(nulls, false, sizeof(nulls));
894 
895  srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId,
896  Anum_pg_foreign_server_oid);
897  values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId);
898  values[Anum_pg_foreign_server_srvname - 1] =
900  values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
901  values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
902 
903  /* Add server type if supplied */
904  if (stmt->servertype)
905  values[Anum_pg_foreign_server_srvtype - 1] =
907  else
908  nulls[Anum_pg_foreign_server_srvtype - 1] = true;
909 
910  /* Add server version if supplied */
911  if (stmt->version)
912  values[Anum_pg_foreign_server_srvversion - 1] =
914  else
915  nulls[Anum_pg_foreign_server_srvversion - 1] = true;
916 
917  /* Start with a blank acl */
918  nulls[Anum_pg_foreign_server_srvacl - 1] = true;
919 
920  /* Add server options */
921  srvoptions = transformGenericOptions(ForeignServerRelationId,
922  PointerGetDatum(NULL),
923  stmt->options,
924  fdw->fdwvalidator);
925 
926  if (PointerIsValid(DatumGetPointer(srvoptions)))
927  values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
928  else
929  nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
930 
931  tuple = heap_form_tuple(rel->rd_att, values, nulls);
932 
933  CatalogTupleInsert(rel, tuple);
934 
935  heap_freetuple(tuple);
936 
937  /* record dependencies */
938  myself.classId = ForeignServerRelationId;
939  myself.objectId = srvId;
940  myself.objectSubId = 0;
941 
942  referenced.classId = ForeignDataWrapperRelationId;
943  referenced.objectId = fdw->fdwid;
944  referenced.objectSubId = 0;
945  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
946 
947  recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
948 
949  /* dependency on extension */
950  recordDependencyOnCurrentExtension(&myself, false);
951 
952  /* Post creation hook for new foreign server */
953  InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
954 
956 
957  return myself;
958 }
AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5134
@ OBJECT_FDW
Definition: parsenodes.h:2151
char * fdwname
Definition: foreign.h:28

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, CreateForeignServerStmt::fdwname, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapperByName(), GetForeignServerByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), CreateForeignServerStmt::if_not_exists, InvalidObjectAddress, InvokeObjectPostCreateHook, namein(), NOTICE, OBJECT_FDW, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignServerStmt::options, pg_foreign_data_wrapper_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, CreateForeignServerStmt::servername, CreateForeignServerStmt::servertype, table_close(), table_open(), transformGenericOptions(), values, and CreateForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

◆ CreateForeignTable()

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1391 of file foreigncmds.c.

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

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_FOREIGN_SERVER, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignTableStmt::options, pg_foreign_server_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, CreateForeignTableStmt::servername, table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateFunction()

ObjectAddress CreateFunction ( ParseState pstate,
CreateFunctionStmt stmt 
)

Definition at line 1017 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateStatistics()

ObjectAddress CreateStatistics ( CreateStatsStmt stmt)

Definition at line 65 of file statscmds.c.

66 {
67  int16 attnums[STATS_MAX_DIMENSIONS];
68  int nattnums = 0;
69  int numcols;
70  char *namestr;
71  NameData stxname;
72  Oid statoid;
73  Oid namespaceId;
74  Oid stxowner = GetUserId();
75  HeapTuple htup;
76  Datum values[Natts_pg_statistic_ext];
77  bool nulls[Natts_pg_statistic_ext];
78  int2vector *stxkeys;
79  List *stxexprs = NIL;
80  Datum exprsDatum;
81  Relation statrel;
82  Relation rel = NULL;
83  Oid relid;
84  ObjectAddress parentobject,
85  myself;
86  Datum types[4]; /* one for each possible type of statistic */
87  int ntypes;
88  ArrayType *stxkind;
89  bool build_ndistinct;
90  bool build_dependencies;
91  bool build_mcv;
92  bool build_expressions;
93  bool requested_type = false;
94  int i;
95  ListCell *cell;
96  ListCell *cell2;
97 
98  Assert(IsA(stmt, CreateStatsStmt));
99 
100  /*
101  * Examine the FROM clause. Currently, we only allow it to be a single
102  * simple table, but later we'll probably allow multiple tables and JOIN
103  * syntax. The grammar is already prepared for that, so we have to check
104  * here that what we got is what we can support.
105  */
106  if (list_length(stmt->relations) != 1)
107  ereport(ERROR,
108  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
109  errmsg("only a single relation is allowed in CREATE STATISTICS")));
110 
111  foreach(cell, stmt->relations)
112  {
113  Node *rln = (Node *) lfirst(cell);
114 
115  if (!IsA(rln, RangeVar))
116  ereport(ERROR,
117  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
118  errmsg("only a single relation is allowed in CREATE STATISTICS")));
119 
120  /*
121  * CREATE STATISTICS will influence future execution plans but does
122  * not interfere with currently executing plans. So it should be
123  * enough to take only ShareUpdateExclusiveLock on relation,
124  * conflicting with ANALYZE and other DDL that sets statistical
125  * information, but not with normal queries.
126  */
128 
129  /* Restrict to allowed relation types */
130  if (rel->rd_rel->relkind != RELKIND_RELATION &&
131  rel->rd_rel->relkind != RELKIND_MATVIEW &&
132  rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
133  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
134  ereport(ERROR,
135  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
136  errmsg("cannot define statistics for relation \"%s\"",
138  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
139 
140  /* You must own the relation to create stats on it */
141  if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
144 
145  /* Creating statistics on system catalogs is not allowed */
147  ereport(ERROR,
148  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
149  errmsg("permission denied: \"%s\" is a system catalog",
150  RelationGetRelationName(rel))));
151  }
152 
153  Assert(rel);
154  relid = RelationGetRelid(rel);
155 
156  /*
157  * If the node has a name, split it up and determine creation namespace.
158  * If not (a possibility not considered by the grammar, but one which can
159  * occur via the "CREATE TABLE ... (LIKE)" command), then we put the
160  * object in the same namespace as the relation, and cons up a name for
161  * it.
162  */
163  if (stmt->defnames)
164  namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames,
165  &namestr);
166  else
167  {
168  namespaceId = RelationGetNamespace(rel);
171  "stat",
172  namespaceId);
173  }
174  namestrcpy(&stxname, namestr);
175 
176  /*
177  * Deal with the possibility that the statistics object already exists.
178  */
180  CStringGetDatum(namestr),
181  ObjectIdGetDatum(namespaceId)))
182  {
183  if (stmt->if_not_exists)
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 */
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 (list_length(stmt->stat_types) > 0)
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 = (list_length(stxexprs) > 0);
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_stxstattarget - 1] = Int32GetDatum(-1);
499  values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
500  values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
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 }
bool pg_class_ownercheck(Oid class_oid, Oid roleid)
Definition: aclchk.c:5171
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1045
#define lengthof(array)
Definition: c.h:745
bool IsSystemRelation(Relation relation)
Definition: catalog.c:75
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:1631
@ DEPENDENCY_AUTO
Definition: dependency.h:34
struct typedefs * types
Definition: ecpg.c:29
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3580
bool allowSystemTableMods
Definition: globals.c:124
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1363
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:825
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
#define IsA(nodeptr, _type_)
Definition: nodes.h:625
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:4789
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define qsort(a, b, c, d)
Definition: port.h:495
#define NameGetDatum(X)
Definition: postgres.h:639
#define RelationGetRelid(relation)
Definition: rel.h:488
#define RelationGetRelationName(relation)
Definition: rel.h:522
#define RelationGetNamespace(relation)
Definition: rel.h:529
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition: statscmds.c:828
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:786
static int compare_int16(const void *a, const void *b)
Definition: statscmds.c:52
Form_pg_class rd_rel
Definition: rel.h:109
char * name
Definition: parsenodes.h:3293
Node * expr
Definition: parsenodes.h:3294
Definition: primnodes.h:209
Oid vartype
Definition: primnodes.h:224
AttrNumber varattno
Definition: primnodes.h:221
Definition: c.h:661
Definition: c.h:687
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:1314
@ STATEXTNAMENSP
Definition: syscache.h:95
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:190
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
#define TYPECACHE_LT_OPR
Definition: typcache.h:137
#define strVal(v)
Definition: value.h:72
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:288

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, CreateStatsStmt::defnames, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, equal(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail_relkind_not_supported(), errmsg(), ERROR, StatsElem::expr, CreateStatsStmt::exprs, exprType(), FirstLowInvalidHeapAttributeNumber, format_type_be(), get_attname(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, if(), CreateStatsStmt::if_not_exists, Int32GetDatum, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHook, IsA, IsSystemRelation(), lappend(), lengthof, lfirst, lfirst_node, list_length(), lookup_type_cache(), StatsElem::name, NameGetDatum, namestrcpy(), NIL, nodeToString(), NoLock, NOTICE, ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum, pfree(), pg_class_ownercheck(), PointerGetDatum, pull_varattnos(), qsort, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RelationData::rd_rel, recordDependencyOn(), recordDependencyOnOwner(), recordDependencyOnSingleRelExpr(), relation_close(), relation_openrv(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, CreateStatsStmt::relations, ReleaseSysCache(), RowExclusiveLock, SearchSysCacheAttName(), SearchSysCacheExists2, ShareUpdateExclusiveLock, CreateStatsStmt::stat_types, STATEXTNAMENSP, STATS_MAX_DIMENSIONS, strVal, CreateStatsStmt::stxcomment, table_open(), generate_unaccent_rules::type, TYPECACHE_LT_OPR, types, values, Var::varattno, and Var::vartype.

Referenced by ATExecAddStatistics(), and ProcessUtilitySlow().

◆ CreateTransform()

ObjectAddress CreateTransform ( CreateTransformStmt stmt)

Definition at line 1799 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateUserMapping()

ObjectAddress CreateUserMapping ( CreateUserMappingStmt stmt)

Definition at line 1091 of file foreigncmds.c.

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

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(), CreateUserMappingStmt::if_not_exists, InvalidObjectAddress, InvokeObjectPostCreateHook, MappingUserName, NOTICE, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, ForeignServer::serverid, CreateUserMappingStmt::servername, table_close(), table_open(), transformGenericOptions(), CreateUserMappingStmt::user, user_mapping_ddl_aclcheck(), and values.

Referenced by ProcessUtilitySlow().

◆ defGetBoolean()

bool defGetBoolean ( DefElem def)

Definition at line 108 of file define.c.

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

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

Referenced by AlterDatabase(), 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(), transformRelOptions(), and UserMappingPasswordRequired().

◆ defGetInt32()

int32 defGetInt32 ( DefElem def)

Definition at line 163 of file define.c.

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

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

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

◆ defGetInt64()

int64 defGetInt64 ( DefElem def)

Definition at line 187 of file define.c.

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

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

Referenced by init_params(), and parse_basebackup_options().

◆ defGetNumeric()

double defGetNumeric ( DefElem def)

Definition at line 82 of file define.c.

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

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

Referenced by AlterFunction(), and compute_function_attributes().

◆ defGetQualifiedName()

List* defGetQualifiedName ( DefElem def)

Definition at line 220 of file define.c.

221 {
222  if (def->arg == NULL)
223  ereport(ERROR,
224  (errcode(ERRCODE_SYNTAX_ERROR),
225  errmsg("%s requires a parameter",
226  def->defname)));
227  switch (nodeTag(def->arg))
228  {
229  case T_TypeName:
230  return ((TypeName *) def->arg)->names;
231  case T_List:
232  return (List *) def->arg;
233  case T_String:
234  /* Allow quoted name for backwards compatibility */
235  return list_make1(def->arg);
236  default:
237  ereport(ERROR,
238  (errcode(ERRCODE_SYNTAX_ERROR),
239  errmsg("argument of %s must be a name",
240  def->defname)));
241  }
242  return NIL; /* keep compiler quiet */
243 }
@ T_List
Definition: nodes.h:317
@ T_TypeName
Definition: nodes.h:474
@ T_String
Definition: nodes.h:311
#define list_make1(x1)
Definition: pg_list.h:210

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

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 49 of file define.c.

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

Referenced by AlterDatabase(), AlterType(), apply_server_options(), apply_table_options(), check_selective_binary_conversion(), createdb(), CreateExtension(), defGetBoolean(), defGetCopyHeaderChoice(), 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(), optionListToArray(), parse_basebackup_options(), 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 324 of file define.c.

325 {
326  ListCell *cell;
327 
328  if (def->arg == NULL)
329  ereport(ERROR,
330  (errcode(ERRCODE_SYNTAX_ERROR),
331  errmsg("%s requires a parameter",
332  def->defname)));
333  if (nodeTag(def->arg) != T_List)
334  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
335 
336  foreach(cell, (List *) def->arg)
337  {
338  Node *str = (Node *) lfirst(cell);
339 
340  if (!IsA(str, String))
341  elog(ERROR, "unexpected node type in name list: %d",
342  (int) nodeTag(str));
343  }
344 
345  return (List *) def->arg;
346 }
Definition: value.h:58

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

◆ defGetTypeLength()

int defGetTypeLength ( DefElem def)

Definition at line 280 of file define.c.

281 {
282  if (def->arg == NULL)
283  ereport(ERROR,
284  (errcode(ERRCODE_SYNTAX_ERROR),
285  errmsg("%s requires a parameter",
286  def->defname)));
287  switch (nodeTag(def->arg))
288  {
289  case T_Integer:
290  return intVal(def->arg);
291  case T_Float:
292  ereport(ERROR,
293  (errcode(ERRCODE_SYNTAX_ERROR),
294  errmsg("%s requires an integer value",
295  def->defname)));
296  break;
297  case T_String:
298  if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
299  return -1; /* variable length */
300  break;
301  case T_TypeName:
302  /* cope if grammar chooses to believe "variable" is a typename */
304  "variable") == 0)
305  return -1; /* variable length */
306  break;
307  case T_List:
308  /* must be an operator name */
309  break;
310  default:
311  elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
312  }
313  ereport(ERROR,
314  (errcode(ERRCODE_SYNTAX_ERROR),
315  errmsg("invalid argument for %s: \"%s\"",
316  def->defname, defGetString(def))));
317  return 0; /* keep compiler quiet */
318 }

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

Referenced by DefineType().

◆ defGetTypeName()

TypeName* defGetTypeName ( 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;
263  case T_String:
264  /* Allow quoted typename for backwards compatibility */
266  default:
267  ereport(ERROR,
268  (errcode(ERRCODE_SYNTAX_ERROR),
269  errmsg("argument of %s must be a type name",
270  def->defname)));
271  }
272  return NULL; /* keep compiler quiet */
273 }
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:457

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

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 56 of file aggregatecmds.c.

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

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_AGGREGATE, OBJECT_SCHEMA, OidInputFunctionCall(), pg_namespace_aclcheck(), pg_strcasecmp(), PointerGetDatum, QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ DefineIndex()

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

Definition at line 521 of file indexcmds.c.

531 {
532  bool concurrent;
533  char *indexRelationName;
534  char *accessMethodName;
535  Oid *typeObjectId;
536  Oid *collationObjectId;
537  Oid *classObjectId;
538  Oid accessMethodId;
539  Oid namespaceId;
540  Oid tablespaceId;
541  Oid createdConstraintId = InvalidOid;
542  List *indexColNames;
543  List *allIndexParams;
544  Relation rel;
545  HeapTuple tuple;
546  Form_pg_am accessMethodForm;
547  IndexAmRoutine *amRoutine;
548  bool amcanorder;
549  amoptions_function amoptions;
550  bool partitioned;
551  bool safe_index;
552  Datum reloptions;
553  int16 *coloptions;
554  IndexInfo *indexInfo;
555  bits16 flags;
556  bits16 constr_flags;
557  int numberOfAttributes;
558  int numberOfKeyAttributes;
559  TransactionId limitXmin;
560  ObjectAddress address;
561  LockRelId heaprelid;
562  LOCKTAG heaplocktag;
563  LOCKMODE lockmode;
564  Snapshot snapshot;
565  Oid root_save_userid;
566  int root_save_sec_context;
567  int root_save_nestlevel;
568  int i;
569 
570  root_save_nestlevel = NewGUCNestLevel();
571 
572  /*
573  * Some callers need us to run with an empty default_tablespace; this is a
574  * necessary hack to be able to reproduce catalog state accurately when
575  * recreating indexes after table-rewriting ALTER TABLE.
576  */
577  if (stmt->reset_default_tblspc)
578  (void) set_config_option("default_tablespace", "",
580  GUC_ACTION_SAVE, true, 0, false);
581 
582  /*
583  * Force non-concurrent build on temporary relations, even if CONCURRENTLY
584  * was requested. Other backends can't access a temporary relation, so
585  * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
586  * is more efficient. Do this before any use of the concurrent option is
587  * done.
588  */
589  if (stmt->concurrent && get_rel_persistence(relationId) != RELPERSISTENCE_TEMP)
590  concurrent = true;
591  else
592  concurrent = false;
593 
594  /*
595  * Start progress report. If we're building a partition, this was already
596  * done.
597  */
598  if (!OidIsValid(parentIndexId))
599  {
601  relationId);
603  concurrent ?
606  }
607 
608  /*
609  * No index OID to report yet
610  */
612  InvalidOid);
613 
614  /*
615  * count key attributes in index
616  */
617  numberOfKeyAttributes = list_length(stmt->indexParams);
618 
619  /*
620  * Calculate the new list of index columns including both key columns and
621  * INCLUDE columns. Later we can determine which of these are key
622  * columns, and which are just part of the INCLUDE list by checking the
623  * list position. A list item in a position less than ii_NumIndexKeyAttrs
624  * is part of the key columns, and anything equal to and over is part of
625  * the INCLUDE columns.
626  */
627  allIndexParams = list_concat_copy(stmt->indexParams,
628  stmt->indexIncludingParams);
629  numberOfAttributes = list_length(allIndexParams);
630 
631  if (numberOfKeyAttributes <= 0)
632  ereport(ERROR,
633  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
634  errmsg("must specify at least one column")));
635  if (numberOfAttributes > INDEX_MAX_KEYS)
636  ereport(ERROR,
637  (errcode(ERRCODE_TOO_MANY_COLUMNS),
638  errmsg("cannot use more than %d columns in an index",
639  INDEX_MAX_KEYS)));
640