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

Go to the source code of this file.

Functions

void RemoveObjects (DropStmt *stmt)
 
ObjectAddress DefineIndex (Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
 
void ExecReindex (ParseState *pstate, const ReindexStmt *stmt, bool isTopLevel)
 
char * makeObjectName (const char *name1, const char *name2, const char *label)
 
char * ChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid, bool isconstraint)
 
bool CheckIndexCompatible (Oid oldId, const char *accessMethodName, const List *attributeList, const List *exclusionOpNames, bool isWithoutOverlaps)
 
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
 
Oid ResolveOpClass (const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId)
 
void GetOperatorFromWellKnownStrategy (Oid opclass, Oid rhstype, Oid *opid, StrategyNumber *strat)
 
ObjectAddress CreateFunction (ParseState *pstate, CreateFunctionStmt *stmt)
 
void RemoveFunctionById (Oid funcOid)
 
ObjectAddress AlterFunction (ParseState *pstate, AlterFunctionStmt *stmt)
 
ObjectAddress CreateCast (CreateCastStmt *stmt)
 
ObjectAddress CreateTransform (CreateTransformStmt *stmt)
 
void IsThereFunctionInNamespace (const char *proname, int pronargs, oidvector *proargtypes, Oid nspOid)
 
void ExecuteDoStmt (ParseState *pstate, DoStmt *stmt, bool atomic)
 
void ExecuteCallStmt (CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest)
 
TupleDesc CallStmtResultDesc (CallStmt *stmt)
 
Oid get_transform_oid (Oid type_id, Oid lang_id, bool missing_ok)
 
void interpret_function_parameter_list (ParseState *pstate, List *parameters, Oid languageOid, ObjectType objtype, oidvector **parameterTypes, List **parameterTypes_list, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **inParameterNames_list, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
 
ObjectAddress DefineOperator (List *names, List *parameters)
 
void RemoveOperatorById (Oid operOid)
 
ObjectAddress AlterOperator (AlterOperatorStmt *stmt)
 
ObjectAddress CreateStatistics (CreateStatsStmt *stmt)
 
ObjectAddress AlterStatistics (AlterStatsStmt *stmt)
 
void RemoveStatisticsById (Oid statsOid)
 
void RemoveStatisticsDataById (Oid statsOid, bool inh)
 
Oid StatisticsGetRelation (Oid statId, bool missing_ok)
 
ObjectAddress DefineAggregate (ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters, bool replace)
 
ObjectAddress DefineOpClass (CreateOpClassStmt *stmt)
 
ObjectAddress DefineOpFamily (CreateOpFamilyStmt *stmt)
 
Oid AlterOpFamily (AlterOpFamilyStmt *stmt)
 
void IsThereOpClassInNamespace (const char *opcname, Oid opcmethod, Oid opcnamespace)
 
void IsThereOpFamilyInNamespace (const char *opfname, Oid opfmethod, Oid opfnamespace)
 
Oid get_opclass_oid (Oid amID, List *opclassname, bool missing_ok)
 
Oid get_opfamily_oid (Oid amID, List *opfamilyname, bool missing_ok)
 
ObjectAddress DefineTSParser (List *names, List *parameters)
 
ObjectAddress DefineTSDictionary (List *names, List *parameters)
 
ObjectAddress AlterTSDictionary (AlterTSDictionaryStmt *stmt)
 
ObjectAddress DefineTSTemplate (List *names, List *parameters)
 
ObjectAddress DefineTSConfiguration (List *names, List *parameters, ObjectAddress *copied)
 
void RemoveTSConfigurationById (Oid cfgId)
 
ObjectAddress AlterTSConfiguration (AlterTSConfigurationStmt *stmt)
 
textserialize_deflist (List *deflist)
 
Listdeserialize_deflist (Datum txt)
 
ObjectAddress AlterForeignServerOwner (const char *name, Oid newOwnerId)
 
void AlterForeignServerOwner_oid (Oid, Oid newOwnerId)
 
ObjectAddress AlterForeignDataWrapperOwner (const char *name, Oid newOwnerId)
 
void AlterForeignDataWrapperOwner_oid (Oid fwdId, Oid newOwnerId)
 
ObjectAddress CreateForeignDataWrapper (ParseState *pstate, CreateFdwStmt *stmt)
 
ObjectAddress AlterForeignDataWrapper (ParseState *pstate, AlterFdwStmt *stmt)
 
ObjectAddress CreateForeignServer (CreateForeignServerStmt *stmt)
 
ObjectAddress AlterForeignServer (AlterForeignServerStmt *stmt)
 
ObjectAddress CreateUserMapping (CreateUserMappingStmt *stmt)
 
ObjectAddress AlterUserMapping (AlterUserMappingStmt *stmt)
 
Oid RemoveUserMapping (DropUserMappingStmt *stmt)
 
void CreateForeignTable (CreateForeignTableStmt *stmt, Oid relid)
 
void ImportForeignSchema (ImportForeignSchemaStmt *stmt)
 
Datum transformGenericOptions (Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
 
ObjectAddress CreateAccessMethod (CreateAmStmt *stmt)
 
Oid get_index_am_oid (const char *amname, bool missing_ok)
 
Oid get_table_am_oid (const char *amname, bool missing_ok)
 
Oid get_am_oid (const char *amname, bool missing_ok)
 
char * get_am_name (Oid amOid)
 
char * defGetString (DefElem *def)
 
double defGetNumeric (DefElem *def)
 
bool defGetBoolean (DefElem *def)
 
int32 defGetInt32 (DefElem *def)
 
int64 defGetInt64 (DefElem *def)
 
Oid defGetObjectId (DefElem *def)
 
ListdefGetQualifiedName (DefElem *def)
 
TypeNamedefGetTypeName (DefElem *def)
 
int defGetTypeLength (DefElem *def)
 
ListdefGetStringList (DefElem *def)
 
void errorConflictingDefElem (DefElem *defel, ParseState *pstate) pg_attribute_noreturn()
 

Function Documentation

◆ AlterForeignDataWrapper()

ObjectAddress AlterForeignDataWrapper ( ParseState pstate,
AlterFdwStmt stmt 
)

Definition at line 674 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterForeignDataWrapperOwner()

ObjectAddress AlterForeignDataWrapperOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 275 of file foreigncmds.c.

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

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

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignDataWrapperOwner_oid()

void AlterForeignDataWrapperOwner_oid ( Oid  fwdId,
Oid  newOwnerId 
)

Definition at line 313 of file foreigncmds.c.

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

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

Referenced by shdepReassignOwned().

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)

Definition at line 974 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterForeignServerOwner()

ObjectAddress AlterForeignServerOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 415 of file foreigncmds.c.

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

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

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignServerOwner_oid()

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)

Definition at line 450 of file foreigncmds.c.

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

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

Referenced by shdepReassignOwned().

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)

Definition at line 1342 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterOperator()

ObjectAddress AlterOperator ( AlterOperatorStmt stmt)

Definition at line 462 of file operatorcmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 816 of file opclasscmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)

Definition at line 599 of file statscmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterTSConfiguration()

ObjectAddress AlterTSConfiguration ( AlterTSConfigurationStmt stmt)

Definition at line 1156 of file tsearchcmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterTSDictionary()

ObjectAddress AlterTSDictionary ( AlterTSDictionaryStmt stmt)

Definition at line 493 of file tsearchcmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterUserMapping()

ObjectAddress AlterUserMapping ( AlterUserMappingStmt stmt)

Definition at line 1226 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CallStmtResultDesc()

TupleDesc CallStmtResultDesc ( CallStmt stmt)

Definition at line 2351 of file functioncmds.c.

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

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

Referenced by UtilityTupleDescriptor().

◆ CheckIndexCompatible()

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

Definition at line 177 of file indexcmds.c.

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

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

Referenced by TryReuseIndex().

◆ ChooseRelationName()

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

Definition at line 2615 of file indexcmds.c.

2618 {
2619  int pass = 0;
2620  char *relname = NULL;
2621  char modlabel[NAMEDATALEN];
2622 
2623  /* try the unmodified label first */
2624  strlcpy(modlabel, label, sizeof(modlabel));
2625 
2626  for (;;)
2627  {
2628  relname = makeObjectName(name1, name2, modlabel);
2629 
2630  if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2631  {
2632  if (!isconstraint ||
2633  !ConstraintNameExists(relname, namespaceid))
2634  break;
2635  }
2636 
2637  /* found a conflict, so try a new name component */
2638  pfree(relname);
2639  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2640  }
2641 
2642  return relname;
2643 }
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2529
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1885
static char * label
NameData relname
Definition: pg_class.h:38
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45

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

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

◆ CreateAccessMethod()

ObjectAddress CreateAccessMethod ( CreateAmStmt stmt)

Definition at line 43 of file amcmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateCast()

ObjectAddress CreateCast ( CreateCastStmt stmt)

Definition at line 1520 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignDataWrapper()

ObjectAddress CreateForeignDataWrapper ( ParseState pstate,
CreateFdwStmt stmt 
)

Definition at line 558 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignServer()

ObjectAddress CreateForeignServer ( CreateForeignServerStmt stmt)

Definition at line 838 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignTable()

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1404 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateFunction()

ObjectAddress CreateFunction ( ParseState pstate,
CreateFunctionStmt stmt 
)

Definition at line 1010 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateStatistics()

ObjectAddress CreateStatistics ( CreateStatsStmt stmt)

Definition at line 62 of file statscmds.c.

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

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

Referenced by ATExecAddStatistics(), and ProcessUtilitySlow().

◆ CreateTransform()

ObjectAddress CreateTransform ( CreateTransformStmt stmt)

Definition at line 1800 of file functioncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateUserMapping()

ObjectAddress CreateUserMapping ( CreateUserMappingStmt stmt)

Definition at line 1100 of file foreigncmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ defGetBoolean()

bool defGetBoolean ( DefElem def)

Definition at line 107 of file define.c.

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

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

Referenced by AlterDatabase(), AlterOperator(), 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(), ParseAlterReplSlotOptions(), parseCreateReplSlotOptions(), postgres_fdw_validator(), postgresExecForeignTruncate(), postgresImportForeignSchema(), postgresIsForeignRelUpdatable(), ProcessCopyOptions(), transformExplainStmt(), transformRelOptions(), and UserMappingPasswordRequired().

◆ defGetInt32()

int32 defGetInt32 ( DefElem def)

Definition at line 162 of file define.c.

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

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

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

◆ defGetInt64()

int64 defGetInt64 ( DefElem def)

Definition at line 186 of file define.c.

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

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

Referenced by init_params(), and parse_basebackup_options().

◆ defGetNumeric()

double defGetNumeric ( DefElem def)

Definition at line 81 of file define.c.

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

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

Referenced by AlterFunction(), and compute_function_attributes().

◆ defGetObjectId()

Oid defGetObjectId ( DefElem def)

Definition at line 219 of file define.c.

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

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

Referenced by createdb().

◆ defGetQualifiedName()

List* defGetQualifiedName ( DefElem def)

Definition at line 252 of file define.c.

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

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

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

◆ defGetString()

char* defGetString ( DefElem def)

Definition at line 48 of file define.c.

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

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

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

◆ defGetStringList()

List* defGetStringList ( DefElem def)

Definition at line 356 of file define.c.

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

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

◆ defGetTypeLength()

int defGetTypeLength ( DefElem def)

Definition at line 312 of file define.c.

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

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

Referenced by DefineType().

◆ defGetTypeName()

TypeName* defGetTypeName ( DefElem def)

Definition at line 284 of file define.c.

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

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

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

◆ DefineAggregate()

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

Definition at line 53 of file aggregatecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineIndex()

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

Definition at line 535 of file indexcmds.c.

546 {
547  bool concurrent;
548  char *indexRelationName;
549  char *accessMethodName;
550  Oid *typeIds;
551  Oid *collationIds;
552  Oid *opclassIds;
553  Datum *opclassOptions;
554  Oid accessMethodId;
555  Oid namespaceId;
556  Oid tablespaceId;
557  Oid createdConstraintId = InvalidOid;
558  List *indexColNames;
559  List *allIndexParams;
560  Relation rel;
561  HeapTuple tuple;
562  Form_pg_am accessMethodForm;
563  IndexAmRoutine *amRoutine;
564  bool amcanorder;
565  bool amissummarizing;
566  amoptions_function amoptions;
567  bool exclusion;
568  bool partitioned;
569  bool safe_index;
570  Datum reloptions;
571  int16 *coloptions;
572  IndexInfo *indexInfo;
573  bits16 flags;
574  bits16 constr_flags;
575  int numberOfAttributes;
576  int numberOfKeyAttributes;
577  TransactionId limitXmin;
578  ObjectAddress address;
579  LockRelId heaprelid;
580  LOCKTAG heaplocktag;
581  LOCKMODE lockmode;
582  Snapshot snapshot;
583  Oid root_save_userid;
584  int root_save_sec_context;
585  int root_save_nestlevel;
586 
587  root_save_nestlevel = NewGUCNestLevel();
588 
590 
591  /*
592  * Some callers need us to run with an empty default_tablespace; this is a
593  * necessary hack to be able to reproduce catalog state accurately when
594  * recreating indexes after table-rewriting ALTER TABLE.
595  */
596  if (stmt->reset_default_tblspc)
597  (void) set_config_option("default_tablespace", "",
599  GUC_ACTION_SAVE, true, 0, false);
600 
601  /*
602  * Force non-concurrent build on temporary relations, even if CONCURRENTLY
603  * was requested. Other backends can't access a temporary relation, so
604  * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
605  * is more efficient. Do this before any use of the concurrent option is
606  * done.
607  */
608  if (stmt->concurrent && get_rel_persistence(tableId) != RELPERSISTENCE_TEMP)
609  concurrent = true;
610  else
611  concurrent = false;
612 
613  /*
614  * Start progress report. If we're building a partition, this was already
615  * done.
616  */
617  if (!OidIsValid(parentIndexId))
618  {
621  concurrent ?
624  }
625 
626  /*
627  * No index OID to report yet
628  */
630  InvalidOid);
631 
632  /*
633  * count key attributes in index
634  */
635  numberOfKeyAttributes = list_length(stmt->indexParams);
636 
637  /*
638  * Calculate the new list of index columns including both key columns and
639  * INCLUDE columns. Later we can determine which of these are key
640  * columns, and which are just part of the INCLUDE list by checking the
641  * list position. A list item in a position less than ii_NumIndexKeyAttrs
642  * is part of the key columns, and anything equal to and over is part of
643  * the INCLUDE columns.
644  */
645  allIndexParams = list_concat_copy(stmt->indexParams,
646  stmt->indexIncludingParams);
647  numberOfAttributes = list_length(allIndexParams);
648 
649  if (numberOfKeyAttributes <= 0)
650  ereport(ERROR,
651  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
652  errmsg("must specify at least one column")));
653  if (numberOfAttributes > INDEX_MAX_KEYS)
654  ereport(ERROR,
655  (errcode(ERRCODE_TOO_MANY_COLUMNS),
656  errmsg("cannot use more than %d columns in an index",
657  INDEX_MAX_KEYS)));
658 
659  /*
660  * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
661  * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
662  * (but not VACUUM).
663  *
664  * NB: Caller is responsible for making sure that tableId refers to the
665  * relation on which the index should be built; except in bootstrap mode,
666  * this will typically require the caller to have already locked the
667  * relation. To avoid lock upgrade hazards, that lock should be at least
668  * as strong as the one we take here.
669  *
670  * NB: If the lock strength here ever changes, code that is run by
671  * parallel workers under the control of certain particular ambuild
672  * functions will need to be updated, too.
673  */
674  lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
675  rel = table_open(tableId, lockmode);
676 
677  /*
678  * Switch to the table owner's userid, so that any index functions are run
679  * as that user. Also lock down security-restricted operations. We
680  * already arranged to make GUC variable changes local to this command.
681  */
682  GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context);
683  SetUserIdAndSecContext(rel->rd_rel->relowner,
684  root_save_sec_context | SECURITY_RESTRICTED_OPERATION);
685 
686  namespaceId = RelationGetNamespace(rel);
687 
688  /*
689  * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
690  * temporal PRIMARY KEY/UNIQUE constraint
691  */
692  exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
693 
694  /* Ensure that it makes sense to index this kind of relation */
695  switch (rel->rd_rel->relkind)
696  {
697  case RELKIND_RELATION:
698  case RELKIND_MATVIEW:
699  case RELKIND_PARTITIONED_TABLE:
700  /* OK */
701  break;
702  default:
703  ereport(ERROR,
704  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
705  errmsg("cannot create index on relation \"%s\"",
707  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
708  break;
709  }
710 
711  /*
712  * Establish behavior for partitioned tables, and verify sanity of
713  * parameters.
714  *
715  * We do not build an actual index in this case; we only create a few
716  * catalog entries. The actual indexes are built by recursing for each
717  * partition.
718  */
719  partitioned = rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
720  if (partitioned)
721  {
722  /*
723  * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
724  * the error is thrown also for temporary tables. Seems better to be
725  * consistent, even though we could do it on temporary table because
726  * we're not actually doing it concurrently.
727  */
728  if (stmt->concurrent)
729  ereport(ERROR,
730  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
731  errmsg("cannot create index on partitioned table \"%s\" concurrently",
732  RelationGetRelationName(rel))));
733  }
734 
735  /*
736  * Don't try to CREATE INDEX on temp tables of other backends.
737  */
738  if (RELATION_IS_OTHER_TEMP(rel))
739  ereport(ERROR,
740  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
741  errmsg("cannot create indexes on temporary tables of other sessions")));
742 
743  /*
744  * Unless our caller vouches for having checked this already, insist that
745  * the table not be in use by our own session, either. Otherwise we might
746  * fail to make entries in the new index (for instance, if an INSERT or
747  * UPDATE is in progress and has already made its list of target indexes).
748  */
749  if (check_not_in_use)
750  CheckTableNotInUse(rel, "CREATE INDEX");
751 
752  /*
753  * Verify we (still) have CREATE rights in the rel's namespace.
754  * (Presumably we did when the rel was created, but maybe not anymore.)
755  * Skip check if caller doesn't want it. Also skip check if
756  * bootstrapping, since permissions machinery may not be working yet.
757  */
758  if (check_rights && !IsBootstrapProcessingMode())
759  {
760  AclResult aclresult;
761 
762  aclresult = object_aclcheck(NamespaceRelationId, namespaceId, root_save_userid,
763  ACL_CREATE);
764  if (aclresult != ACLCHECK_OK)
765  aclcheck_error(aclresult, OBJECT_SCHEMA,
766  get_namespace_name(namespaceId));
767  }
768 
769  /*
770  * Select tablespace to use. If not specified, use default tablespace
771  * (which may in turn default to database's default).
772  */
773  if (stmt->tableSpace)
774  {
775  tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
776  if (partitioned && tablespaceId == MyDatabaseTableSpace)
777  ereport(ERROR,
778  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
779  errmsg("cannot specify default tablespace for partitioned relations")));
780  }
781  else
782  {
783  tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
784  partitioned);
785  /* note InvalidOid is OK in this case */
786  }
787 
788  /* Check tablespace permissions */
789  if (check_rights &&
790  OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
791  {
792  AclResult aclresult;
793 
794  aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId, root_save_userid,
795  ACL_CREATE);
796  if (aclresult != ACLCHECK_OK)
798  get_tablespace_name(tablespaceId));
799  }
800 
801  /*
802  * Force shared indexes into the pg_global tablespace. This is a bit of a
803  * hack but seems simpler than marking them in the BKI commands. On the
804  * other hand, if it's not shared, don't allow it to be placed there.
805  */
806  if (rel->rd_rel->relisshared)
807  tablespaceId = GLOBALTABLESPACE_OID;
808  else if (tablespaceId == GLOBALTABLESPACE_OID)
809  ereport(ERROR,
810  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
811  errmsg("only shared relations can be placed in pg_global tablespace")));
812 
813  /*
814  * Choose the index column names.
815  */
816  indexColNames = ChooseIndexColumnNames(allIndexParams);
817 
818  /*
819  * Select name for index if caller didn't specify
820  */
821  indexRelationName = stmt->idxname;
822  if (indexRelationName == NULL)
823  indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
824  namespaceId,
825  indexColNames,
826  stmt->excludeOpNames,
827  stmt->primary,
828  stmt->isconstraint);
829 
830  /*
831  * look up the access method, verify it can handle the requested features
832  */
833  accessMethodName = stmt->accessMethod;
834  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
835  if (!HeapTupleIsValid(tuple))
836  {
837  /*
838  * Hack to provide more-or-less-transparent updating of old RTREE
839  * indexes to GiST: if RTREE is requested and not found, use GIST.
840  */
841  if (strcmp(accessMethodName, "rtree") == 0)
842  {
843  ereport(NOTICE,
844  (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
845  accessMethodName = "gist";
846  tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
847  }
848 
849  if (!HeapTupleIsValid(tuple))
850  ereport(ERROR,
851  (errcode(ERRCODE_UNDEFINED_OBJECT),
852  errmsg("access method \"%s\" does not exist",
853  accessMethodName)));
854  }
855  accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
856  accessMethodId = accessMethodForm->oid;
857  amRoutine = GetIndexAmRoutine(accessMethodForm->amhandler);
858 
860  accessMethodId);
861 
862  if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
863  ereport(ERROR,
864  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
865  errmsg("access method \"%s\" does not support unique indexes",
866  accessMethodName)));
867  if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
868  ereport(ERROR,
869  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
870  errmsg("access method \"%s\" does not support included columns",
871  accessMethodName)));
872  if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
873  ereport(ERROR,
874  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
875  errmsg("access method \"%s\" does not support multicolumn indexes",
876  accessMethodName)));
877  if (exclusion && amRoutine->amgettuple == NULL)
878  ereport(ERROR,
879  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
880  errmsg("access method \"%s\" does not support exclusion constraints",
881  accessMethodName)));
882 
883  amcanorder = amRoutine->amcanorder;
884  amoptions = amRoutine->amoptions;
885  amissummarizing = amRoutine->amsummarizing;
886 
887  pfree(amRoutine);
888  ReleaseSysCache(tuple);
889 
890  /*
891  * Validate predicate, if given
892  */
893  if (stmt->whereClause)
894  CheckPredicate((Expr *) stmt->whereClause);
895 
896  /*
897  * Parse AM-specific options, convert to text array form, validate.
898  */
899  reloptions = transformRelOptions((Datum) 0, stmt->options,
900  NULL, NULL, false, false);
901 
902  (void) index_reloptions(amoptions, reloptions, true);
903 
904  /*
905  * Prepare arguments for index_create, primarily an IndexInfo structure.
906  * Note that predicates must be in implicit-AND format. In a concurrent
907  * build, mark it not-ready-for-inserts.
908  */
909  indexInfo = makeIndexInfo(numberOfAttributes,
910  numberOfKeyAttributes,
911  accessMethodId,
912  NIL, /* expressions, NIL for now */
913  make_ands_implicit((Expr *) stmt->whereClause),
914  stmt->unique,
915  stmt->nulls_not_distinct,
916  !concurrent,
917  concurrent,
918  amissummarizing);
919 
920  typeIds = palloc_array(Oid, numberOfAttributes);
921  collationIds = palloc_array(Oid, numberOfAttributes);
922  opclassIds = palloc_array(Oid, numberOfAttributes);
923  opclassOptions = palloc_array(Datum, numberOfAttributes);
924  coloptions = palloc_array(int16, numberOfAttributes);
925  ComputeIndexAttrs(indexInfo,
926  typeIds, collationIds, opclassIds, opclassOptions,
927  coloptions, allIndexParams,
928  stmt->excludeOpNames, tableId,
929  accessMethodName, accessMethodId,
930  amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
931  root_save_userid, root_save_sec_context,
932  &root_save_nestlevel);
933 
934  /*
935  * Extra checks when creating a PRIMARY KEY index.
936  */
937  if (stmt->primary)
938  index_check_primary_key(rel, indexInfo, is_alter_table, stmt);
939 
940  /*
941  * If this table is partitioned and we're creating a unique index, primary
942  * key, or exclusion constraint, make sure that the partition key is a
943  * subset of the index's columns. Otherwise it would be possible to
944  * violate uniqueness by putting values that ought to be unique in
945  * different partitions.
946  *
947  * We could lift this limitation if we had global indexes, but those have
948  * their own problems, so this is a useful feature combination.
949  */
950  if (partitioned && (stmt->unique || exclusion))
951  {
953  const char *constraint_type;
954  int i;
955 
956  if (stmt->primary)
957  constraint_type = "PRIMARY KEY";
958  else if (stmt->unique)
959  constraint_type = "UNIQUE";
960  else if (stmt->excludeOpNames)
961  constraint_type = "EXCLUDE";
962  else
963  {
964  elog(ERROR, "unknown constraint type");
965  constraint_type = NULL; /* keep compiler quiet */
966  }
967 
968  /*
969  * Verify that all the columns in the partition key appear in the
970  * unique key definition, with the same notion of equality.
971  */
972  for (i = 0; i < key->partnatts; i++)
973  {
974  bool found = false;
975  int eq_strategy;
976  Oid ptkey_eqop;
977  int j;
978 
979  /*
980  * Identify the equality operator associated with this partkey
981  * column. For list and range partitioning, partkeys use btree
982  * operator classes; hash partitioning uses hash operator classes.
983  * (Keep this in sync with ComputePartitionAttrs!)
984  */
985  if (key->strategy == PARTITION_STRATEGY_HASH)
986  eq_strategy = HTEqualStrategyNumber;
987  else
988  eq_strategy = BTEqualStrategyNumber;
989 
990  ptkey_eqop = get_opfamily_member(key->partopfamily[i],
991  key->partopcintype[i],
992  key->partopcintype[i],
993  eq_strategy);
994  if (!OidIsValid(ptkey_eqop))
995  elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
996  eq_strategy, key->partopcintype[i], key->partopcintype[i],
997  key->partopfamily[i]);
998 
999  /*
1000  * We'll need to be able to identify the equality operators
1001  * associated with index columns, too. We know what to do with
1002  * btree opclasses; if there are ever any other index types that
1003  * support unique indexes, this logic will need extension. But if
1004  * we have an exclusion constraint (or a temporal PK), it already
1005  * knows the operators, so we don't have to infer them.
1006  */
1007  if (stmt->unique && !stmt->iswithoutoverlaps && accessMethodId != BTREE_AM_OID)
1008  ereport(ERROR,
1009  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1010  errmsg("cannot match partition key to an index using access method \"%s\"",
1011  accessMethodName)));
1012 
1013  /*
1014  * It may be possible to support UNIQUE constraints when partition
1015  * keys are expressions, but is it worth it? Give up for now.
1016  */
1017  if (key->partattrs[i] == 0)
1018  ereport(ERROR,
1019  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1020  errmsg("unsupported %s constraint with partition key definition",
1021  constraint_type),
1022  errdetail("%s constraints cannot be used when partition keys include expressions.",
1023  constraint_type)));
1024 
1025  /* Search the index column(s) for a match */
1026  for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1027  {
1028  if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1029  {
1030  /*
1031  * Matched the column, now what about the collation and
1032  * equality op?
1033  */
1034  Oid idx_opfamily;
1035  Oid idx_opcintype;
1036 
1037  if (key->partcollation[i] != collationIds[j])
1038  continue;
1039 
1040  if (get_opclass_opfamily_and_input_type(opclassIds[j],
1041  &idx_opfamily,
1042  &idx_opcintype))
1043  {
1044  Oid idx_eqop = InvalidOid;
1045 
1046  if (stmt->unique && !stmt->iswithoutoverlaps)
1047  idx_eqop = get_opfamily_member(idx_opfamily,
1048  idx_opcintype,
1049  idx_opcintype,
1051  else if (exclusion)
1052  idx_eqop = indexInfo->ii_ExclusionOps[j];
1053  Assert(idx_eqop);
1054 
1055  if (ptkey_eqop == idx_eqop)
1056  {
1057  found = true;
1058  break;
1059  }
1060  else if (exclusion)
1061  {
1062  /*
1063  * We found a match, but it's not an equality
1064  * operator. Instead of failing below with an
1065  * error message about a missing column, fail now
1066  * and explain that the operator is wrong.
1067  */
1068  Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1069 
1070  ereport(ERROR,
1071  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1072  errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1073  NameStr(att->attname),
1074  get_opname(indexInfo->ii_ExclusionOps[j]))));
1075  }
1076  }
1077  }
1078  }
1079 
1080  if (!found)
1081  {
1082  Form_pg_attribute att;
1083 
1084  att = TupleDescAttr(RelationGetDescr(rel),
1085  key->partattrs[i] - 1);
1086  ereport(ERROR,
1087  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1088  errmsg("unique constraint on partitioned table must include all partitioning columns"),
1089  errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1090  constraint_type, RelationGetRelationName(rel),
1091  NameStr(att->attname))));
1092  }
1093  }
1094  }
1095 
1096 
1097  /*
1098  * We disallow indexes on system columns. They would not necessarily get
1099  * updated correctly, and they don't seem useful anyway.
1100  */
1101  for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1102  {
1103  AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1104 
1105  if (attno < 0)
1106  ereport(ERROR,
1107  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1108  errmsg("index creation on system columns is not supported")));
1109  }
1110 
1111  /*
1112  * Also check for system columns used in expressions or predicates.
1113  */
1114  if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1115  {
1116  Bitmapset *indexattrs = NULL;
1117 
1118  pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1119  pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1120 
1121  for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1122  {
1124  indexattrs))
1125  ereport(ERROR,
1126  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1127  errmsg("index creation on system columns is not supported")));
1128  }
1129  }
1130 
1131  /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1132  safe_index = indexInfo->ii_Expressions == NIL &&
1133  indexInfo->ii_Predicate == NIL;
1134 
1135  /*
1136  * Report index creation if appropriate (delay this till after most of the
1137  * error checks)
1138  */
1139  if (stmt->isconstraint && !quiet)
1140  {
1141  const char *constraint_type;
1142 
1143  if (stmt->primary)
1144  constraint_type = "PRIMARY KEY";
1145  else if (stmt->unique)
1146  constraint_type = "UNIQUE";
1147  else if (stmt->excludeOpNames)
1148  constraint_type = "EXCLUDE";
1149  else
1150  {
1151  elog(ERROR, "unknown constraint type");
1152  constraint_type = NULL; /* keep compiler quiet */
1153  }
1154 
1155  ereport(DEBUG1,
1156  (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1157  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1158  constraint_type,
1159  indexRelationName, RelationGetRelationName(rel))));
1160  }
1161 
1162  /*
1163  * A valid stmt->oldNumber implies that we already have a built form of
1164  * the index. The caller should also decline any index build.
1165  */
1166  Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1167 
1168  /*
1169  * Make the catalog entries for the index, including constraints. This
1170  * step also actually builds the index, except if caller requested not to
1171  * or in concurrent mode, in which case it'll be done later, or doing a
1172  * partitioned index (because those don't have storage).
1173  */
1174  flags = constr_flags = 0;
1175  if (stmt->isconstraint)
1176  flags |= INDEX_CREATE_ADD_CONSTRAINT;
1177  if (skip_build || concurrent || partitioned)
1178  flags |= INDEX_CREATE_SKIP_BUILD;
1179  if (stmt->if_not_exists)
1180  flags |= INDEX_CREATE_IF_NOT_EXISTS;
1181  if (concurrent)
1182  flags |= INDEX_CREATE_CONCURRENT;
1183  if (partitioned)
1184  flags |= INDEX_CREATE_PARTITIONED;
1185  if (stmt->primary)
1186  flags |= INDEX_CREATE_IS_PRIMARY;
1187 
1188  /*
1189  * If the table is partitioned, and recursion was declined but partitions
1190  * exist, mark the index as invalid.
1191  */
1192  if (partitioned && stmt->relation && !stmt->relation->inh)
1193  {
1194  PartitionDesc pd = RelationGetPartitionDesc(rel, true);
1195 
1196  if (pd->nparts != 0)
1197  flags |= INDEX_CREATE_INVALID;
1198  }
1199 
1200  if (stmt->deferrable)
1201  constr_flags |= INDEX_CONSTR_CREATE_DEFERRABLE;
1202  if (stmt->initdeferred)
1203  constr_flags |= INDEX_CONSTR_CREATE_INIT_DEFERRED;
1204  if (stmt->iswithoutoverlaps)
1205  constr_flags |= INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS;
1206 
1207  indexRelationId =
1208  index_create(rel, indexRelationName, indexRelationId, parentIndexId,
1209  parentConstraintId,
1210  stmt->oldNumber, indexInfo, indexColNames,
1211  accessMethodId, tablespaceId,
1212  collationIds, opclassIds, opclassOptions,
1213  coloptions, NULL, reloptions,
1214  flags, constr_flags,
1215  allowSystemTableMods, !check_rights,
1216  &createdConstraintId);
1217 
1218  ObjectAddressSet(address, RelationRelationId, indexRelationId);
1219 
1220  if (!OidIsValid(indexRelationId))
1221  {
1222  /*
1223  * Roll back any GUC changes executed by index functions. Also revert
1224  * to original default_tablespace if we changed it above.
1225  */
1226  AtEOXact_GUC(false, root_save_nestlevel);
1227 
1228  /* Restore userid and security context */
1229  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1230 
1231  table_close(rel, NoLock);
1232 
1233  /* If this is the top-level index, we're done */
1234  if (!OidIsValid(parentIndexId))
1236 
1237  return address;
1238  }
1239 
1240  /*
1241  * Roll back any GUC changes executed by index functions, and keep
1242  * subsequent changes local to this command. This is essential if some
1243  * index function changed a behavior-affecting GUC, e.g. search_path.
1244  */
1245  AtEOXact_GUC(false, root_save_nestlevel);
1246  root_save_nestlevel = NewGUCNestLevel();
1247 
1248  /* Add any requested comment */
1249  if (stmt->idxcomment != NULL)
1250  CreateComments(indexRelationId, RelationRelationId, 0,
1251  stmt->idxcomment);
1252 
1253  if (partitioned)
1254  {
1255  PartitionDesc partdesc;
1256 
1257  /*
1258  * Unless caller specified to skip this step (via ONLY), process each
1259  * partition to make sure they all contain a corresponding index.
1260  *
1261  * If we're called internally (no stmt->relation), recurse always.
1262  */
1263  partdesc = RelationGetPartitionDesc(rel, true);
1264  if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1265  {
1266  int nparts = partdesc->nparts;
1267  Oid *part_oids = palloc_array(Oid, nparts);
1268  bool invalidate_parent = false;
1269  Relation parentIndex;
1270  TupleDesc parentDesc;
1271 
1272  /*
1273  * Report the total number of partitions at the start of the
1274  * command; don't update it when being called recursively.
1275  */
1276  if (!OidIsValid(parentIndexId))
1277  {
1278  /*
1279  * When called by ProcessUtilitySlow, the number of partitions
1280  * is passed in as an optimization; but other callers pass -1
1281  * since they don't have the value handy. This should count
1282  * partitions the same way, ie one less than the number of
1283  * relations find_all_inheritors reports.
1284  *
1285  * We assume we needn't ask find_all_inheritors to take locks,
1286  * because that should have happened already for all callers.
1287  * Even if it did not, this is safe as long as we don't try to
1288  * touch the partitions here; the worst consequence would be a
1289  * bogus progress-reporting total.
1290  */
1291  if (total_parts < 0)
1292  {
1293  List *children = find_all_inheritors(tableId, NoLock, NULL);
1294 
1295  total_parts = list_length(children) - 1;
1296  list_free(children);
1297  }
1298 
1300  total_parts);
1301  }
1302 
1303  /* Make a local copy of partdesc->oids[], just for safety */
1304  memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1305 
1306  /*
1307  * We'll need an IndexInfo describing the parent index. The one
1308  * built above is almost good enough, but not quite, because (for
1309  * example) its predicate expression if any hasn't been through
1310  * expression preprocessing. The most reliable way to get an
1311  * IndexInfo that will match those for child indexes is to build
1312  * it the same way, using BuildIndexInfo().
1313  */
1314  parentIndex = index_open(indexRelationId, lockmode);
1315  indexInfo = BuildIndexInfo(parentIndex);
1316 
1317  parentDesc = RelationGetDescr(rel);
1318 
1319  /*
1320  * For each partition, scan all existing indexes; if one matches
1321  * our index definition and is not already attached to some other
1322  * parent index, attach it to the one we just created.
1323  *
1324  * If none matches, build a new index by calling ourselves
1325  * recursively with the same options (except for the index name).
1326  */
1327  for (int i = 0; i < nparts; i++)
1328  {
1329  Oid childRelid = part_oids[i];
1330  Relation childrel;
1331  Oid child_save_userid;
1332  int child_save_sec_context;
1333  int child_save_nestlevel;
1334  List *childidxs;
1335  ListCell *cell;
1336  AttrMap *attmap;
1337  bool found = false;
1338 
1339  childrel = table_open(childRelid, lockmode);
1340 
1341  GetUserIdAndSecContext(&child_save_userid,
1342  &child_save_sec_context);
1343  SetUserIdAndSecContext(childrel->rd_rel->relowner,
1344  child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
1345  child_save_nestlevel = NewGUCNestLevel();
1347 
1348  /*
1349  * Don't try to create indexes on foreign tables, though. Skip
1350  * those if a regular index, or fail if trying to create a
1351  * constraint index.
1352  */
1353  if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1354  {
1355  if (stmt->unique || stmt->primary)
1356  ereport(ERROR,
1357  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1358  errmsg("cannot create unique index on partitioned table \"%s\"",
1360  errdetail("Table \"%s\" contains partitions that are foreign tables.",
1361  RelationGetRelationName(rel))));
1362 
1363  AtEOXact_GUC(false, child_save_nestlevel);
1364  SetUserIdAndSecContext(child_save_userid,
1365  child_save_sec_context);
1366  table_close(childrel, lockmode);
1367  continue;
1368  }
1369 
1370  childidxs = RelationGetIndexList(childrel);
1371  attmap =
1373  parentDesc,
1374  false);
1375 
1376  foreach(cell, childidxs)
1377  {
1378  Oid cldidxid = lfirst_oid(cell);
1379  Relation cldidx;
1380  IndexInfo *cldIdxInfo;
1381 
1382  /* this index is already partition of another one */
1383  if (has_superclass(cldidxid))
1384  continue;
1385 
1386  cldidx = index_open(cldidxid, lockmode);
1387  cldIdxInfo = BuildIndexInfo(cldidx);
1388  if (CompareIndexInfo(cldIdxInfo, indexInfo,
1389  cldidx->rd_indcollation,
1390  parentIndex->rd_indcollation,
1391  cldidx->rd_opfamily,
1392  parentIndex->rd_opfamily,
1393  attmap))
1394  {
1395  Oid cldConstrOid = InvalidOid;
1396 
1397  /*
1398  * Found a match.
1399  *
1400  * If this index is being created in the parent
1401  * because of a constraint, then the child needs to
1402  * have a constraint also, so look for one. If there
1403  * is no such constraint, this index is no good, so
1404  * keep looking.
1405  */
1406  if (createdConstraintId != InvalidOid)
1407  {
1408  cldConstrOid =
1410  cldidxid);
1411  if (cldConstrOid == InvalidOid)
1412  {
1413  index_close(cldidx, lockmode);
1414  continue;
1415  }
1416  }
1417 
1418  /* Attach index to parent and we're done. */
1419  IndexSetParentIndex(cldidx, indexRelationId);
1420  if (createdConstraintId != InvalidOid)
1421  ConstraintSetParentConstraint(cldConstrOid,
1422  createdConstraintId,
1423  childRelid);
1424 
1425  if (!cldidx->rd_index->indisvalid)
1426  invalidate_parent = true;
1427 
1428  found = true;
1429 
1430  /*
1431  * Report this partition as processed. Note that if
1432  * the partition has children itself, we'd ideally
1433  * count the children and update the progress report
1434  * for all of them; but that seems unduly expensive.
1435  * Instead, the progress report will act like all such
1436  * indirect children were processed in zero time at
1437  * the end of the command.
1438  */
1440 
1441  /* keep lock till commit */
1442  index_close(cldidx, NoLock);
1443  break;
1444  }
1445 
1446  index_close(cldidx, lockmode);
1447  }
1448 
1449  list_free(childidxs);
1450  AtEOXact_GUC(false, child_save_nestlevel);
1451  SetUserIdAndSecContext(child_save_userid,
1452  child_save_sec_context);
1453  table_close(childrel, NoLock);
1454 
1455  /*
1456  * If no matching index was found, create our own.
1457  */
1458  if (!found)
1459  {
1460  IndexStmt *childStmt = copyObject(stmt);
1461  bool found_whole_row;
1462  ListCell *lc;
1463  ObjectAddress childAddr;
1464 
1465  /*
1466  * We can't use the same index name for the child index,
1467  * so clear idxname to let the recursive invocation choose
1468  * a new name. Likewise, the existing target relation
1469  * field is wrong, and if indexOid or oldNumber are set,
1470  * they mustn't be applied to the child either.
1471  */
1472  childStmt->idxname = NULL;
1473  childStmt->relation = NULL;
1474  childStmt->indexOid = InvalidOid;
1475  childStmt->oldNumber = InvalidRelFileNumber;
1478 
1479  /*
1480  * Adjust any Vars (both in expressions and in the index's
1481  * WHERE clause) to match the partition's column numbering
1482  * in case it's different from the parent's.
1483  */
1484  foreach(lc, childStmt->indexParams)
1485  {
1486  IndexElem *ielem = lfirst(lc);
1487 
1488  /*
1489  * If the index parameter is an expression, we must
1490  * translate it to contain child Vars.
1491  */
1492  if (ielem->expr)
1493  {
1494  ielem->expr =
1495  map_variable_attnos((Node *) ielem->expr,
1496  1, 0, attmap,
1497  InvalidOid,
1498  &found_whole_row);
1499  if (found_whole_row)
1500  elog(ERROR, "cannot convert whole-row table reference");
1501  }
1502  }
1503  childStmt->whereClause =
1504  map_variable_attnos(stmt->whereClause, 1, 0,
1505  attmap,
1506  InvalidOid, &found_whole_row);
1507  if (found_whole_row)
1508  elog(ERROR, "cannot convert whole-row table reference");
1509 
1510  /*
1511  * Recurse as the starting user ID. Callee will use that
1512  * for permission checks, then switch again.
1513  */
1514  Assert(GetUserId() == child_save_userid);
1515  SetUserIdAndSecContext(root_save_userid,
1516  root_save_sec_context);
1517  childAddr =
1518  DefineIndex(childRelid, childStmt,
1519  InvalidOid, /* no predefined OID */
1520  indexRelationId, /* this is our child */
1521  createdConstraintId,
1522  -1,
1523  is_alter_table, check_rights,
1524  check_not_in_use,
1525  skip_build, quiet);
1526  SetUserIdAndSecContext(child_save_userid,
1527  child_save_sec_context);
1528 
1529  /*
1530  * Check if the index just created is valid or not, as it
1531  * could be possible that it has been switched as invalid
1532  * when recursing across multiple partition levels.
1533  */
1534  if (!get_index_isvalid(childAddr.objectId))
1535  invalidate_parent = true;
1536  }
1537 
1538  free_attrmap(attmap);
1539  }
1540 
1541  index_close(parentIndex, lockmode);
1542 
1543  /*
1544  * The pg_index row we inserted for this index was marked
1545  * indisvalid=true. But if we attached an existing index that is
1546  * invalid, this is incorrect, so update our row to invalid too.
1547  */
1548  if (invalidate_parent)
1549  {
1550  Relation pg_index = table_open(IndexRelationId, RowExclusiveLock);
1551  HeapTuple tup,
1552  newtup;
1553 
1554  tup = SearchSysCache1(INDEXRELID,
1555  ObjectIdGetDatum(indexRelationId));
1556  if (!HeapTupleIsValid(tup))
1557  elog(ERROR, "cache lookup failed for index %u",
1558  indexRelationId);
1559  newtup = heap_copytuple(tup);
1560  ((Form_pg_index) GETSTRUCT(newtup))->indisvalid = false;
1561  CatalogTupleUpdate(pg_index, &tup->t_self, newtup);
1562  ReleaseSysCache(tup);
1563  table_close(pg_index, RowExclusiveLock);
1564  heap_freetuple(newtup);
1565 
1566  /*
1567  * CCI here to make this update visible, in case this recurses
1568  * across multiple partition levels.
1569  */
1571  }
1572  }
1573 
1574  /*
1575  * Indexes on partitioned tables are not themselves built, so we're
1576  * done here.
1577  */
1578  AtEOXact_GUC(false, root_save_nestlevel);
1579  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1580  table_close(rel, NoLock);
1581  if (!OidIsValid(parentIndexId))
1583  else
1584  {
1585  /* Update progress for an intermediate partitioned index itself */
1587  }
1588 
1589  return address;
1590  }
1591 
1592  AtEOXact_GUC(false, root_save_nestlevel);
1593  SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
1594 
1595  if (!concurrent)
1596  {
1597  /* Close the heap and we're done, in the non-concurrent case */
1598  table_close(rel, NoLock);
1599 
1600  /*
1601  * If this is the top-level index, the command is done overall;
1602  * otherwise, increment progress to report one child index is done.
1603  */
1604  if (!OidIsValid(parentIndexId))
1606  else
1608 
1609  return address;
1610  }
1611 
1612  /* save lockrelid and locktag for below, then close rel */
1613  heaprelid = rel->rd_lockInfo.lockRelId;
1614  SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1615  table_close(rel, NoLock);
1616 
1617  /*
1618  * For a concurrent build, it's important to make the catalog entries
1619  * visible to other transactions before we start to build the index. That
1620  * will prevent them from making incompatible HOT updates. The new index
1621  * will be marked not indisready and not indisvalid, so that no one else
1622  * tries to either insert into it or use it for queries.
1623  *
1624  * We must commit our current transaction so that the index becomes
1625  * visible; then start another. Note that all the data structures we just
1626  * built are lost in the commit. The only data we keep past here are the
1627  * relation IDs.
1628  *
1629  * Before committing, get a session-level lock on the table, to ensure
1630  * that neither it nor the index can be dropped before we finish. This
1631  * cannot block, even if someone else is waiting for access, because we
1632  * already have the same lock within our transaction.
1633  *
1634  * Note: we don't currently bother with a session lock on the index,
1635  * because there are no operations that could change its state while we
1636  * hold lock on the parent table. This might need to change later.
1637  */
1639 
1643 
1644  /* Tell concurrent index builds to ignore us, if index qualifies */
1645  if (safe_index)
1647 
1648  /*
1649  * The index is now visible, so we can report the OID. While on it,
1650  * include the report for the beginning of phase 2.
1651  */
1652  {
1653  const int progress_cols[] = {
1656  };
1657  const int64 progress_vals[] = {
1658  indexRelationId,
1660  };
1661 
1662  pgstat_progress_update_multi_param(2, progress_cols, progress_vals);
1663  }
1664 
1665  /*
1666  * Phase 2 of concurrent index build (see comments for validate_index()
1667  * for an overview of how this works)
1668  *
1669  * Now we must wait until no running transaction could have the table open
1670  * with the old list of indexes. Use ShareLock to consider running
1671  * transactions that hold locks that permit writing to the table. Note we
1672  * do not need to worry about xacts that open the table for writing after
1673  * this point; they will see the new index when they open it.
1674  *
1675  * Note: the reason we use actual lock acquisition here, rather than just
1676  * checking the ProcArray and sleeping, is that deadlock is possible if
1677  * one of the transactions in question is blocked trying to acquire an
1678  * exclusive lock on our table. The lock code will detect deadlock and
1679  * error out properly.
1680  */
1681  WaitForLockers(heaplocktag, ShareLock, true);
1682 
1683  /*
1684  * At this moment we are sure that there are no transactions with the
1685  * table open for write that don't have this new index in their list of
1686  * indexes. We have waited out all the existing transactions and any new
1687  * transaction will have the new index in its list, but the index is still
1688  * marked as "not-ready-for-inserts". The index is consulted while
1689  * deciding HOT-safety though. This arrangement ensures that no new HOT
1690  * chains can be created where the new tuple and the old tuple in the
1691  * chain have different index keys.
1692  *
1693  * We now take a new snapshot, and build the index using all tuples that
1694  * are visible in this snapshot. We can be sure that any HOT updates to
1695  * these tuples will be compatible with the index, since any updates made
1696  * by transactions that didn't know about the index are now committed or
1697  * rolled back. Thus, each visible tuple is either the end of its
1698  * HOT-chain or the extension of the chain is HOT-safe for this index.
1699  */
1700 
1701  /* Set ActiveSnapshot since functions in the indexes may need it */
1703 
1704  /* Perform concurrent build of index */
1705  index_concurrently_build(tableId, indexRelationId);
1706 
1707  /* we can do away with our snapshot */
1709 
1710  /*
1711  * Commit this transaction to make the indisready update visible.
1712  */
1715 
1716  /* Tell concurrent index builds to ignore us, if index qualifies */
1717  if (safe_index)
1719 
1720  /*
1721  * Phase 3 of concurrent index build
1722  *
1723  * We once again wait until no transaction can have the table open with
1724  * the index marked as read-only for updates.
1725  */
1728  WaitForLockers(heaplocktag, ShareLock, true);
1729 
1730  /*
1731  * Now take the "reference snapshot" that will be used by validate_index()
1732  * to filter candidate tuples. Beware! There might still be snapshots in
1733  * use that treat some transaction as in-progress that our reference
1734  * snapshot treats as committed. If such a recently-committed transaction
1735  * deleted tuples in the table, we will not include them in the index; yet
1736  * those transactions which see the deleting one as still-in-progress will
1737  * expect such tuples to be there once we mark the index as valid.
1738  *
1739  * We solve this by waiting for all endangered transactions to exit before
1740  * we mark the index as valid.
1741  *
1742  * We also set ActiveSnapshot to this snap, since functions in indexes may
1743  * need a snapshot.
1744  */
1746  PushActiveSnapshot(snapshot);
1747 
1748  /*
1749  * Scan the index and the heap, insert any missing index entries.
1750  */
1751  validate_index(tableId, indexRelationId, snapshot);
1752 
1753  /*
1754  * Drop the reference snapshot. We must do this before waiting out other
1755  * snapshot holders, else we will deadlock against other processes also
1756  * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1757  * they must wait for. But first, save the snapshot's xmin to use as
1758  * limitXmin for GetCurrentVirtualXIDs().
1759  */
1760  limitXmin = snapshot->xmin;
1761 
1763  UnregisterSnapshot(snapshot);
1764 
1765  /*
1766  * The snapshot subsystem could still contain registered snapshots that
1767  * are holding back our process's advertised xmin; in particular, if
1768  * default_transaction_isolation = serializable, there is a transaction
1769  * snapshot that is still active. The CatalogSnapshot is likewise a
1770  * hazard. To ensure no deadlocks, we must commit and start yet another
1771  * transaction, and do our wait before any snapshot has been taken in it.
1772  */
1775 
1776  /* Tell concurrent index builds to ignore us, if index qualifies */
1777  if (safe_index)
1779 
1780  /* We should now definitely not be advertising any xmin. */
1782 
1783  /*
1784  * The index is now valid in the sense that it contains all currently
1785  * interesting tuples. But since it might not contain tuples deleted just
1786  * before the reference snap was taken, we have to wait out any
1787  * transactions that might have older snapshots.
1788  */
1791  WaitForOlderSnapshots(limitXmin, true);
1792 
1793  /*
1794  * Index can now be marked valid -- update its pg_index entry
1795  */
1797 
1798  /*
1799  * The pg_index update will cause backends (including this one) to update
1800  * relcache entries for the index itself, but we should also send a
1801  * relcache inval on the parent table to force replanning of cached plans.
1802  * Otherwise existing sessions might fail to use the new index where it
1803  * would be useful. (Note that our earlier commits did not create reasons
1804  * to replan; so relcache flush on the index itself was sufficient.)
1805  */
1807 
1808  /*
1809  * Last thing to do is release the session-level lock on the parent table.
1810  */
1812 
1814 
1815  return address;
1816 }
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition: amapi.h:144
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:177
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
Definition: tablespace.c:1143
void pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
void pgstat_progress_incr_param(int index, int64 incr)
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
void pgstat_progress_end_command(void)
@ PROGRESS_COMMAND_CREATE_INDEX
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
uint16 bits16
Definition: c.h:514
#define InvalidSubTransactionId
Definition: c.h:658
uint32 TransactionId
Definition: c.h:652
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define DEBUG1
Definition: elog.h:30
Oid MyDatabaseTableSpace
Definition: globals.c:93
int NewGUCNestLevel(void)
Definition: guc.c:2237
void RestrictSearchPath(void)
Definition: guc.c:2248
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2264
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition: guc.c:3343
@ GUC_ACTION_SAVE
Definition: guc.h:201
@ PGC_S_SESSION
Definition: guc.h:122
@ PGC_USERSET
Definition: guc.h:75
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition: index.c:3294
Oid index_create(Relation heapRelation, const char *indexRelationName, Oid indexRelationId, Oid parentIndexRelid, Oid parentConstraintId, RelFileNumber relFileNumber, IndexInfo *indexInfo, const List *indexColNames, Oid accessMethodId, Oid tableSpaceId, const Oid *collationIds, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition: index.c:724
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition: index.c:3447
bool CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, const Oid *collations1, const Oid *collations2, const Oid *opfamilies1, const Oid *opfamilies2, const AttrMap *attmap)
Definition: index.c:2514
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition: index.c:201
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition: index.c:1481
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2407
#define INDEX_CREATE_IS_PRIMARY
Definition: index.h:61
#define INDEX_CREATE_IF_NOT_EXISTS
Definition: index.h:65
#define INDEX_CREATE_PARTITIONED
Definition: index.h:66
#define INDEX_CREATE_INVALID
Definition: index.h:67
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition: index.h:96
#define INDEX_CREATE_ADD_CONSTRAINT
Definition: index.h:62
#define INDEX_CREATE_SKIP_BUILD
Definition: index.h:63
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition: index.h:92
@ INDEX_CREATE_SET_VALID
Definition: index.h:27
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition: index.h:93
#define INDEX_CREATE_CONCURRENT
Definition: index.h:64
ObjectAddress DefineIndex(Oid tableId, IndexStmt *stmt, Oid indexRelationId, Oid parentIndexId, Oid parentConstraintId, int total_parts, bool is_alter_table, bool check_rights, bool check_not_in_use, bool skip_build, bool quiet)
Definition: indexcmds.c:535
static void set_indexsafe_procflags(void)
Definition: indexcmds.c:4560
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition: indexcmds.c:4396
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition: indexcmds.c:428
static void CheckPredicate(Expr *predicate)
Definition: indexcmds.c:1831
static List * ChooseIndexColumnNames(const List *indexElems)
Definition: indexcmds.c:2740
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition: indexcmds.c:2651
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition: inval.c:1419
int j
Definition: isn.c:74
void list_free(List *list)
Definition: list.c:1546
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:397
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
Definition: lmgr.c:985
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition: lmgr.c:410
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
int LOCKMODE
Definition: lockdefs.h:26
#define ShareLock
Definition: lockdefs.h:40
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:2078
char * get_opname(Oid opno)
Definition: lsyscache.c:1310
bool get_index_isvalid(Oid index_oid)
Definition: lsyscache.c:3578
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:166
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:737
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:315
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
#define copyObject(obj)
Definition: nodes.h:224
@ PARTITION_STRATEGY_HASH
Definition: parsenodes.h:874
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2305
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:51
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:70
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
bool has_superclass(Oid relationId)
Definition: pg_inherits.c:377
#define PROGRESS_CREATEIDX_PARTITIONS_DONE
Definition: progress.h:89
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition: progress.h:93
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition: progress.h:111
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition: progress.h:83
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition: progress.h:99
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition: progress.h:110
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition: progress.h:95
#define PROGRESS_CREATEIDX_PHASE
Definition: progress.h:84
#define PROGRESS_CREATEIDX_INDEX_OID
Definition: progress.h:82
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition: progress.h:88
#define PROGRESS_CREATEIDX_COMMAND
Definition: progress.h:81
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:658
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4760
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Definition: reloptions.c:2054
Datum transformRelOptions(Datum oldOptions, List *defList, const char *namspace, char *validnsps[], bool acceptOidsOff, bool isReset)
Definition: reloptions.c:1156
#define InvalidRelFileNumber
Definition: relpath.h:26
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrMap *attno_map, Oid to_rowtype, bool *found_whole_row)
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
PGPROC * MyProc
Definition: proc.c:66
#define HTEqualStrategyNumber
Definition: stratnum.h:41
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Definition: attmap.h:35
amoptions_function amoptions
Definition: amapi.h:275
amgettuple_function amgettuple
Definition: amapi.h:282
bool amcanunique
Definition: amapi.h:230
bool amcanmulticol
Definition: amapi.h:232
bool amcaninclude
Definition: amapi.h:250
Node * expr
Definition: parsenodes.h:784
int ii_NumIndexAttrs
Definition: execnodes.h:184
int ii_NumIndexKeyAttrs
Definition: execnodes.h:185
List * ii_Expressions
Definition: execnodes.h:187
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition: execnodes.h:186
List * ii_Predicate
Definition: execnodes.h:189
List * indexParams
Definition: parsenodes.h:3366
Oid indexOid
Definition: parsenodes.h:3373
RangeVar * relation
Definition: parsenodes.h:3363
SubTransactionId oldFirstRelfilelocatorSubid
Definition: parsenodes.h:3376
SubTransactionId oldCreateSubid
Definition: parsenodes.h:3375
char * idxname
Definition: parsenodes.h:3362
Node * whereClause
Definition: parsenodes.h:3370
RelFileNumber oldNumber
Definition: parsenodes.h:3374
Definition: lock.h:165
LockRelId lockRelId
Definition: rel.h:46
Definition: rel.h:39
Oid relId
Definition: rel.h:40
Oid dbId
Definition: rel.h:41
TransactionId xmin
Definition: proc.h:173
LockInfoData rd_lockInfo
Definition: rel.h:114
Form_pg_index rd_index
Definition: rel.h:192
Oid * rd_opfamily
Definition: rel.h:207
Oid * rd_indcollation
Definition: rel.h:217
TransactionId xmin
Definition: snapshot.h:157
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition: tablecmds.c:4346
#define InvalidTransactionId
Definition: transam.h:31
void StartTransactionCommand(void)
Definition: xact.c:2995
void CommitTransactionCommand(void)
Definition: xact.c:3093

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, IndexAmRoutine::amcaninclude, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanunique, IndexAmRoutine::amgettuple, IndexAmRoutine::amoptions, IndexAmRoutine::amsummarizing, Assert, AtEOXact_GUC(), bms_is_member(), BTEqualStrategyNumber, build_attrmap_by_name(), BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CheckPredicate(), CheckTableNotInUse(), ChooseIndexColumnNames(), ChooseIndexName(), CommandCounterIncrement(), CommitTransactionCommand(), CompareIndexInfo(), ComputeIndexAttrs(), ConstraintSetParentConstraint(), copyObject, CreateComments(), LockRelId::dbId, DEBUG1, elog, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errmsg(), errmsg_internal(), ERROR, IndexElem::expr, find_all_inheritors(), FirstLowInvalidHeapAttributeNumber, free_attrmap(), get_index_isvalid(), get_namespace_name(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_opname(), get_rel_persistence(), get_relation_idx_constraint_oid(), get_tablespace_name(), get_tablespace_oid(), GetDefaultTablespace(), GetIndexAmRoutine(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), GetUserIdAndSecContext(), GUC_ACTION_SAVE, has_superclass(), heap_copytuple(), heap_freetuple(), HeapTupleIsValid, HTEqualStrategyNumber, i, IndexStmt::idxname, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Expressions, IndexInfo::ii_IndexAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_NumIndexKeyAttrs, IndexInfo::ii_Predicate, index_check_primary_key(), index_close(), index_concurrently_build(), INDEX_CONSTR_CREATE_DEFERRABLE, INDEX_CONSTR_CREATE_INIT_DEFERRED, INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS, index_create(), INDEX_CREATE_ADD_CONSTRAINT, INDEX_CREATE_CONCURRENT, INDEX_CREATE_IF_NOT_EXISTS, INDEX_CREATE_INVALID, INDEX_CREATE_IS_PRIMARY, INDEX_CREATE_PARTITIONED, INDEX_CREATE_SET_VALID, INDEX_CREATE_SKIP_BUILD, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexStmt::indexOid, IndexStmt::indexParams, IndexSetParentIndex(), InvalidOid, InvalidRelFileNumber, InvalidSubTransactionId, InvalidTransactionId, IsBootstrapProcessingMode, j, sort-test::key, lfirst, lfirst_oid, list_concat_copy(), list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeIndexInfo(), map_variable_attnos(), MyDatabaseTableSpace, MyProc, NameStr, NewGUCNestLevel(), NIL, NoLock, NOTICE, PartitionDescData::nparts, object_aclcheck(), OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, PartitionDescData::oids, IndexStmt::oldCreateSubid, IndexStmt::oldFirstRelfilelocatorSubid, IndexStmt::oldNumber, palloc_array, PARTITION_STRATEGY_HASH, pfree(), PGC_S_SESSION, PGC_USERSET, pgstat_progress_end_command(), pgstat_progress_incr_param(), pgstat_progress_start_command(), pgstat_progress_update_multi_param(), pgstat_progress_update_param(), PointerGetDatum(), PopActiveSnapshot(), PROGRESS_COMMAND_CREATE_INDEX, PROGRESS_CREATEIDX_ACCESS_METHOD_OID, PROGRESS_CREATEIDX_COMMAND, PROGRESS_CREATEIDX_COMMAND_CREATE, PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY, PROGRESS_CREATEIDX_INDEX_OID, PROGRESS_CREATEIDX_PARTITIONS_DONE, PROGRESS_CREATEIDX_PARTITIONS_TOTAL, PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_1, PROGRESS_CREATEIDX_PHASE_WAIT_2, PROGRESS_CREATEIDX_PHASE_WAIT_3, pull_varattnos(), PushActiveSnapshot(), RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_lockInfo, RelationData::rd_opfamily, RelationData::rd_rel, RegisterSnapshot(), IndexStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetDescr, RelationGetIndexList(), RelationGetNamespace, RelationGetPartitionDesc(), RelationGetPartitionKey(), RelationGetRelationName, ReleaseSysCache(), RelFileNumberIsValid, LockRelId::relId, RestrictSearchPath(), RowExclusiveLock, SearchSysCache1(), SECURITY_RESTRICTED_OPERATION, set_config_option(), set_indexsafe_procflags(), SET_LOCKTAG_RELATION, SetUserIdAndSecContext(), ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), stmt, HeapTupleData::t_self, table_close(), table_open(), transformRelOptions(), TupleDescAttr, UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), WaitForLockers(), WaitForOlderSnapshots(), IndexStmt::whereClause, PGPROC::xmin, and SnapshotData::xmin.

Referenced by ATExecAddIndex(), AttachPartitionEnsureIndexes(), DefineRelation(), and ProcessUtilitySlow().

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

Definition at line 332 of file opclasscmds.c.

333 {
334  char *opcname; /* name of opclass we're creating */
335  Oid amoid, /* our AM's oid */
336  typeoid, /* indexable datatype oid */
337  storageoid, /* storage datatype oid, if any */
338  namespaceoid, /* namespace to create opclass in */
339  opfamilyoid, /* oid of containing opfamily */
340  opclassoid; /* oid of opclass we create */
341  int maxOpNumber, /* amstrategies value */
342  optsProcNumber, /* amoptsprocnum value */
343  maxProcNumber; /* amsupport value */
344  bool amstorage; /* amstorage flag */
345  List *operators; /* OpFamilyMember list for operators */
346  List *procedures; /* OpFamilyMember list for support procs */
347  ListCell *l;
348  Relation rel;
349  HeapTuple tup;
350  Form_pg_am amform;
351  IndexAmRoutine *amroutine;
352  Datum values[Natts_pg_opclass];
353  bool nulls[Natts_pg_opclass];
354  AclResult aclresult;
355  NameData opcName;
356  ObjectAddress myself,
357  referenced;
358 
359  /* Convert list of names to a name and namespace */
360  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
361  &opcname);
362 
363  /* Check we have creation rights in target namespace */
364  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
365  if (aclresult != ACLCHECK_OK)
366  aclcheck_error(aclresult, OBJECT_SCHEMA,
367  get_namespace_name(namespaceoid));
368 
369  /* Get necessary info about access method */
370  tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
371  if (!HeapTupleIsValid(tup))
372  ereport(ERROR,
373  (errcode(ERRCODE_UNDEFINED_OBJECT),
374  errmsg("access method \"%s\" does not exist",
375  stmt->amname)));
376 
377  amform = (Form_pg_am) GETSTRUCT(tup);
378  amoid = amform->oid;
379  amroutine = GetIndexAmRoutineByAmId(amoid, false);
380  ReleaseSysCache(tup);
381 
382  maxOpNumber = amroutine->amstrategies;
383  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
384  if (maxOpNumber <= 0)
385  maxOpNumber = SHRT_MAX;
386  maxProcNumber = amroutine->amsupport;
387  optsProcNumber = amroutine->amoptsprocnum;
388  amstorage = amroutine->amstorage;
389 
390  /* XXX Should we make any privilege check against the AM? */
391 
392  /*
393  * The question of appropriate permissions for CREATE OPERATOR CLASS is
394  * interesting. Creating an opclass is tantamount to granting public
395  * execute access on the functions involved, since the index machinery
396  * generally does not check access permission before using the functions.
397  * A minimum expectation therefore is that the caller have execute
398  * privilege with grant option. Since we don't have a way to make the
399  * opclass go away if the grant option is revoked, we choose instead to
400  * require ownership of the functions. It's also not entirely clear what
401  * permissions should be required on the datatype, but ownership seems
402  * like a safe choice.
403  *
404  * Currently, we require superuser privileges to create an opclass. This
405  * seems necessary because we have no way to validate that the offered set
406  * of operators and functions are consistent with the AM's expectations.
407  * It would be nice to provide such a check someday, if it can be done
408  * without solving the halting problem :-(
409  *
410  * XXX re-enable NOT_USED code sections below if you remove this test.
411  */
412  if (!superuser())
413  ereport(ERROR,
414  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
415  errmsg("must be superuser to create an operator class")));
416 
417  /* Look up the datatype */
418  typeoid = typenameTypeId(NULL, stmt->datatype);
419 
420 #ifdef NOT_USED
421  /* XXX this is unnecessary given the superuser check above */
422  /* Check we have ownership of the datatype */
423  if (!object_ownercheck(TypeRelationId, typeoid, GetUserId()))
425 #endif
426 
427  /*
428  * Look up the containing operator family, or create one if FAMILY option
429  * was omitted and there's not a match already.
430  */
431  if (stmt->opfamilyname)
432  {
433  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
434  }
435  else
436  {
437  /* Lookup existing family of same name and namespace */
438  tup = SearchSysCache3(OPFAMILYAMNAMENSP,
439  ObjectIdGetDatum(amoid),
440  PointerGetDatum(opcname),
441  ObjectIdGetDatum(namespaceoid));
442  if (HeapTupleIsValid(tup))
443  {
444  opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
445 
446  /*
447  * XXX given the superuser check above, there's no need for an
448  * ownership check here
449  */
450  ReleaseSysCache(tup);
451  }
452  else
453  {
454  CreateOpFamilyStmt *opfstmt;
455  ObjectAddress tmpAddr;
456 
457  opfstmt = makeNode(CreateOpFamilyStmt);
458  opfstmt->opfamilyname = stmt->opclassname;
459  opfstmt->amname = stmt->amname;
460 
461  /*
462  * Create it ... again no need for more permissions ...
463  */
464  tmpAddr = CreateOpFamily(opfstmt, opcname, namespaceoid, amoid);
465  opfamilyoid = tmpAddr.objectId;
466  }
467  }
468 
469  operators = NIL;
470  procedures = NIL;
471 
472  /* Storage datatype is optional */
473  storageoid = InvalidOid;
474 
475  /*
476  * Scan the "items" list to obtain additional info.
477  */
478  foreach(l, stmt->items)
479  {
481  Oid operOid;
482  Oid funcOid;
483  Oid sortfamilyOid;
484  OpFamilyMember *member;
485 
486  switch (item->itemtype)
487  {
489  if (item->number <= 0 || item->number > maxOpNumber)
490  ereport(ERROR,
491  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
492  errmsg("invalid operator number %d,"
493  " must be between 1 and %d",
494  item->number, maxOpNumber)));
495  if (item->name->objargs != NIL)
496  operOid = LookupOperWithArgs(item->name, false);
497  else
498  {
499  /* Default to binary op on input datatype */
500  operOid = LookupOperName(NULL, item->name->objname,
501  typeoid, typeoid,
502  false, -1);
503  }
504 
505  if (item->order_family)
506  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
507  item->order_family,
508  false);
509  else
510  sortfamilyOid = InvalidOid;
511 
512 #ifdef NOT_USED
513  /* XXX this is unnecessary given the superuser check above */
514  /* Caller must own operator and its underlying function */
515  if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
517  get_opname(operOid));
518  funcOid = get_opcode(operOid);
519  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
521  get_func_name(funcOid));
522 #endif
523 
524  /* Save the info */
525  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
526  member->is_func = false;
527  member->object = operOid;
528  member->number = item->number;
529  member->sortfamily = sortfamilyOid;
530  assignOperTypes(member, amoid, typeoid);
531  addFamilyMember(&operators, member);
532  break;
534  if (item->number <= 0 || item->number > maxProcNumber)
535  ereport(ERROR,
536  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
537  errmsg("invalid function number %d,"
538  " must be between 1 and %d",
539  item->number, maxProcNumber)));
540  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
541 #ifdef NOT_USED
542  /* XXX this is unnecessary given the superuser check above */
543  /* Caller must own function */
544  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
546  get_func_name(funcOid));
547 #endif
548  /* Save the info */
549  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
550  member->is_func = true;
551  member->object = funcOid;
552  member->number = item->number;
553 
554  /* allow overriding of the function's actual arg types */
555  if (item->class_args)
557  &member->lefttype, &member->righttype);
558 
559  assignProcTypes(member, amoid, typeoid, optsProcNumber);
560  addFamilyMember(&procedures, member);
561  break;
563  if (OidIsValid(storageoid))
564  ereport(ERROR,
565  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
566  errmsg("storage type specified more than once")));
567  storageoid = typenameTypeId(NULL, item->storedtype);
568 
569 #ifdef NOT_USED
570  /* XXX this is unnecessary given the superuser check above */
571  /* Check we have ownership of the datatype */
572  if (!object_ownercheck(TypeRelationId, storageoid, GetUserId()))
574 #endif
575  break;
576  default:
577  elog(ERROR, "unrecognized item type: %d", item->itemtype);
578  break;
579  }
580  }
581 
582  /*
583  * If storagetype is specified, make sure it's legal.
584  */
585  if (OidIsValid(storageoid))
586  {
587  /* Just drop the spec if same as column datatype */
588  if (storageoid == typeoid)
589  storageoid = InvalidOid;
590  else if (!amstorage)
591  ereport(ERROR,
592  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
593  errmsg("storage type cannot be different from data type for access method \"%s\"",
594  stmt->amname)));
595  }
596 
597  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
598 
599  /*
600  * Make sure there is no existing opclass of this name (this is just to
601  * give a more friendly error message than "duplicate key").
602  */
603  if (SearchSysCacheExists3(CLAAMNAMENSP,
604  ObjectIdGetDatum(amoid),
605  CStringGetDatum(opcname),
606  ObjectIdGetDatum(namespaceoid)))
607  ereport(ERROR,
609  errmsg("operator class \"%s\" for access method \"%s\" already exists",
610  opcname, stmt->amname)));
611 
612  /*
613  * If we are creating a default opclass, check there isn't one already.
614  * (Note we do not restrict this test to visible opclasses; this ensures
615  * that typcache.c can find unique solutions to its questions.)
616  */
617  if (stmt->isDefault)
618  {
619  ScanKeyData skey[1];
620  SysScanDesc scan;
621 
622  ScanKeyInit(&skey[0],
623  Anum_pg_opclass_opcmethod,
624  BTEqualStrategyNumber, F_OIDEQ,
625  ObjectIdGetDatum(amoid));
626 
627  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
628  NULL, 1, skey);
629 
630  while (HeapTupleIsValid(tup = systable_getnext(scan)))
631  {
632  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
633 
634  if (opclass->opcintype == typeoid && opclass->opcdefault)
635  ereport(ERROR,
637  errmsg("could not make operator class \"%s\" be default for type %s",
638  opcname,
639  TypeNameToString(stmt->datatype)),
640  errdetail("Operator class \"%s\" already is the default.",
641  NameStr(opclass->opcname))));
642  }
643 
644  systable_endscan(scan);
645  }
646 
647  /*
648  * Okay, let's create the pg_opclass entry.
649  */
650  memset(values, 0, sizeof(values));
651  memset(nulls, false, sizeof(nulls));
652 
653  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
654  Anum_pg_opclass_oid);
655  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
656  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
657  namestrcpy(&opcName, opcname);
658  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
659  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
660  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
661  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
662  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
663  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
664  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
665 
666  tup = heap_form_tuple(rel->rd_att, values, nulls);
667 
668  CatalogTupleInsert(rel, tup);
669 
670  heap_freetuple(tup);
671 
672  /*
673  * Now that we have the opclass OID, set up default dependency info for
674  * the pg_amop and pg_amproc entries. Historically, CREATE OPERATOR CLASS
675  * has created hard dependencies on the opclass, so that's what we use.
676  */
677  foreach(l, operators)
678  {
679  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
680 
681  op->ref_is_hard = true;
682  op->ref_is_family = false;
683  op->refobjid = opclassoid;
684  }
685  foreach(l, procedures)
686  {
687  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
688 
689  proc->ref_is_hard = true;
690  proc->ref_is_family = false;
691  proc->refobjid = opclassoid;
692  }
693 
694  /*
695  * Let the index AM editorialize on the dependency choices. It could also
696  * do further validation on the operators and functions, if it likes.
697  */
698  if (amroutine->amadjustmembers)
699  amroutine->amadjustmembers(opfamilyoid,
700  opclassoid,
701  operators,
702  procedures);
703 
704  /*
705  * Now add tuples to pg_amop and pg_amproc tying in the operators and
706  * functions. Dependencies on them are inserted, too.
707  */
708  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
709  operators, false);
710  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
711  procedures, false);
712 
713  /* let event triggers know what happened */
714  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
715 
716  /*
717  * Create dependencies for the opclass proper. Note: we do not need a
718  * dependency link to the AM, because that exists through the opfamily.
719  */
720  myself.classId = OperatorClassRelationId;
721  myself.objectId = opclassoid;
722  myself.objectSubId = 0;
723 
724  /* dependency on namespace */
725  referenced.classId = NamespaceRelationId;
726  referenced.objectId = namespaceoid;
727  referenced.objectSubId = 0;
728  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
729 
730  /* dependency on opfamily */
731  referenced.classId = OperatorFamilyRelationId;
732  referenced.objectId = opfamilyoid;
733  referenced.objectSubId = 0;
734  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
735 
736  /* dependency on indexed datatype */
737  referenced.classId = TypeRelationId;
738  referenced.objectId = typeoid;
739  referenced.objectSubId = 0;
740  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
741 
742  /* dependency on storage datatype */
743  if (OidIsValid(storageoid))
744  {
745  referenced.classId = TypeRelationId;
746  referenced.objectId = storageoid;
747  referenced.objectSubId = 0;
748  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
749  }
750 
751  /* dependency on owner */
752  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
753 
754  /* dependency on extension */
755  recordDependencyOnCurrentExtension(&myself, false);
756 
757  /* Post creation hook for new operator class */
758  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
759 
761 
762  return myself;
763 }
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
void * palloc0(Size size)
Definition: mcxt.c:1346
#define makeNode(_type_)
Definition: nodes.h:155
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1136
static ObjectAddress CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:242
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1535
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1428
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1202
static void addFamilyMember(List **list, OpFamilyMember *member)
Definition: opclasscmds.c:1391
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1107
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:99
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:3193
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:3191
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:3192
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
ObjectWithArgs * name
Definition: parsenodes.h:3199
TypeName * storedtype
Definition: parsenodes.h:3205
amadjustmembers_function amadjustmembers
Definition: amapi.h:279
bool amstorage
Definition: amapi.h:240
Oid refobjid
Definition: amapi.h:90
Oid lefttype
Definition: amapi.h:85
bool ref_is_family
Definition: amapi.h:89
Oid righttype
Definition: amapi.h:86
int number
Definition: amapi.h:84
Oid object
Definition: amapi.h:83
bool is_func
Definition: amapi.h:82
bool ref_is_hard
Definition: amapi.h:88
Oid sortfamily
Definition: amapi.h:87
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:240
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:99

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), IndexAmRoutine::amadjustmembers, CreateOpFamilyStmt::amname, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, assignOperTypes(), assignProcTypes(), BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleInsert(), CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, EventTriggerCollectCreateOpClass(), get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetIndexAmRoutineByAmId(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostCreateHook, OpFamilyMember::is_func, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, lfirst_node, LookupFuncWithArgs(), LookupOperName(), LookupOperWithArgs(), makeNode, CreateOpClassItem::name, NameGetDatum(), NameStr, namestrcpy(), NIL, OpFamilyMember::number, CreateOpClassItem::number, ObjectWithArgs::objargs, OpFamilyMember::object, object_aclcheck(), OBJECT_FUNCTION, OBJECT_OPERATOR, object_ownercheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, ObjectWithArgs::objname, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, CreateOpFamilyStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), PointerGetDatum(), processTypesSpec(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, ReleaseSysCache(), OpFamilyMember::righttype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SearchSysCache3(), SearchSysCacheExists3, OpFamilyMember::sortfamily, stmt, CreateOpClassItem::storedtype, storeOperators(), storeProcedures(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

◆ DefineOperator()

ObjectAddress DefineOperator ( List names,
List parameters 
)

Definition at line 67 of file operatorcmds.c.

68 {
69  char *oprName;
70  Oid oprNamespace;
71  AclResult aclresult;
72  bool canMerge = false; /* operator merges */
73  bool canHash = false; /* operator hashes */
74  List *functionName = NIL; /* function for operator */
75  TypeName *typeName1 = NULL; /* first type name */
76  TypeName *typeName2 = NULL; /* second type name */
77  Oid typeId1 = InvalidOid; /* types converted to OID */
78  Oid typeId2 = InvalidOid;
79  Oid rettype;
80  List *commutatorName = NIL; /* optional commutator operator name */
81  List *negatorName = NIL; /* optional negator operator name */
82  List *restrictionName = NIL; /* optional restrict. sel. function */
83  List *joinName = NIL; /* optional join sel. function */
84  Oid functionOid; /* functions converted to OID */
85  Oid restrictionOid;
86  Oid joinOid;
87  Oid typeId[2]; /* to hold left and right arg */
88  int nargs;
89  ListCell *pl;
90 
91  /* Convert list of names to a name and namespace */
92  oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
93 
94  /* Check we have creation rights in target namespace */
95  aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
96  if (aclresult != ACLCHECK_OK)
97  aclcheck_error(aclresult, OBJECT_SCHEMA,
98  get_namespace_name(oprNamespace));
99 
100  /*
101  * loop over the definition list and extract the information we need.
102  */
103  foreach(pl, parameters)
104  {
105  DefElem *defel = (DefElem *) lfirst(pl);
106 
107  if (strcmp(defel->defname, "leftarg") == 0)
108  {
109  typeName1 = defGetTypeName(defel);
110  if (typeName1->setof)
111  ereport(ERROR,
112  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
113  errmsg("SETOF type not allowed for operator argument")));
114  }
115  else if (strcmp(defel->defname, "rightarg") == 0)
116  {
117  typeName2 = defGetTypeName(defel);
118  if (typeName2->setof)
119  ereport(ERROR,
120  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
121  errmsg("SETOF type not allowed for operator argument")));
122  }
123  /* "function" and "procedure" are equivalent here */
124  else if (strcmp(defel->defname, "function") == 0)
125  functionName = defGetQualifiedName(defel);
126  else if (strcmp(defel->defname, "procedure") == 0)
127  functionName = defGetQualifiedName(defel);
128  else if (strcmp(defel->defname, "commutator") == 0)
129  commutatorName = defGetQualifiedName(defel);
130  else if (strcmp(defel->defname, "negator") == 0)
131  negatorName = defGetQualifiedName(defel);
132  else if (strcmp(defel->defname, "restrict") == 0)
133  restrictionName = defGetQualifiedName(defel);
134  else if (strcmp(defel->defname, "join") == 0)
135  joinName = defGetQualifiedName(defel);
136  else if (strcmp(defel->defname, "hashes") == 0)
137  canHash = defGetBoolean(defel);
138  else if (strcmp(defel->defname, "merges") == 0)
139  canMerge = defGetBoolean(defel);
140  /* These obsolete options are taken as meaning canMerge */
141  else if (strcmp(defel->defname, "sort1") == 0)
142  canMerge = true;
143  else if (strcmp(defel->defname, "sort2") == 0)
144  canMerge = true;
145  else if (strcmp(defel->defname, "ltcmp") == 0)
146  canMerge = true;
147  else if (strcmp(defel->defname, "gtcmp") == 0)
148  canMerge = true;
149  else
150  {
151  /* WARNING, not ERROR, for historical backwards-compatibility */
153  (errcode(ERRCODE_SYNTAX_ERROR),
154  errmsg("operator attribute \"%s\" not recognized",
155  defel->defname)));
156  }
157  }
158 
159  /*
160  * make sure we have our required definitions
161  */
162  if (functionName == NIL)
163  ereport(ERROR,
164  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
165  errmsg("operator function must be specified")));
166 
167  /* Transform type names to type OIDs */
168  if (typeName1)
169  typeId1 = typenameTypeId(NULL, typeName1);
170  if (typeName2)
171  typeId2 = typenameTypeId(NULL, typeName2);
172 
173  /*
174  * If only the right argument is missing, the user is likely trying to
175  * create a postfix operator, so give them a hint about why that does not
176  * work. But if both arguments are missing, do not mention postfix
177  * operators, as the user most likely simply neglected to mention the
178  * arguments.
179  */
180  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
181  ereport(ERROR,
182  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
183  errmsg("operator argument types must be specified")));
184  if (!OidIsValid(typeId2))
185  ereport(ERROR,
186  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
187  errmsg("operator right argument type must be specified"),
188  errdetail("Postfix operators are not supported.")));
189 
190  if (typeName1)
191  {
192  aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
193  if (aclresult != ACLCHECK_OK)
194  aclcheck_error_type(aclresult, typeId1);
195  }
196 
197  if (typeName2)
198  {
199  aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
200  if (aclresult != ACLCHECK_OK)
201  aclcheck_error_type(aclresult, typeId2);
202  }
203 
204  /*
205  * Look up the operator's underlying function.
206  */
207  if (!OidIsValid(typeId1))
208  {
209  typeId[0] = typeId2;
210  nargs = 1;
211  }
212  else if (!OidIsValid(typeId2))
213  {
214  typeId[0] = typeId1;
215  nargs = 1;
216  }
217  else
218  {
219  typeId[0] = typeId1;
220  typeId[1] = typeId2;
221  nargs = 2;
222  }
223  functionOid = LookupFuncName(functionName, nargs, typeId, false);
224 
225  /*
226  * We require EXECUTE rights for the function. This isn't strictly
227  * necessary, since EXECUTE will be checked at any attempted use of the
228  * operator, but it seems like a good idea anyway.
229  */
230  aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
231  if (aclresult != ACLCHECK_OK)
232  aclcheck_error(aclresult, OBJECT_FUNCTION,
233  NameListToString(functionName));
234 
235  rettype = get_func_rettype(functionOid);
236  aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
237  if (aclresult != ACLCHECK_OK)
238  aclcheck_error_type(aclresult, rettype);
239 
240  /*
241  * Look up restriction and join estimators if specified
242  */
243  if (restrictionName)
244  restrictionOid = ValidateRestrictionEstimator(restrictionName);
245  else
246  restrictionOid = InvalidOid;
247  if (joinName)
248  joinOid = ValidateJoinEstimator(joinName);
249  else
250  joinOid = InvalidOid;
251 
252  /*
253  * now have OperatorCreate do all the work..
254  */
255  return
256  OperatorCreate(oprName, /* operator name */
257  oprNamespace, /* namespace */
258  typeId1, /* left type id */
259  typeId2, /* right type id */
260  functionOid, /* function for operator */
261  commutatorName, /* optional commutator operator name */
262  negatorName, /* optional negator operator name */
263  restrictionOid, /* optional restrict. sel. function */
264  joinOid, /* optional join sel. function name */
265  canMerge, /* operator merges */
266  canHash); /* operator hashes */
267 }
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2143
ObjectAddress OperatorCreate(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
Definition: pg_operator.c:321
bool setof
Definition: parsenodes.h:270

References ACL_CREATE, ACL_EXECUTE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, get_func_rettype(), get_namespace_name(), GetUserId(), InvalidOid, lfirst, LookupFuncName(), NameListToString(), NIL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_SCHEMA, OidIsValid, OperatorCreate(), QualifiedNameGetCreationNamespace(), TypeName::setof, typenameTypeId(), ValidateJoinEstimator(), ValidateRestrictionEstimator(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

Definition at line 771 of file opclasscmds.c.

772 {
773  char *opfname; /* name of opfamily we're creating */
774  Oid amoid, /* our AM's oid */
775  namespaceoid; /* namespace to create opfamily in */
776  AclResult aclresult;
777 
778  /* Convert list of names to a name and namespace */
779  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
780  &opfname);
781 
782  /* Check we have creation rights in target namespace */
783  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
784  if (aclresult != ACLCHECK_OK)
785  aclcheck_error(aclresult, OBJECT_SCHEMA,
786  get_namespace_name(namespaceoid));
787 
788  /* Get access method OID, throwing an error if it doesn't exist. */
789  amoid = get_index_am_oid(stmt->amname, false);
790 
791  /* XXX Should we make any privilege check against the AM? */
792 
793  /*
794  * Currently, we require superuser privileges to create an opfamily. See
795  * comments in DefineOpClass.
796  */
797  if (!superuser())
798  ereport(ERROR,
799  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
800  errmsg("must be superuser to create an operator family")));
801 
802  /* Insert pg_opfamily catalog entry */
803  return CreateOpFamily(stmt, opfname, namespaceoid, amoid);
804 }
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:163

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_index_am_oid(), get_namespace_name(), GetUserId(), object_aclcheck(), OBJECT_SCHEMA, QualifiedNameGetCreationNamespace(), stmt, and superuser().

Referenced by ProcessUtilitySlow().

◆ DefineTSConfiguration()

ObjectAddress DefineTSConfiguration ( List names,
List parameters,
ObjectAddress copied 
)

Definition at line 899 of file tsearchcmds.c.

900 {
901  Relation cfgRel;
902  Relation mapRel = NULL;
903  HeapTuple tup;
904  Datum values[Natts_pg_ts_config];
905  bool nulls[Natts_pg_ts_config];
906  AclResult aclresult;
907  Oid namespaceoid;
908  char *cfgname;
909  NameData cname;
910  Oid sourceOid = InvalidOid;
911  Oid prsOid = InvalidOid;
912  Oid cfgOid;
913  ListCell *pl;
914  ObjectAddress address;
915 
916  /* Convert list of names to a name and namespace */
917  namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
918 
919  /* Check we have creation rights in target namespace */
920  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
921  if (aclresult != ACLCHECK_OK)
922  aclcheck_error(aclresult, OBJECT_SCHEMA,
923  get_namespace_name(namespaceoid));
924 
925  /*
926  * loop over the definition list and extract the information we need.
927  */
928  foreach(pl, parameters)
929  {
930  DefElem *defel = (DefElem *) lfirst(pl);
931 
932  if (strcmp(defel->defname, "parser") == 0)
933  prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
934  else if (strcmp(defel->defname, "copy") == 0)
935  sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
936  else
937  ereport(ERROR,
938  (errcode(ERRCODE_SYNTAX_ERROR),
939  errmsg("text search configuration parameter \"%s\" not recognized",
940  defel->defname)));
941  }
942 
943  if (OidIsValid(sourceOid) && OidIsValid(prsOid))
944  ereport(ERROR,
945  (errcode(ERRCODE_SYNTAX_ERROR),
946  errmsg("cannot specify both PARSER and COPY options")));
947 
948  /* make copied tsconfig available to callers */
949  if (copied && OidIsValid(sourceOid))
950  {
951  ObjectAddressSet(*copied,
952  TSConfigRelationId,
953  sourceOid);
954  }
955 
956  /*
957  * Look up source config if given.
958  */
959  if (OidIsValid(sourceOid))
960  {
961  Form_pg_ts_config cfg;
962 
963  tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(sourceOid));
964  if (!HeapTupleIsValid(tup))
965  elog(ERROR, "cache lookup failed for text search configuration %u",
966  sourceOid);
967 
968  cfg = (Form_pg_ts_config) GETSTRUCT(tup);
969 
970  /* use source's parser */
971  prsOid = cfg->cfgparser;
972 
973  ReleaseSysCache(tup);
974  }
975 
976  /*
977  * Validation
978  */
979  if (!OidIsValid(prsOid))
980  ereport(ERROR,
981  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
982  errmsg("text search parser is required")));
983 
984  cfgRel = table_open(TSConfigRelationId, RowExclusiveLock);
985 
986  /*
987  * Looks good, build tuple and insert
988  */
989  memset(values, 0, sizeof(values));
990  memset(nulls, false, sizeof(nulls));
991 
992  cfgOid = GetNewOidWithIndex(cfgRel, TSConfigOidIndexId,
993  Anum_pg_ts_config_oid);
994  values[Anum_pg_ts_config_oid - 1] = ObjectIdGetDatum(cfgOid);
995  namestrcpy(&cname, cfgname);
996  values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname);
997  values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid);
998  values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
999  values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);
1000 
1001  tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
1002 
1003  CatalogTupleInsert(cfgRel, tup);
1004 
1005  if (OidIsValid(sourceOid))
1006  {
1007  /*
1008  * Copy token-dicts map from source config
1009  */
1010  ScanKeyData skey;
1011  SysScanDesc scan;
1012  HeapTuple maptup;
1013  TupleDesc mapDesc;
1014  TupleTableSlot **slot;
1015  CatalogIndexState indstate;
1016  int max_slots,
1017  slot_init_count,
1018  slot_stored_count;
1019 
1020  mapRel = table_open(TSConfigMapRelationId, RowExclusiveLock);
1021  mapDesc = RelationGetDescr(mapRel);
1022 
1023  indstate = CatalogOpenIndexes(mapRel);
1024 
1025  /*
1026  * Allocate the slots to use, but delay costly initialization until we
1027  * know that they will be used.
1028  */
1030  slot = palloc(sizeof(TupleTableSlot *) * max_slots);
1031 
1032  ScanKeyInit(&skey,
1033  Anum_pg_ts_config_map_mapcfg,
1034  BTEqualStrategyNumber, F_OIDEQ,
1035  ObjectIdGetDatum(sourceOid));
1036 
1037  scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
1038  NULL, 1, &skey);
1039 
1040  /* number of slots currently storing tuples */
1041  slot_stored_count = 0;
1042  /* number of slots currently initialized */
1043  slot_init_count = 0;
1044 
1045  while (HeapTupleIsValid((maptup = systable_getnext(scan))))
1046  {
1048 
1049  if (slot_init_count < max_slots)
1050  {
1051  slot[slot_stored_count] = MakeSingleTupleTableSlot(mapDesc,
1052  &TTSOpsHeapTuple);
1053  slot_init_count++;
1054  }
1055 
1056  ExecClearTuple(slot[slot_stored_count]);
1057 
1058  memset(slot[slot_stored_count]->tts_isnull, false,
1059  slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
1060 
1061  slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
1062  slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
1063  slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
1064  slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
1065 
1066  ExecStoreVirtualTuple(slot[slot_stored_count]);
1067  slot_stored_count++;
1068 
1069  /* If slots are full, insert a batch of tuples */
1070  if (slot_stored_count == max_slots)
1071  {
1072  CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
1073  indstate);
1074  slot_stored_count = 0;
1075  }
1076  }
1077 
1078  /* Insert any tuples left in the buffer */
1079  if (slot_stored_count > 0)
1080  CatalogTuplesMultiInsertWithInfo(mapRel, slot, slot_stored_count,
1081  indstate);
1082 
1083  for (int i = 0; i < slot_init_count; i++)
1085 
1086  systable_endscan(scan);
1087  CatalogCloseIndexes(indstate);
1088  }
1089 
1090  address = makeConfigurationDependencies(tup, false, mapRel);
1091 
1092  /* Post creation hook for new text search configuration */
1093  InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
1094 
1095  heap_freetuple(tup);
1096 
1097  if (mapRel)
1098  table_close(mapRel, RowExclusiveLock);
1099  table_close(cfgRel, RowExclusiveLock);
1100 
1101  return address;
1102 }
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
Oid get_ts_parser_oid(List *names, bool missing_ok)
Definition: namespace.c:2701
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:3137
FormData_pg_ts_config_map * Form_pg_ts_config_map
FormData_pg_ts_config_map
Datum * tts_values
Definition: tuptable.h:125
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, BTEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleInsert(), CatalogTuplesMultiInsertWithInfo(), defGetQualifiedName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), FormData_pg_ts_config_map, get_namespace_name(), get_ts_config_oid(), get_ts_parser_oid(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostCreateHook, lfirst, makeConfigurationDependencies(), MakeSingleTupleTableSlot(), MAX_CATALOG_MULTI_INSERT_BYTES, NameGetDatum(), namestrcpy(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, palloc(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TupleTableSlot::tts_values, TTSOpsHeapTuple, and values.

Referenced by ProcessUtilitySlow().

◆ DefineTSDictionary()

ObjectAddress DefineTSDictionary ( List names,
List parameters 
)

Definition at line 397 of file tsearchcmds.c.

398 {
399  ListCell *pl;
400  Relation dictRel;
401  HeapTuple tup;
402  Datum values[Natts_pg_ts_dict];
403  bool nulls[Natts_pg_ts_dict];
404  NameData dname;
405  Oid templId = InvalidOid;
406  List *dictoptions = NIL;
407  Oid dictOid;
408  Oid namespaceoid;
409  AclResult aclresult;
410  char *dictname;
411  ObjectAddress address;
412 
413  /* Convert list of names to a name and namespace */
414  namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);
415 
416  /* Check we have creation rights in target namespace */
417  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
418  if (aclresult != ACLCHECK_OK)
419  aclcheck_error(aclresult, OBJECT_SCHEMA,
420  get_namespace_name(namespaceoid));
421 
422  /*
423  * loop over the definition list and extract the information we need.
424  */
425  foreach(pl, parameters)
426  {
427  DefElem *defel = (DefElem *) lfirst(pl);
428 
429  if (strcmp(defel->defname, "template") == 0)
430  {
431  templId = get_ts_template_oid(defGetQualifiedName(defel), false);
432  }
433  else
434  {
435  /* Assume it's an option for the dictionary itself */
436  dictoptions = lappend(dictoptions, defel);
437  }
438  }
439 
440  /*
441  * Validation
442  */
443  if (!OidIsValid(templId))
444  ereport(ERROR,
445  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
446  errmsg("text search template is required")));
447 
448  verify_dictoptions(templId, dictoptions);
449 
450 
451  dictRel = table_open(TSDictionaryRelationId, RowExclusiveLock);
452 
453  /*
454  * Looks good, insert
455  */
456  memset(values, 0, sizeof(values));
457  memset(nulls, false, sizeof(nulls));
458 
459  dictOid = GetNewOidWithIndex(dictRel, TSDictionaryOidIndexId,
460  Anum_pg_ts_dict_oid);
461  values[Anum_pg_ts_dict_oid - 1] = ObjectIdGetDatum(dictOid);
462  namestrcpy(&dname, dictname);
463  values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
464  values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
465  values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
466  values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
467  if (dictoptions)
468  values[Anum_pg_ts_dict_dictinitoption - 1] =
469  PointerGetDatum(serialize_deflist(dictoptions));
470  else
471  nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;
472 
473  tup = heap_form_tuple(dictRel->rd_att, values, nulls);
474 
475  CatalogTupleInsert(dictRel, tup);
476 
477  address = makeDictionaryDependencies(tup);
478 
479  /* Post creation hook for new text search dictionary */
480  InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
481 
482  heap_freetuple(tup);
483 
484  table_close(dictRel, RowExclusiveLock);
485 
486  return address;
487 }
Oid get_ts_template_oid(List *names, bool missing_ok)
Definition: namespace.c:2992
static ObjectAddress makeDictionaryDependencies(HeapTuple tuple)
Definition: tsearchcmds.c:307

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), defGetQualifiedName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_template_oid(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvalidOid, InvokeObjectPostCreateHook, lappend(), lfirst, makeDictionaryDependencies(), NameGetDatum(), namestrcpy(), NIL, object_aclcheck(), OBJECT_SCHEMA, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, serialize_deflist(), table_close(), table_open(), values, and verify_dictoptions().

Referenced by ProcessUtilitySlow().

◆ DefineTSParser()

ObjectAddress DefineTSParser ( List names,
List parameters 
)

Definition at line 184 of file tsearchcmds.c.

185 {
186  char *prsname;
187  ListCell *pl;
188  Relation prsRel;
189  HeapTuple tup;
190  Datum values[Natts_pg_ts_parser];
191  bool nulls[Natts_pg_ts_parser];
192  NameData pname;
193  Oid prsOid;
194  Oid namespaceoid;
195  ObjectAddress address;
196 
197  if (!superuser())
198  ereport(ERROR,
199  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200  errmsg("must be superuser to create text search parsers")));
201 
202  prsRel = table_open(TSParserRelationId, RowExclusiveLock);
203 
204  /* Convert list of names to a name and namespace */
205  namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);
206 
207  /* initialize tuple fields with name/namespace */
208  memset(values, 0, sizeof(values));
209  memset(nulls, false, sizeof(nulls));
210 
211  prsOid = GetNewOidWithIndex(prsRel, TSParserOidIndexId,
212  Anum_pg_ts_parser_oid);
213  values[Anum_pg_ts_parser_oid - 1] = ObjectIdGetDatum(prsOid);
214  namestrcpy(&pname, prsname);
215  values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
216  values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);
217 
218  /*
219  * loop over the definition list and extract the information we need.
220  */
221  foreach(pl, parameters)
222  {
223  DefElem *defel = (DefElem *) lfirst(pl);
224 
225  if (strcmp(defel->defname, "start") == 0)
226  {
227  values[Anum_pg_ts_parser_prsstart - 1] =
228  get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
229  }
230  else if (strcmp(defel->defname, "gettoken") == 0)
231  {
232  values[Anum_pg_ts_parser_prstoken - 1] =
233  get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
234  }
235  else if (strcmp(defel->defname, "end") == 0)
236  {
237  values[Anum_pg_ts_parser_prsend - 1] =
238  get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
239  }
240  else if (strcmp(defel->defname, "headline") == 0)
241  {
242  values[Anum_pg_ts_parser_prsheadline - 1] =
243  get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
244  }
245  else if (strcmp(defel->defname, "lextypes") == 0)
246  {
247  values[Anum_pg_ts_parser_prslextype - 1] =
248  get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
249  }
250  else
251  ereport(ERROR,
252  (errcode(ERRCODE_SYNTAX_ERROR),
253  errmsg("text search parser parameter \"%s\" not recognized",
254  defel->defname)));
255  }
256 
257  /*
258  * Validation
259  */
260  if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1])))
261  ereport(ERROR,
262  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
263  errmsg("text search parser start method is required")));
264 
265  if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1])))
266  ereport(ERROR,
267  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
268  errmsg("text search parser gettoken method is required")));
269 
270  if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1])))
271  ereport(ERROR,
272  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273  errmsg("text search parser end method is required")));
274 
275  if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])))
276  ereport(ERROR,
277  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
278  errmsg("text search parser lextypes method is required")));
279 
280  /*
281  * Looks good, insert
282  */
283  tup = heap_form_tuple(prsRel->rd_att, values, nulls);
284 
285  CatalogTupleInsert(prsRel, tup);
286 
287  address = makeParserDependencies(tup);
288 
289  /* Post creation hook for new text search parser */
290  InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
291 
292  heap_freetuple(tup);
293 
294  table_close(prsRel, RowExclusiveLock);
295 
296  return address;
297 }
static Datum get_ts_parser_func(DefElem *defel, int attnum)
Definition: tsearchcmds.c:74
static ObjectAddress makeParserDependencies(HeapTuple tuple)
Definition: tsearchcmds.c:137

References CatalogTupleInsert(), DatumGetObjectId(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_parser_func(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, lfirst, makeParserDependencies(), NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), OidIsValid, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, superuser(), table_close(), table_open(), and values.

Referenced by ProcessUtilitySlow().

◆ DefineTSTemplate()

ObjectAddress DefineTSTemplate ( List names,
List parameters 
)

Definition at line 690 of file tsearchcmds.c.

691 {
692  ListCell *pl;
693  Relation tmplRel;
694  HeapTuple tup;
695  Datum values[Natts_pg_ts_template];
696  bool nulls[Natts_pg_ts_template];
697  NameData dname;
698  int i;
699  Oid tmplOid;
700  Oid namespaceoid;
701  char *tmplname;
702  ObjectAddress address;
703 
704  if (!superuser())
705  ereport(ERROR,
706  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
707  errmsg("must be superuser to create text search templates")));
708 
709  /* Convert list of names to a name and namespace */
710  namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);
711 
712  tmplRel = table_open(TSTemplateRelationId, RowExclusiveLock);
713 
714  for (i = 0; i < Natts_pg_ts_template; i++)
715  {
716  nulls[i] = false;
718  }
719 
720  tmplOid = GetNewOidWithIndex(tmplRel, TSTemplateOidIndexId,
721  Anum_pg_ts_dict_oid);
722  values[Anum_pg_ts_template_oid - 1] = ObjectIdGetDatum(tmplOid);
723  namestrcpy(&dname, tmplname);
724  values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
725  values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);
726 
727  /*
728  * loop over the definition list and extract the information we need.
729  */
730  foreach(pl, parameters)
731  {
732  DefElem *defel = (DefElem *) lfirst(pl);
733 
734  if (strcmp(defel->defname, "init") == 0)
735  {
736  values[Anum_pg_ts_template_tmplinit - 1] =
737  get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
738  nulls[Anum_pg_ts_template_tmplinit - 1] = false;
739  }
740  else if (strcmp(defel->defname, "lexize") == 0)
741  {
742  values[Anum_pg_ts_template_tmpllexize - 1] =
743  get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
744  nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
745  }
746  else
747  ereport(ERROR,
748  (errcode(ERRCODE_SYNTAX_ERROR),
749  errmsg("text search template parameter \"%s\" not recognized",
750  defel->defname)));
751  }
752 
753  /*
754  * Validation
755  */
756  if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])))
757  ereport(ERROR,
758  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
759  errmsg("text search template lexize method is required")));
760 
761  /*
762  * Looks good, insert
763  */
764  tup = heap_form_tuple(tmplRel->rd_att, values, nulls);
765 
766  CatalogTupleInsert(tmplRel, tup);
767 
768  address = makeTSTemplateDependencies(tup);
769 
770  /* Post creation hook for new text search template */
771  InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);
772 
773  heap_freetuple(tup);
774 
775  table_close(tmplRel, RowExclusiveLock);
776 
777  return address;
778 }
static ObjectAddress makeTSTemplateDependencies(HeapTuple tuple)
Definition: tsearchcmds.c:652
static Datum get_ts_template_func(DefElem *defel, int attnum)
Definition: tsearchcmds.c:609

References CatalogTupleInsert(), DatumGetObjectId(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_template_func(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), i, InvalidOid, InvokeObjectPostCreateHook, lfirst, makeTSTemplateDependencies(), NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), OidIsValid, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, superuser(), table_close(), table_open(), and values.

Referenced by ProcessUtilitySlow().

◆ deserialize_deflist()

List* deserialize_deflist ( Datum  txt)

Definition at line 1621 of file tsearchcmds.c.

1622 {
1623  text *in = DatumGetTextPP(txt); /* in case it's toasted */
1624  List *result = NIL;
1625  int len = VARSIZE_ANY_EXHDR(in);
1626  char *ptr,
1627  *endptr,
1628  *workspace,
1629  *wsptr = NULL,
1630  *startvalue = NULL;
1631  typedef enum
1632  {
1633  CS_WAITKEY,
1634  CS_INKEY,
1635  CS_INQKEY,
1636  CS_WAITEQ,
1637  CS_WAITVALUE,
1638  CS_INSQVALUE,
1639  CS_INDQVALUE,
1640  CS_INWVALUE
1641  } ds_state;
1642  ds_state state = CS_WAITKEY;
1643 
1644  workspace = (char *) palloc(len + 1); /* certainly enough room */
1645  ptr = VARDATA_ANY(in);
1646  endptr = ptr + len;
1647  for (; ptr < endptr; ptr++)
1648  {
1649  switch (state)
1650  {
1651  case CS_WAITKEY:
1652  if (isspace((unsigned char) *ptr) || *ptr == ',')
1653  continue;
1654  if (*ptr == '"')
1655  {
1656  wsptr = workspace;
1657  state = CS_INQKEY;
1658  }
1659  else
1660  {
1661  wsptr = workspace;
1662  *wsptr++ = *ptr;
1663  state = CS_INKEY;
1664  }
1665  break;
1666  case CS_INKEY:
1667  if (isspace((unsigned char) *ptr))
1668  {
1669  *wsptr++ = '\0';
1670  state = CS_WAITEQ;
1671  }
1672  else if (*ptr == '=')
1673  {
1674  *wsptr++ = '\0';
1675  state = CS_WAITVALUE;
1676  }
1677  else
1678  {
1679  *wsptr++ = *ptr;
1680  }
1681  break;
1682  case CS_INQKEY:
1683  if (*ptr == '"')
1684  {
1685  if (ptr + 1 < endptr && ptr[1] == '"')
1686  {
1687  /* copy only one of the two quotes */
1688  *wsptr++ = *ptr++;
1689  }
1690  else
1691  {
1692  *wsptr++ = '\0';
1693  state = CS_WAITEQ;
1694  }
1695  }
1696  else
1697  {
1698  *wsptr++ = *ptr;
1699  }
1700  break;
1701  case CS_WAITEQ:
1702  if (*ptr == '=')
1703  state = CS_WAITVALUE;
1704  else if (!isspace((unsigned char) *ptr))
1705  ereport(ERROR,
1706  (errcode(ERRCODE_SYNTAX_ERROR),
1707  errmsg("invalid parameter list format: \"%s\"",
1708  text_to_cstring(in))));
1709  break;
1710  case CS_WAITVALUE:
1711  if (*ptr == '\'')
1712  {
1713  startvalue = wsptr;
1714  state = CS_INSQVALUE;
1715  }
1716  else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
1717  {
1718  ptr++;
1719  startvalue = wsptr;
1720  state = CS_INSQVALUE;
1721  }
1722  else if (*ptr == '"')
1723  {
1724  startvalue = wsptr;
1725  state = CS_INDQVALUE;
1726  }
1727  else if (!isspace((unsigned char) *ptr))
1728  {
1729  startvalue = wsptr;
1730  *wsptr++ = *ptr;
1731  state = CS_INWVALUE;
1732  }
1733  break;
1734  case CS_INSQVALUE:
1735  if (*ptr == '\'')
1736  {
1737  if (ptr + 1 < endptr && ptr[1] == '\'')
1738  {
1739  /* copy only one of the two quotes */
1740  *wsptr++ = *ptr++;
1741  }
1742  else
1743  {
1744  *wsptr++ = '\0';
1745  result = lappend(result,
1746  buildDefItem(workspace,
1747  startvalue,
1748  true));
1749  state = CS_WAITKEY;
1750  }
1751  }
1752  else if (*ptr == '\\')
1753  {
1754  if (ptr + 1 < endptr && ptr[1] == '\\')
1755  {
1756  /* copy only one of the two backslashes */
1757  *wsptr++ = *ptr++;
1758  }
1759  else
1760  *wsptr++ = *ptr;
1761  }
1762  else
1763  {
1764  *wsptr++ = *ptr;
1765  }
1766  break;
1767  case CS_INDQVALUE:
1768  if (*ptr == '"')
1769  {
1770  if (ptr + 1 < endptr && ptr[1] == '"')
1771  {
1772  /* copy only one of the two quotes */
1773  *wsptr++ = *ptr++;
1774  }
1775  else
1776  {
1777  *wsptr++ = '\0';
1778  result = lappend(result,
1779  buildDefItem(workspace,
1780  startvalue,
1781  true));
1782  state = CS_WAITKEY;
1783  }
1784  }
1785  else
1786  {
1787  *wsptr++ = *ptr;
1788  }
1789  break;
1790  case CS_INWVALUE:
1791  if (*ptr == ',' || isspace((unsigned char) *ptr))
1792  {
1793  *wsptr++ = '\0';
1794  result = lappend(result,
1795  buildDefItem(workspace,
1796  startvalue,
1797  false));
1798  state = CS_WAITKEY;
1799  }
1800  else
1801  {
1802  *wsptr++ = *ptr;
1803  }
1804  break;
1805  default:
1806  elog(ERROR, "unrecognized deserialize_deflist state: %d",
1807  state);
1808  }
1809  }
1810 
1811  if (state == CS_INWVALUE)
1812  {
1813  *wsptr++ = '\0';
1814  result = lappend(result,
1815  buildDefItem(workspace,
1816  startvalue,
1817  false));
1818  }
1819  else if (state != CS_WAITKEY)
1820  ereport(ERROR,
1821  (errcode(ERRCODE_SYNTAX_ERROR),
1822  errmsg("invalid parameter list format: \"%s\"",
1823  text_to_cstring(in))));
1824 
1825  pfree(workspace);
1826 
1827  return result;
1828 }
#define DatumGetTextPP(X)
Definition: fmgr.h:292
const void size_t len
Definition: regguts.h:323
Definition: c.h:687
static DefElem * buildDefItem(const char *name, const char *val, bool was_quoted)
Definition: tsearchcmds.c:1834
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References buildDefItem(), DatumGetTextPP, elog, ereport, errcode(), errmsg(), ERROR, lappend(), len, NIL, palloc(), pfree(), text_to_cstring(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by AlterTSDictionary(), lookup_ts_dictionary_cache(), ts_headline_byid_opt(), ts_headline_json_byid_opt(), and ts_headline_jsonb_byid_opt().

◆ errorConflictingDefElem()

void errorConflictingDefElem ( DefElem defel,
ParseState pstate 
)

◆ ExecReindex()

void ExecReindex ( ParseState pstate,
const ReindexStmt stmt,
bool  isTopLevel 
)

Definition at line 2801 of file indexcmds.c.

2802 {
2803  ReindexParams params = {0};
2804  ListCell *lc;
2805  bool concurrently = false;
2806  bool verbose = false;
2807  char *tablespacename = NULL;
2808 
2809  /* Parse option list */
2810  foreach(lc, stmt->params)
2811  {
2812  DefElem *opt = (DefElem *) lfirst(lc);
2813 
2814  if (strcmp(opt->defname, "verbose") == 0)
2815  verbose = defGetBoolean(opt);
2816  else if (strcmp(opt->defname, "concurrently") == 0)
2817  concurrently = defGetBoolean(opt);
2818  else if (strcmp(opt->defname, "tablespace") == 0)
2819  tablespacename = defGetString(opt);
2820  else
2821  ereport(ERROR,
2822  (errcode(ERRCODE_SYNTAX_ERROR),
2823  errmsg("unrecognized REINDEX option \"%s\"",
2824  opt->defname),
2825  parser_errposition(pstate, opt->location)));
2826  }
2827 
2828  if (concurrently)
2829  PreventInTransactionBlock(isTopLevel,
2830  "REINDEX CONCURRENTLY");
2831 
2832  params.options =
2833  (verbose ? REINDEXOPT_VERBOSE : 0) |
2834  (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
2835 
2836  /*
2837  * Assign the tablespace OID to move indexes to, with InvalidOid to do
2838  * nothing.
2839  */
2840  if (tablespacename != NULL)
2841  {
2842  params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2843 
2844  /* Check permissions except when moving to database's default */
2845  if (OidIsValid(params.tablespaceOid) &&
2847  {
2848  AclResult aclresult;
2849 
2850  aclresult = object_aclcheck(TableSpaceRelationId, params.tablespaceOid,
2851  GetUserId(), ACL_CREATE);
2852  if (aclresult != ACLCHECK_OK)
2853  aclcheck_error(aclresult, OBJECT_TABLESPACE,
2855  }
2856  }
2857  else
2858  params.tablespaceOid = InvalidOid;
2859 
2860  switch (stmt->kind)
2861  {
2862  case REINDEX_OBJECT_INDEX:
2863  ReindexIndex(stmt, &params, isTopLevel);
2864  break;
2865  case REINDEX_OBJECT_TABLE:
2866  ReindexTable(stmt, &params, isTopLevel);
2867  break;
2868  case REINDEX_OBJECT_SCHEMA:
2869  case REINDEX_OBJECT_SYSTEM:
2871 
2872  /*
2873  * This cannot run inside a user transaction block; if we were
2874  * inside a transaction, then its commit- and
2875  * start-transaction-command calls would not have the intended
2876  * effect!
2877  */
2878  PreventInTransactionBlock(isTopLevel,
2879  (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2880  (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2881  "REINDEX DATABASE");
2882  ReindexMultipleTables(stmt, &params);
2883  break;
2884  default:
2885  elog(ERROR, "unrecognized object type: %d",
2886  (int) stmt->kind);
2887  break;
2888  }
2889 }
int verbose
#define REINDEXOPT_CONCURRENTLY
Definition: index.h:44
#define REINDEXOPT_VERBOSE
Definition: index.h:41
static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:2896
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition: indexcmds.c:3085
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:3026
@ REINDEX_OBJECT_DATABASE
Definition: parsenodes.h:3983
@ REINDEX_OBJECT_INDEX
Definition: parsenodes.h:3979
@ REINDEX_OBJECT_SCHEMA
Definition: parsenodes.h:3981
@ REINDEX_OBJECT_SYSTEM
Definition: parsenodes.h:3982
@ REINDEX_OBJECT_TABLE
Definition: parsenodes.h:3980
Oid tablespaceOid
Definition: index.h:36
bits32 options
Definition: index.h:35
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3584

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, get_tablespace_name(), get_tablespace_oid(), GetUserId(), InvalidOid, lfirst, DefElem::location, MyDatabaseTableSpace, object_aclcheck(), OBJECT_TABLESPACE, OidIsValid, ReindexParams::options, parser_errposition(), PreventInTransactionBlock(), REINDEX_OBJECT_DATABASE, REINDEX_OBJECT_INDEX, REINDEX_OBJECT_SCHEMA, REINDEX_OBJECT_SYSTEM, REINDEX_OBJECT_TABLE, ReindexIndex(), ReindexMultipleTables(), REINDEXOPT_CONCURRENTLY, REINDEXOPT_VERBOSE, ReindexTable(), stmt, ReindexParams::tablespaceOid, and verbose.

Referenced by ProcessUtilitySlow().

◆ ExecuteCallStmt()

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

Definition at line 2174 of file functioncmds.c.

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

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

Referenced by standard_ProcessUtility().

◆ ExecuteDoStmt()

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

Definition at line 2052 of file functioncmds.c.

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

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

Referenced by standard_ProcessUtility().

◆ get_am_name()

char* get_am_name ( Oid  amOid)

Definition at line 192 of file amcmds.c.

193 {
194  HeapTuple tup;
195  char *result = NULL;
196 
197  tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
198  if (HeapTupleIsValid(tup))
199  {
200  Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
201 
202  result = pstrdup(NameStr(amform->amname));
203  ReleaseSysCache(tup);
204  }
205  return result;
206 }

References GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), pstrdup(), ReleaseSysCache(), and SearchSysCache1().

Referenced by assignOperTypes(), getObjectIdentityParts(), IsThereOpClassInNamespace(), and IsThereOpFamilyInNamespace().

◆ get_am_oid()

Oid get_am_oid ( const char *  amname,
bool  missing_ok 
)

Definition at line 183 of file amcmds.c.

184 {
185  return get_am_type_oid(amname, '\0', missing_ok);
186 }
static Oid get_am_type_oid(const char *amname, char amtype, bool missing_ok)
Definition: amcmds.c:129

References get_am_type_oid().

Referenced by get_object_address_unqualified().

◆ get_index_am_oid()

Oid get_index_am_oid ( const char *  amname,
bool  missing_ok 
)

Definition at line 163 of file amcmds.c.

164 {
165  return get_am_type_oid(amname, AMTYPE_INDEX, missing_ok);
166 }

References get_am_type_oid().

Referenced by DefineOpFamily(), get_object_address_opcf(), and transformIndexConstraint().

◆ get_opclass_oid()

Oid get_opclass_oid ( Oid  amID,
List opclassname,
bool  missing_ok 
)

Definition at line 219 of file opclasscmds.c.

220 {
221  HeapTuple htup;
222  Form_pg_opclass opcform;
223  Oid opcID;
224 
225  htup = OpClassCacheLookup(amID, opclassname, missing_ok);
226  if (!HeapTupleIsValid(htup))
227  return InvalidOid;
228  opcform = (Form_pg_opclass) GETSTRUCT(htup);
229  opcID = opcform->oid;
230  ReleaseSysCache(htup);
231 
232  return opcID;
233 }
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:161

References GETSTRUCT, HeapTupleIsValid, InvalidOid, OpClassCacheLookup(), and ReleaseSysCache().

Referenced by findRangeSubOpclass(), get_object_address_opcf(), and resolve_unique_index_expr().

◆ get_opfamily_oid()

Oid get_opfamily_oid ( Oid  amID,
List opfamilyname,
bool  missing_ok 
)

Definition at line 138 of file opclasscmds.c.

139 {
140  HeapTuple htup;
141  Form_pg_opfamily opfamform;
142  Oid opfID;
143 
144  htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
145  if (!HeapTupleIsValid(htup))
146  return InvalidOid;
147  opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
148  opfID = opfamform->oid;
149  ReleaseSysCache(htup);
150 
151  return opfID;
152 }
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:80

References GETSTRUCT, HeapTupleIsValid, InvalidOid, OpFamilyCacheLookup(), and ReleaseSysCache().

Referenced by AlterOpFamily(), AlterOpFamilyAdd(), DefineOpClass(), and get_object_address_opcf().

◆ get_table_am_oid()

Oid get_table_am_oid ( const char *  amname,
bool  missing_ok 
)

Definition at line 173 of file amcmds.c.

174 {
175  return get_am_type_oid(amname, AMTYPE_TABLE, missing_ok);
176 }

References get_am_type_oid().

Referenced by ATPrepSetAccessMethod(), check_default_table_access_method(), and DefineRelation().

◆ get_transform_oid()

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

Definition at line 2005 of file functioncmds.c.

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

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

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

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 2338 of file indexcmds.c.

2339 {
2340  Oid result = InvalidOid;
2341  int nexact = 0;
2342  int ncompatible = 0;
2343  int ncompatiblepreferred = 0;
2344  Relation rel;
2345  ScanKeyData skey[1];
2346  SysScanDesc scan;
2347  HeapTuple tup;
2348  TYPCATEGORY tcategory;
2349 
2350  /* If it's a domain, look at the base type instead */
2351  type_id = getBaseType(type_id);
2352 
2353  tcategory = TypeCategory(type_id);
2354 
2355  /*
2356  * We scan through all the opclasses available for the access method,
2357  * looking for one that is marked default and matches the target type
2358  * (either exactly or binary-compatibly, but prefer an exact match).
2359  *
2360  * We could find more than one binary-compatible match. If just one is
2361  * for a preferred type, use that one; otherwise we fail, forcing the user
2362  * to specify which one he wants. (The preferred-type special case is a
2363  * kluge for varchar: it's binary-compatible to both text and bpchar, so
2364  * we need a tiebreaker.) If we find more than one exact match, then
2365  * someone put bogus entries in pg_opclass.
2366  */
2367  rel = table_open(OperatorClassRelationId, AccessShareLock);
2368 
2369  ScanKeyInit(&skey[0],
2370  Anum_pg_opclass_opcmethod,
2371  BTEqualStrategyNumber, F_OIDEQ,
2372  ObjectIdGetDatum(am_id));
2373 
2374  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
2375  NULL, 1, skey);
2376 
2377  while (HeapTupleIsValid(tup = systable_getnext(scan)))
2378  {
2379  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
2380 
2381  /* ignore altogether if not a default opclass */
2382  if (!opclass->opcdefault)
2383  continue;
2384  if (opclass->opcintype == type_id)
2385  {
2386  nexact++;
2387  result = opclass->oid;
2388  }
2389  else if (nexact == 0 &&
2390  IsBinaryCoercible(type_id, opclass->opcintype))
2391  {
2392  if (IsPreferredType(tcategory, opclass->opcintype))
2393  {
2394  ncompatiblepreferred++;
2395  result = opclass->oid;
2396  }
2397  else if (ncompatiblepreferred == 0)
2398  {
2399  ncompatible++;
2400  result = opclass->oid;
2401  }
2402  }
2403  }
2404 
2405  systable_endscan(scan);
2406 
2408 
2409  /* raise error if pg_opclass contains inconsistent data */
2410  if (nexact > 1)
2411  ereport(ERROR,
2413  errmsg("there are multiple default operator classes for data type %s",
2414  format_type_be(type_id))));
2415 
2416  if (nexact == 1 ||
2417  ncompatiblepreferred == 1 ||
2418  (ncompatiblepreferred == 0 && ncompatible == 1))
2419  return result;
2420 
2421  return InvalidOid;
2422 }
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2521
TYPCATEGORY TypeCategory(Oid type)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY
Definition: parse_coerce.h:21

References AccessShareLock, BTEqualStrategyNumber, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), getBaseType(), GETSTRUCT, HeapTupleIsValid, InvalidOid, IsBinaryCoercible(), IsPreferredType(), ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TypeCategory().

Referenced by ComputePartitionAttrs(), findRangeSubOpclass(), get_opclass(), get_opclass_name(), lookup_type_cache(), ResolveOpClass(), and transformIndexConstraint().

◆ GetOperatorFromWellKnownStrategy()

void GetOperatorFromWellKnownStrategy ( Oid  opclass,
Oid  rhstype,
Oid opid,
StrategyNumber strat 
)

Definition at line 2441 of file indexcmds.c.

2443 {
2444  Oid opfamily;
2445  Oid opcintype;
2446  StrategyNumber instrat = *strat;
2447 
2448  Assert(instrat == RTEqualStrategyNumber || instrat == RTOverlapStrategyNumber || instrat == RTContainedByStrategyNumber);
2449 
2450  *opid = InvalidOid;
2451 
2452  if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2453  {
2454  /*
2455  * Ask the opclass to translate to its internal stratnum
2456  *
2457  * For now we only need GiST support, but this could support other
2458  * indexams if we wanted.
2459  */
2460  *strat = GistTranslateStratnum(opclass, instrat);
2461  if (*strat == InvalidStrategy)
2462  {
2463  HeapTuple tuple;
2464 
2465  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
2466  if (!HeapTupleIsValid(tuple))
2467  elog(ERROR, "cache lookup failed for operator class %u", opclass);
2468 
2469  ereport(ERROR,
2470  errcode(ERRCODE_UNDEFINED_OBJECT),
2471  instrat == RTEqualStrategyNumber ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2472  instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2473  instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2474  errdetail("Could not translate strategy number %d for operator class \"%s\" for access method \"%s\".",
2475  instrat, NameStr(((Form_pg_opclass) GETSTRUCT(tuple))->opcname), "gist"));
2476  }
2477 
2478  /*
2479  * We parameterize rhstype so foreign keys can ask for a <@ operator
2480  * whose rhs matches the aggregate function. For example range_agg
2481  * returns anymultirange.
2482  */
2483  if (!OidIsValid(rhstype))
2484  rhstype = opcintype;
2485  *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2486  }
2487 
2488  if (!OidIsValid(*opid))
2489  {
2490  HeapTuple tuple;
2491 
2492  tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamily));
2493  if (!HeapTupleIsValid(tuple))
2494  elog(ERROR, "cache lookup failed for operator family %u", opfamily);
2495 
2496  ereport(ERROR,
2497  errcode(ERRCODE_UNDEFINED_OBJECT),
2498  instrat == RTEqualStrategyNumber ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2499  instrat == RTOverlapStrategyNumber ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2500  instrat == RTContainedByStrategyNumber ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2501  errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2502  NameStr(((Form_pg_opfamily) GETSTRUCT(tuple))->opfname), "gist"));
2503  }
2504 }
StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat)
Definition: gistutil.c:1081
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTEqualStrategyNumber
Definition: stratnum.h:68
#define InvalidStrategy
Definition: stratnum.h:24
#define RTContainedByStrategyNumber
Definition: stratnum.h:58

References Assert, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), GETSTRUCT, GistTranslateStratnum(), HeapTupleIsValid, InvalidOid, InvalidStrategy, NameStr, ObjectIdGetDatum(), OidIsValid, RTContainedByStrategyNumber, RTEqualStrategyNumber, RTOverlapStrategyNumber, and SearchSysCache1().

Referenced by ComputeIndexAttrs(), and FindFKPeriodOpers().

◆ ImportForeignSchema()

void ImportForeignSchema ( ImportForeignSchemaStmt stmt)

Definition at line 1484 of file foreigncmds.c.

1485 {
1486  ForeignServer *server;
1487  ForeignDataWrapper *fdw;
1488  FdwRoutine *fdw_routine;
1489  AclResult aclresult;
1490  List *cmd_list;
1491  ListCell *lc;
1492 
1493  /* Check that the foreign server exists and that we have USAGE on it */
1494  server = GetForeignServerByName(stmt->server_name, false);
1495  aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, GetUserId(), ACL_USAGE);
1496  if (aclresult != ACLCHECK_OK)
1497  aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1498 
1499  /* Check that the schema exists and we have CREATE permissions on it */
1500  (void) LookupCreationNamespace(stmt->local_schema);
1501 
1502  /* Get the FDW and check it supports IMPORT */
1503  fdw = GetForeignDataWrapper(server->fdwid);
1504  if (!OidIsValid(fdw->fdwhandler))
1505  ereport(ERROR,
1506  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1507  errmsg("foreign-data wrapper \"%s\" has no handler",
1508  fdw->fdwname)));
1509  fdw_routine = GetFdwRoutine(fdw->fdwhandler);
1510  if (fdw_routine->ImportForeignSchema == NULL)
1511  ereport(ERROR,
1512  (errcode(ERRCODE_FDW_NO_SCHEMAS),
1513  errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
1514  fdw->fdwname)));
1515 
1516  /* Call FDW to get a list of commands */
1517  cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
1518 
1519  /* Parse and execute each command */
1520  foreach(lc, cmd_list)
1521  {
1522  char *cmd = (char *) lfirst(lc);
1523  import_error_callback_arg callback_arg;
1524  ErrorContextCallback sqlerrcontext;
1525  List *raw_parsetree_list;
1526  ListCell *lc2;
1527 
1528  /*
1529  * Setup error traceback support for ereport(). This is so that any
1530  * error in the generated SQL will be displayed nicely.
1531  */
1532  callback_arg.tablename = NULL; /* not known yet */
1533  callback_arg.cmd = cmd;
1534  sqlerrcontext.callback = import_error_callback;
1535  sqlerrcontext.arg = (void *) &callback_arg;
1536  sqlerrcontext.previous = error_context_stack;
1537  error_context_stack = &sqlerrcontext;
1538 
1539  /*
1540  * Parse the SQL string into a list of raw parse trees.
1541  */
1542  raw_parsetree_list = pg_parse_query(cmd);
1543 
1544  /*
1545  * Process each parse tree (we allow the FDW to put more than one
1546  * command per string, though this isn't really advised).
1547  */
1548  foreach(lc2, raw_parsetree_list)
1549  {
1550  RawStmt *rs = lfirst_node(RawStmt, lc2);
1552  PlannedStmt *pstmt;
1553 
1554  /*
1555  * Because we only allow CreateForeignTableStmt, we can skip parse
1556  * analysis, rewrite, and planning steps here.
1557  */
1558  if (!IsA(cstmt, CreateForeignTableStmt))
1559  elog(ERROR,
1560  "foreign-data wrapper \"%s\" returned incorrect statement type %d",
1561  fdw->fdwname, (int) nodeTag(cstmt));
1562 
1563  /* Ignore commands for tables excluded by filter options */
1565  continue;
1566 
1567  /* Enable reporting of current table's name on error */
1568  callback_arg.tablename = cstmt->base.relation->relname;
1569 
1570  /* Ensure creation schema is the one given in IMPORT statement */
1571  cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
1572 
1573  /* No planning needed, just make a wrapper PlannedStmt */
1574  pstmt = makeNode(PlannedStmt);
1575  pstmt->commandType = CMD_UTILITY;
1576  pstmt->canSetTag = false;
1577  pstmt->utilityStmt = (Node *) cstmt;
1578  pstmt->stmt_location = rs->stmt_location;
1579  pstmt->stmt_len = rs->stmt_len;
1580 
1581  /* Execute statement */
1582  ProcessUtility(pstmt, cmd, false,
1583  PROCESS_UTILITY_SUBCOMMAND, NULL, NULL,
1584  None_Receiver, NULL);
1585 
1586  /* Be sure to advance the command counter between subcommands */
1588 
1589  callback_arg.tablename = NULL;
1590  }
1591 
1592  error_context_stack = sqlerrcontext.previous;
1593  }
1594 }
DestReceiver * None_Receiver
Definition: dest.c:96
ErrorContextCallback * error_context_stack
Definition: elog.c:94
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition: foreign.c:324
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition: foreign.c:472
static void import_error_callback(void *arg)
Definition: foreigncmds.c:1600
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3413
@ CMD_UTILITY
Definition: nodes.h:270
List * pg_parse_query(const char *query_string)
Definition: postgres.c:611
RangeVar * relation
Definition: parsenodes.h:2658
struct ErrorContextCallback * previous
Definition: elog.h:295
void(* callback)(void *arg)
Definition: elog.h:296
ImportForeignSchema_function ImportForeignSchema
Definition: fdwapi.h:260
char * relname
Definition: primnodes.h:82
char * schemaname
Definition: primnodes.h:79
ParseLoc stmt_location
Definition: parsenodes.h:2028
ParseLoc stmt_len
Definition: parsenodes.h:2029
Node * stmt
Definition: parsenodes.h:2027
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
@ PROCESS_UTILITY_SUBCOMMAND
Definition: utility.h:26

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, ErrorContextCallback::arg, CreateForeignTableStmt::base, ErrorContextCallback::callback, import_error_callback_arg::cmd, CMD_UTILITY, CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, error_context_stack, ForeignDataWrapper::fdwhandler, ForeignServer::fdwid, ForeignDataWrapper::fdwname, GetFdwRoutine(), GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), if(), import_error_callback(), FdwRoutine::ImportForeignSchema, IsA, IsImportableForeignTable(), lfirst, lfirst_node, LookupCreationNamespace(), makeNode, nodeTag, None_Receiver, object_aclcheck(), OBJECT_FOREIGN_SERVER, OidIsValid, pg_parse_query(), ErrorContextCallback::previous, PROCESS_UTILITY_SUBCOMMAND, ProcessUtility(), pstrdup(), CreateStmt::relation, RangeVar::relname, RangeVar::schemaname, ForeignServer::serverid, ForeignServer::servername, RawStmt::stmt, stmt, RawStmt::stmt_len, RawStmt::stmt_location, and import_error_callback_arg::tablename.

Referenced by ProcessUtilitySlow().

◆ interpret_function_parameter_list()

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

Definition at line 182 of file functioncmds.c.

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

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

Referenced by CreateFunction(), and DefineAggregate().

◆ IsThereFunctionInNamespace()

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

Definition at line 2029 of file functioncmds.c.

2031 {
2032  /* check for duplicate name (more friendly than unique-index failure) */
2033  if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2035  PointerGetDatum(proargtypes),
2036  ObjectIdGetDatum(nspOid)))
2037  ereport(ERROR,
2038  (errcode(ERRCODE_DUPLICATE_FUNCTION),
2039  errmsg("function %s already exists in schema \"%s\"",
2041  NIL, proargtypes->values),
2042  get_namespace_name(nspOid))));
2043 }
const char * funcname_signature_string(const char *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1992
int16 pronargs
Definition: pg_proc.h:81
NameData proname
Definition: pg_proc.h:35

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

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

◆ IsThereOpClassInNamespace()

void IsThereOpClassInNamespace ( const char *  opcname,
Oid  opcmethod,
Oid  opcnamespace 
)

Definition at line 1707 of file opclasscmds.c.

1709 {
1710  /* make sure the new name doesn't exist */
1711  if (SearchSysCacheExists3(CLAAMNAMENSP,
1712  ObjectIdGetDatum(opcmethod),
1713  CStringGetDatum(opcname),
1714  ObjectIdGetDatum(opcnamespace)))
1715  ereport(ERROR,
1717  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1718  opcname,
1719  get_am_name(opcmethod),
1720  get_namespace_name(opcnamespace))));
1721 }
char * get_am_name(Oid amOid)
Definition: amcmds.c:192

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum(), and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

◆ IsThereOpFamilyInNamespace()

void IsThereOpFamilyInNamespace ( const char *  opfname,
Oid  opfmethod,
Oid  opfnamespace 
)

Definition at line 1730 of file opclasscmds.c.

1732 {
1733  /* make sure the new name doesn't exist */
1734  if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1735  ObjectIdGetDatum(opfmethod),
1736  CStringGetDatum(opfname),
1737  ObjectIdGetDatum(opfnamespace)))
1738  ereport(ERROR,
1740  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1741  opfname,
1742  get_am_name(opfmethod),
1743  get_namespace_name(opfnamespace))));
1744 }

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum(), and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

◆ makeObjectName()

char* makeObjectName ( const char *  name1,
const char *  name2,
const char *  label 
)

Definition at line 2529 of file indexcmds.c.

2530 {
2531  char *name;
2532  int overhead = 0; /* chars needed for label and underscores */
2533  int availchars; /* chars available for name(s) */
2534  int name1chars; /* chars allocated to name1 */
2535  int name2chars; /* chars allocated to name2 */
2536  int ndx;
2537 
2538  name1chars = strlen(name1);
2539  if (name2)
2540  {
2541  name2chars = strlen(name2);
2542  overhead++; /* allow for separating underscore */
2543  }
2544  else
2545  name2chars = 0;
2546  if (label)
2547  overhead += strlen(label) + 1;
2548 
2549  availchars = NAMEDATALEN - 1 - overhead;
2550  Assert(availchars > 0); /* else caller chose a bad label */
2551 
2552  /*
2553  * If we must truncate, preferentially truncate the longer name. This
2554  * logic could be expressed without a loop, but it's simple and obvious as
2555  * a loop.
2556  */
2557  while (name1chars + name2chars > availchars)
2558  {
2559  if (name1chars > name2chars)
2560  name1chars--;
2561  else
2562  name2chars--;
2563  }
2564 
2565  name1chars = pg_mbcliplen(name1, name1chars, name1chars);
2566  if (name2)
2567  name2chars = pg_mbcliplen(name2, name2chars, name2chars);
2568 
2569  /* Now construct the string using the chosen lengths */
2570  name = palloc(name1chars + name2chars + overhead + 1);
2571  memcpy(name, name1, name1chars);
2572  ndx = name1chars;
2573  if (name2)
2574  {
2575  name[ndx++] = '_';
2576  memcpy(name + ndx, name2, name2chars);
2577  ndx += name2chars;
2578  }
2579  if (label)
2580  {
2581  name[ndx++] = '_';
2582  strcpy(name + ndx, label);
2583  }
2584  else
2585  name[ndx] = '\0';
2586 
2587  return name;
2588 }
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083

References Assert, label, name, NAMEDATALEN, palloc(), and pg_mbcliplen().

Referenced by ChooseConstraintName(), ChooseExtendedStatisticName(), ChooseRelationName(), and makeArrayTypeName().

◆ RemoveFunctionById()

void RemoveFunctionById ( Oid  funcOid)

Definition at line 1292 of file functioncmds.c.

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

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

Referenced by doDeletion().

◆ RemoveObjects()

void RemoveObjects ( DropStmt stmt)

Definition at line 53 of file dropcmds.c.

54 {
55  ObjectAddresses *objects;
56  ListCell *cell1;
57 
58  objects = new_object_addresses();
59 
60  foreach(cell1, stmt->objects)
61  {
62  ObjectAddress address;
63  Node *object = lfirst(cell1);
64  Relation relation = NULL;
65  Oid namespaceId;
66 
67  /* Get an ObjectAddress for the object. */
68  address = get_object_address(stmt->removeType,
69  object,
70  &relation,
72  stmt->missing_ok);
73 
74  /*
75  * Issue NOTICE if supplied object was not found. Note this is only
76  * relevant in the missing_ok case, because otherwise
77  * get_object_address would have thrown an error.
78  */
79  if (!OidIsValid(address.objectId))
80  {
81  Assert(stmt->missing_ok);
82  does_not_exist_skipping(stmt->removeType, object);
83  continue;
84  }
85 
86  /*
87  * Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are
88  * happy to operate on an aggregate as on any other function, we have
89  * historically not allowed this for DROP FUNCTION.
90  */
91  if (stmt->removeType == OBJECT_FUNCTION)
92  {
93  if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
94  ereport(ERROR,
95  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
96  errmsg("\"%s\" is an aggregate function",
97  NameListToString(castNode(ObjectWithArgs, object)->objname)),
98  errhint("Use DROP AGGREGATE to drop aggregate functions.")));
99  }
100 
101  /* Check permissions. */
102  namespaceId = get_object_namespace(&address);
103  if (!OidIsValid(namespaceId) ||
104  !object_ownercheck(NamespaceRelationId, namespaceId, GetUserId()))
105  check_object_ownership(GetUserId(), stmt->removeType, address,
106  object, relation);
107 
108  /*
109  * Make note if a temporary namespace has been accessed in this
110  * transaction.
111  */
112  if (OidIsValid(namespaceId) && isTempNamespace(namespaceId))
114 
115  /* Release any relcache reference count, but keep lock until commit. */
116  if (relation)
117  table_close(relation, NoLock);
118 
119  add_exact_object_address(&address, objects);
120  }
121 
122  /* Here we really delete them. */
123  performMultipleDeletions(objects, stmt->behavior, 0);
124 
125  free_object_addresses(objects);
126 }
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
static void does_not_exist_skipping(ObjectType objtype, Node *object)
Definition: dropcmds.c:243
#define AccessExclusiveLock
Definition: lockdefs.h:43
char get_func_prokind(Oid funcid)
Definition: lsyscache.c:1818
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3634
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
Oid get_object_namespace(const ObjectAddress *address)
int MyXactFlags
Definition: xact.c:134
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102

References AccessExclusiveLock, add_exact_object_address(), Assert, castNode, check_object_ownership(), does_not_exist_skipping(), ereport, errcode(), errhint(), errmsg(), ERROR, free_object_addresses(), get_func_prokind(), get_object_address(), get_object_namespace(), GetUserId(), isTempNamespace(), lfirst, MyXactFlags, NameListToString(), new_object_addresses(), NoLock, OBJECT_FUNCTION, object_ownercheck(), ObjectAddress::objectId, OidIsValid, performMultipleDeletions(), stmt, table_close(), and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by ExecDropStmt().

◆ RemoveOperatorById()

void RemoveOperatorById ( Oid  operOid)

Definition at line 413 of file operatorcmds.c.

414 {
415  Relation relation;
416  HeapTuple tup;
417  Form_pg_operator op;
418 
419  relation = table_open(OperatorRelationId, RowExclusiveLock);
420 
421  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
422  if (!HeapTupleIsValid(tup)) /* should not happen */
423  elog(ERROR, "cache lookup failed for operator %u", operOid);
424  op = (Form_pg_operator) GETSTRUCT(tup);
425 
426  /*
427  * Reset links from commutator and negator, if any. In case of a
428  * self-commutator or self-negator, this means we have to re-fetch the
429  * updated tuple. (We could optimize away updates on the tuple we're
430  * about to drop, but it doesn't seem worth convoluting the logic for.)
431  */
432  if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
433  {
434  OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
435  if (operOid == op->oprcom || operOid == op->oprnegate)
436  {
437  ReleaseSysCache(tup);
438  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
439  if (!HeapTupleIsValid(tup)) /* should not happen */
440  elog(ERROR, "cache lookup failed for operator %u", operOid);
441  }
442  }
443 
444  CatalogTupleDelete(relation, &tup->t_self);
445 
446  ReleaseSysCache(tup);
447 
448  table_close(relation, RowExclusiveLock);
449 }

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

Referenced by doDeletion().

◆ RemoveStatisticsById()

void RemoveStatisticsById ( Oid  statsOid)

Definition at line 747 of file statscmds.c.

748 {
749  Relation relation;
750  Relation rel;
751  HeapTuple tup;
752  Form_pg_statistic_ext statext;
753  Oid relid;
754 
755  /*
756  * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
757  * associated table, so that dependent plans will be rebuilt.
758  */
759  relation = table_open(StatisticExtRelationId, RowExclusiveLock);
760 
761  tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
762 
763  if (!HeapTupleIsValid(tup)) /* should not happen */
764  elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
765 
766  statext = (Form_pg_statistic_ext) GETSTRUCT(tup);
767  relid = statext->stxrelid;
768 
769  /*
770  * Delete the pg_statistic_ext_data tuples holding the actual statistical
771  * data. There might be data with/without inheritance, so attempt deleting
772  * both. We lock the user table first, to prevent other processes (e.g.
773  * DROP STATISTICS) from removing the row concurrently.
774  */
775  rel = table_open(relid, ShareUpdateExclusiveLock);
776 
777  RemoveStatisticsDataById(statsOid, true);
778  RemoveStatisticsDataById(statsOid, false);
779 
781 
782  CatalogTupleDelete(relation, &tup->t_self);
783 
784  ReleaseSysCache(tup);
785 
786  /* Keep lock until the end of the transaction. */
787  table_close(rel, NoLock);
788 
789  table_close(relation, RowExclusiveLock);
790 }
FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition: statscmds.c:722

References CacheInvalidateRelcacheByRelid(), CatalogTupleDelete(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, NoLock, ObjectIdGetDatum(), ReleaseSysCache(), RemoveStatisticsDataById(), RowExclusiveLock, SearchSysCache1(), ShareUpdateExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveStatisticsDataById()

void RemoveStatisticsDataById ( Oid  statsOid,
bool  inh 
)

Definition at line 722 of file statscmds.c.

723 {
724  Relation relation;
725  HeapTuple tup;
726 
727  relation = table_open(StatisticExtDataRelationId, RowExclusiveLock);
728 
729  tup = SearchSysCache2(STATEXTDATASTXOID, ObjectIdGetDatum(statsOid),
730  BoolGetDatum(inh));
731 
732  /* We don't know if the data row for inh value exists. */
733  if (HeapTupleIsValid(tup))
734  {
735  CatalogTupleDelete(relation, &tup->t_self);
736 
737  ReleaseSysCache(tup);
738  }
739 
740  table_close(relation, RowExclusiveLock);
741 }

References BoolGetDatum(), CatalogTupleDelete(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by RemoveStatisticsById(), and statext_store().

◆ RemoveTSConfigurationById()

void RemoveTSConfigurationById ( Oid  cfgId)

Definition at line 1108 of file tsearchcmds.c.

1109 {
1110  Relation relCfg,
1111  relMap;
1112  HeapTuple tup;
1113  ScanKeyData skey;
1114  SysScanDesc scan;
1115 
1116  /* Remove the pg_ts_config entry */
1117  relCfg = table_open(TSConfigRelationId, RowExclusiveLock);
1118 
1119  tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
1120 
1121  if (!HeapTupleIsValid(tup))
1122  elog(ERROR, "cache lookup failed for text search dictionary %u",
1123  cfgId);
1124 
1125  CatalogTupleDelete(relCfg, &tup->t_self);
1126 
1127  ReleaseSysCache(tup);
1128 
1129  table_close(relCfg, RowExclusiveLock);
1130 
1131  /* Remove any pg_ts_config_map entries */
1132  relMap = table_open(TSConfigMapRelationId, RowExclusiveLock);
1133 
1134  ScanKeyInit(&skey,
1135  Anum_pg_ts_config_map_mapcfg,
1136  BTEqualStrategyNumber, F_OIDEQ,
1137  ObjectIdGetDatum(cfgId));
1138 
1139  scan = systable_beginscan(relMap, TSConfigMapIndexId, true,
1140  NULL, 1, &skey);
1141 
1142  while (HeapTupleIsValid((tup = systable_getnext(scan))))
1143  {
1144  CatalogTupleDelete(relMap, &tup->t_self);
1145  }
1146 
1147  systable_endscan(scan);
1148 
1149  table_close(relMap, RowExclusiveLock);
1150 }

References BTEqualStrategyNumber, CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveUserMapping()

Oid RemoveUserMapping ( DropUserMappingStmt stmt)

Definition at line 1324 of file foreigncmds.c.

1325 {
1326  ObjectAddress object;
1327  Oid useId;
1328  Oid umId;
1329  ForeignServer *srv;
1330  RoleSpec *role = (RoleSpec *) stmt->user;
1331 
1332  if (role->roletype == ROLESPEC_PUBLIC)
1333  useId = ACL_ID_PUBLIC;
1334  else
1335  {
1336  useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1337  if (!OidIsValid(useId))
1338  {
1339  /*
1340  * IF EXISTS specified, role not found and not public. Notice this
1341  * and leave.
1342  */
1343  elog(NOTICE, "role \"%s\" does not exist, skipping",
1344  role->rolename);
1345  return InvalidOid;
1346  }
1347  }
1348 
1349  srv = GetForeignServerByName(stmt->servername, true);
1350 
1351  if (!srv)
1352  {
1353  if (!stmt->missing_ok)
1354  ereport(ERROR,
1355  (errcode(ERRCODE_UNDEFINED_OBJECT),
1356  errmsg("server \"%s\" does not exist",
1357  stmt->servername)));
1358  /* IF EXISTS, just note it */
1359  ereport(NOTICE,
1360  (errmsg("server \"%s\" does not exist, skipping",
1361  stmt->servername)));
1362  return InvalidOid;
1363  }
1364 
1365  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1366  ObjectIdGetDatum(useId),
1367  ObjectIdGetDatum(srv->serverid));
1368 
1369  if (!OidIsValid(umId))
1370  {
1371  if (!stmt->missing_ok)
1372  ereport(ERROR,
1373  (errcode(ERRCODE_UNDEFINED_OBJECT),
1374  errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1375  MappingUserName(useId), stmt->servername)));
1376 
1377  /* IF EXISTS specified, just note it */
1378  ereport(NOTICE,
1379  (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1380  MappingUserName(useId), stmt->servername)));
1381  return InvalidOid;
1382  }
1383 
1384  user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
1385 
1386  /*
1387  * Do the deletion
1388  */
1389  object.classId = UserMappingRelationId;
1390  object.objectId = umId;
1391  object.objectSubId = 0;
1392 
1393  performDeletion(&object, DROP_CASCADE, 0);
1394 
1395  return umId;
1396 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DROP_CASCADE
Definition: parsenodes.h:2337
char * rolename
Definition: parsenodes.h:405

References ACL_ID_PUBLIC, DROP_CASCADE, elog, ereport, errcode(), errmsg(), ERROR, get_rolespec_oid(), GetForeignServerByName(), GetSysCacheOid2, if(), InvalidOid, MappingUserName, NOTICE, ObjectIdGetDatum(), OidIsValid, performDeletion(), RoleSpec::rolename, ROLESPEC_PUBLIC, RoleSpec::roletype, ForeignServer::serverid, ForeignServer::servername, stmt, and user_mapping_ddl_aclcheck().

Referenced by ProcessUtilitySlow().

◆ ResolveOpClass()

Oid ResolveOpClass ( const List opclass,
Oid  attrType,
const char *  accessMethodName,
Oid  accessMethodId 
)

Definition at line 2253 of file indexcmds.c.

2255 {
2256  char *schemaname;
2257  char *opcname;
2258  HeapTuple tuple;
2259  Form_pg_opclass opform;
2260  Oid opClassId,
2261  opInputType;
2262 
2263  if (opclass == NIL)
2264  {
2265  /* no operator class specified, so find the default */
2266  opClassId = GetDefaultOpClass(attrType, accessMethodId);
2267  if (!OidIsValid(opClassId))
2268  ereport(ERROR,
2269  (errcode(ERRCODE_UNDEFINED_OBJECT),
2270  errmsg("data type %s has no default operator class for access method \"%s\"",
2271  format_type_be(attrType), accessMethodName),
2272  errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2273  return opClassId;
2274  }
2275 
2276  /*
2277  * Specific opclass name given, so look up the opclass.
2278  */
2279 
2280  /* deconstruct the name list */
2281  DeconstructQualifiedName(opclass, &schemaname, &opcname);
2282 
2283  if (schemaname)
2284  {
2285  /* Look in specific schema only */
2286  Oid namespaceId;
2287 
2288  namespaceId = LookupExplicitNamespace(schemaname, false);
2289  tuple = SearchSysCache3(CLAAMNAMENSP,
2290  ObjectIdGetDatum(accessMethodId),
2291  PointerGetDatum(opcname),
2292  ObjectIdGetDatum(namespaceId));
2293  }
2294  else
2295  {
2296  /* Unqualified opclass name, so search the search path */
2297  opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
2298  if (!OidIsValid(opClassId))
2299  ereport(ERROR,
2300  (errcode(ERRCODE_UNDEFINED_OBJECT),
2301  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2302  opcname, accessMethodName)));
2303  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
2304  }
2305 
2306  if (!HeapTupleIsValid(tuple))
2307  ereport(ERROR,
2308  (errcode(ERRCODE_UNDEFINED_OBJECT),
2309  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2310  NameListToString(opclass), accessMethodName)));
2311 
2312  /*
2313  * Verify that the index operator class accepts this datatype. Note we
2314  * will accept binary compatibility.
2315  */
2316  opform = (Form_pg_opclass) GETSTRUCT(tuple);
2317  opClassId = opform->oid;
2318  opInputType = opform->opcintype;
2319 
2320  if (!IsBinaryCoercible(attrType, opInputType))
2321  ereport(ERROR,
2322  (errcode(ERRCODE_DATATYPE_MISMATCH),
2323  errmsg("operator class \"%s\" does not accept data type %s",
2324  NameListToString(opclass), format_type_be(attrType))));
2325 
2326  ReleaseSysCache(tuple);
2327 
2328  return opClassId;
2329 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:2106
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3370

References DeconstructQualifiedName(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), GetDefaultOpClass(), GETSTRUCT, HeapTupleIsValid, IsBinaryCoercible(), LookupExplicitNamespace(), NameListToString(), NIL, ObjectIdGetDatum(), OidIsValid, OpclassnameGetOpcid(), PointerGetDatum(), ReleaseSysCache(), SearchSysCache1(), and SearchSysCache3().

Referenced by ComputeIndexAttrs(), and ComputePartitionAttrs().

◆ serialize_deflist()

text* serialize_deflist ( List deflist)

Definition at line 1565 of file tsearchcmds.c.

1566 {
1567  text *result;
1569  ListCell *l;
1570 
1571  initStringInfo(&buf);
1572 
1573  foreach(l, deflist)
1574  {
1575  DefElem *defel = (DefElem *) lfirst(l);
1576  char *val = defGetString(defel);
1577 
1578  appendStringInfo(&buf, "%s = ",
1579  quote_identifier(defel->defname));
1580 
1581  /*
1582  * If the value is a T_Integer or T_Float, emit it without quotes,
1583  * otherwise with quotes. This is essential to allow correct
1584  * reconstruction of the node type as well as the value.
1585  */
1586  if (IsA(defel->arg, Integer) || IsA(defel->arg, Float))
1588  else
1589  {
1590  /* If backslashes appear, force E syntax to quote them safely */
1591  if (strchr(val, '\\'))
1593  appendStringInfoChar(&buf, '\'');
1594  while (*val)
1595  {
1596  char ch = *val++;
1597 
1598  if (SQL_STR_DOUBLE(ch, true))
1599  appendStringInfoChar(&buf, ch);
1600  appendStringInfoChar(&buf, ch);
1601  }
1602  appendStringInfoChar(&buf, '\'');
1603  }
1604  if (lnext(deflist, l) != NULL)
1605  appendStringInfoString(&buf, ", ");
1606  }
1607 
1608  result = cstring_to_text_with_len(buf.data, buf.len);
1609  pfree(buf.data);
1610  return result;
1611 }
#define ESCAPE_STRING_SYNTAX
Definition: c.h:1166
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1163
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
static char * buf
Definition: pg_test_fsync.c:73
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12623
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: value.h:29
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), DefElem::arg, buf, cstring_to_text_with_len(), defGetString(), DefElem::defname, ESCAPE_STRING_SYNTAX, initStringInfo(), IsA, lfirst, lnext(), pfree(), quote_identifier(), SQL_STR_DOUBLE, and val.

Referenced by AlterTSDictionary(), and DefineTSDictionary().

◆ StatisticsGetRelation()

Oid StatisticsGetRelation ( Oid  statId,
bool  missing_ok 
)

Definition at line 898 of file statscmds.c.

899 {
900  HeapTuple tuple;
902  Oid result;
903 
904  tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statId));
905  if (!HeapTupleIsValid(tuple))
906  {
907  if (missing_ok)
908  return InvalidOid;
909  elog(ERROR, "cache lookup failed for statistics object %u", statId);
910  }
911  stx = (Form_pg_statistic_ext) GETSTRUCT(tuple);
912  Assert(stx->oid == statId);
913 
914  result = stx->stxrelid;
915  ReleaseSysCache(tuple);
916  return result;
917 }

References Assert, elog, ERROR, GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache1().

◆ transformGenericOptions()

Datum transformGenericOptions ( Oid  catalogId,
Datum  oldOptions,
List options,
Oid  fdwvalidator 
)

Definition at line 110 of file foreigncmds.c.

114 {
115  List *resultOptions = untransformRelOptions(oldOptions);
116  ListCell *optcell;
117  Datum result;
118 
119  foreach(optcell, options)
120  {
121  DefElem *od = lfirst(optcell);
122  ListCell *cell;
123 
124  /*
125  * Find the element in resultOptions. We need this for validation in
126  * all cases.
127  */
128  foreach(cell, resultOptions)
129  {
130  DefElem *def = lfirst(cell);
131 
132  if (strcmp(def->defname, od->defname) == 0)
133  break;
134  }
135 
136  /*
137  * It is possible to perform multiple SET/DROP actions on the same
138  * option. The standard permits this, as long as the options to be
139  * added are unique. Note that an unspecified action is taken to be
140  * ADD.
141  */
142  switch (od->defaction)
143  {
144  case DEFELEM_DROP:
145  if (!cell)
146  ereport(ERROR,
147  (errcode(ERRCODE_UNDEFINED_OBJECT),
148  errmsg("option \"%s\" not found",
149  od->defname)));
150  resultOptions = list_delete_cell(resultOptions, cell);
151  break;
152 
153  case DEFELEM_SET:
154  if (!cell)
155  ereport(ERROR,
156  (errcode(ERRCODE_UNDEFINED_OBJECT),
157  errmsg("option \"%s\" not found",
158  od->defname)));
159  lfirst(cell) = od;
160  break;
161 
162  case DEFELEM_ADD:
163  case DEFELEM_UNSPEC:
164  if (cell)
165  ereport(ERROR,
167  errmsg("option \"%s\" provided more than once",
168  od->defname)));
169  resultOptions = lappend(resultOptions, od);
170  break;
171 
172  default:
173  elog(ERROR, "unrecognized action %d on option \"%s\"",
174  (int) od->defaction, od->defname);
175  break;
176  }
177  }
178 
179  result = optionListToArray(resultOptions);
180 
181  if (OidIsValid(fdwvalidator))
182  {
183  Datum valarg = result;
184 
185  /*
186  * Pass a null options list as an empty array, so that validators
187  * don't have to be declared non-strict to handle the case.
188  */
189  if (DatumGetPointer(valarg) == NULL)
190  valarg = PointerGetDatum(construct_empty_array(TEXTOID));
191  OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
192  }
193 
194  return result;
195 }
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3561
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:682
static Datum optionListToArray(List *options)
Definition: foreigncmds.c:66
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:841
@ DEFELEM_UNSPEC
Definition: parsenodes.h:805
@ DEFELEM_DROP
Definition: parsenodes.h:808
@ DEFELEM_SET
Definition: parsenodes.h:806
@ DEFELEM_ADD
Definition: parsenodes.h:807
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1331
DefElemAction defaction
Definition: parsenodes.h:818

References construct_empty_array(), DatumGetPointer(), DefElem::defaction, DEFELEM_ADD, DEFELEM_DROP, DEFELEM_SET, DEFELEM_UNSPEC, DefElem::defname, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, lappend(), lfirst, list_delete_cell(), ObjectIdGetDatum(), OidFunctionCall2, OidIsValid, optionListToArray(), PointerGetDatum(), and untransformRelOptions().

Referenced by AlterForeignDataWrapper(), AlterForeignServer(), AlterUserMapping(), ATExecAlterColumnGenericOptions(), ATExecGenericOptions(), CreateForeignDataWrapper(), CreateForeignServer(), CreateForeignTable(), and CreateUserMapping().