PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 GetOperatorFromCompareType (Oid opclass, Oid rhstype, CompareType cmptype, 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)
 
pg_noreturn void errorConflictingDefElem (DefElem *defel, ParseState *pstate)
 

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())
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))
706 (errcode(ERRCODE_UNDEFINED_OBJECT),
707 errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
708
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
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 */
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:734
#define OidIsValid(objectId)
Definition: c.h:746
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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:1210
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#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:45
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:351
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
unsigned int Oid
Definition: postgres_ext.h:30
#define RelationGetDescr(relation)
Definition: rel.h:542
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:600
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
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))
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))
324 (errcode(ERRCODE_UNDEFINED_OBJECT),
325 errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
326
327 AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
328
329 heap_freetuple(tup);
330
332}

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

Referenced by shdepReassignOwned_Owner().

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)

Definition at line 974 of file foreigncmds.c.

975{
976 Relation rel;
977 HeapTuple tp;
978 Datum repl_val[Natts_pg_foreign_server];
979 bool repl_null[Natts_pg_foreign_server];
980 bool repl_repl[Natts_pg_foreign_server];
981 Oid srvId;
983 ObjectAddress address;
984
985 rel = table_open(ForeignServerRelationId, RowExclusiveLock);
986
987 tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
988 CStringGetDatum(stmt->servername));
989
990 if (!HeapTupleIsValid(tp))
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:2639
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4075
#define CStringGetTextDatum(s)
Definition: builtins.h:97
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:37
Oid GetUserId(void)
Definition: miscinit.c:520
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2334
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))
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))
461 (errcode(ERRCODE_UNDEFINED_OBJECT),
462 errmsg("foreign server with OID %u does not exist", srvId)));
463
464 AlterForeignServerOwner_internal(rel, tup, newOwnerId);
465
466 heap_freetuple(tup);
467
469}

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

Referenced by shdepReassignOwned_Owner().

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)

Definition at line 1361 of file functioncmds.c.

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

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 817 of file opclasscmds.c.

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

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 617 of file statscmds.c.

618{
619 Relation rel;
620 Oid stxoid;
621 HeapTuple oldtup;
622 HeapTuple newtup;
623 Datum repl_val[Natts_pg_statistic_ext];
624 bool repl_null[Natts_pg_statistic_ext];
625 bool repl_repl[Natts_pg_statistic_ext];
626 ObjectAddress address;
627 int newtarget = 0;
628 bool newtarget_default;
629
630 /* -1 was used in previous versions for the default setting */
631 if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
632 {
633 newtarget = intVal(stmt->stxstattarget);
634 newtarget_default = false;
635 }
636 else
637 newtarget_default = true;
638
639 if (!newtarget_default)
640 {
641 /* Limit statistics target to a sane range */
642 if (newtarget < 0)
643 {
645 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
646 errmsg("statistics target %d is too low",
647 newtarget)));
648 }
649 else if (newtarget > MAX_STATISTICS_TARGET)
650 {
651 newtarget = MAX_STATISTICS_TARGET;
653 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
654 errmsg("lowering statistics target to %d",
655 newtarget)));
656 }
657 }
658
659 /* lookup OID of the statistics object */
660 stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
661
662 /*
663 * If we got here and the OID is not valid, it means the statistics object
664 * does not exist, but the command specified IF EXISTS. So report this as
665 * a simple NOTICE and we're done.
666 */
667 if (!OidIsValid(stxoid))
668 {
669 char *schemaname;
670 char *statname;
671
672 Assert(stmt->missing_ok);
673
674 DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
675
676 if (schemaname)
678 (errmsg("statistics object \"%s.%s\" does not exist, skipping",
679 schemaname, statname)));
680 else
682 (errmsg("statistics object \"%s\" does not exist, skipping",
683 statname)));
684
686 }
687
688 /* Search pg_statistic_ext */
689 rel = table_open(StatisticExtRelationId, RowExclusiveLock);
690
691 oldtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxoid));
692 if (!HeapTupleIsValid(oldtup))
693 elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
694
695 /* Must be owner of the existing statistics object */
696 if (!object_ownercheck(StatisticExtRelationId, stxoid, GetUserId()))
698 NameListToString(stmt->defnames));
699
700 /* Build new tuple. */
701 memset(repl_val, 0, sizeof(repl_val));
702 memset(repl_null, false, sizeof(repl_null));
703 memset(repl_repl, false, sizeof(repl_repl));
704
705 /* replace the stxstattarget column */
706 repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
707 if (!newtarget_default)
708 repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget);
709 else
710 repl_null[Anum_pg_statistic_ext_stxstattarget - 1] = true;
711
712 newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
713 repl_val, repl_null, repl_repl);
714
715 /* Update system catalog. */
716 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
717
718 InvokeObjectPostAlterHook(StatisticExtRelationId, stxoid, 0);
719
720 ObjectAddressSet(address, StatisticExtRelationId, stxoid);
721
722 /*
723 * NOTE: because we only support altering the statistics target, not the
724 * other fields, there is no need to update dependencies.
725 */
726
727 heap_freetuple(newtup);
728 ReleaseSysCache(oldtup);
729
731
732 return address;
733}
#define NOTICE
Definition: elog.h:35
Assert(PointerIsAligned(start, uint64))
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition: namespace.c:2575
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:3301
const ObjectAddress InvalidObjectAddress
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2356
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
#define MAX_STATISTICS_TARGET
Definition: vacuum.h:324
#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
1194
1195 ReleaseSysCache(tup);
1196
1197 return address;
1198}
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2362
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] =
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:2861
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2363
#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
text * serialize_deflist(List *deflist)
Definition: tsearchcmds.c:1565
static void verify_dictoptions(Oid tmplId, List *dictoptions)
Definition: tsearchcmds.c:342

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),
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:5570
#define ACL_ID_PUBLIC
Definition: acl.h:46
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition: foreign.c:182
#define MappingUserName(userid)
Definition: foreign.h:20
static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
Definition: foreigncmds.c:1075
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:409
Oid serverid
Definition: foreign.h:36
RoleSpecType roletype
Definition: parsenodes.h:415
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111

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 2383 of file functioncmds.c.

2384{
2385 FuncExpr *fexpr;
2386 HeapTuple tuple;
2387 TupleDesc tupdesc;
2388
2389 fexpr = stmt->funcexpr;
2390
2391 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2392 if (!HeapTupleIsValid(tuple))
2393 elog(ERROR, "cache lookup failed for procedure %u", fexpr->funcid);
2394
2395 tupdesc = build_function_result_tupdesc_t(tuple);
2396
2397 ReleaseSysCache(tuple);
2398
2399 /*
2400 * The result of build_function_result_tupdesc_t has the right column
2401 * names, but it just has the declared output argument types, which is the
2402 * wrong thing in polymorphic cases. Get the correct types by examining
2403 * stmt->outargs. We intentionally keep the atttypmod as -1 and the
2404 * attcollation as the type's default, since that's always the appropriate
2405 * thing for function outputs; there's no point in considering any
2406 * additional info available from outargs. Note that tupdesc is null if
2407 * there are no outargs.
2408 */
2409 if (tupdesc)
2410 {
2411 Assert(tupdesc->natts == list_length(stmt->outargs));
2412 for (int i = 0; i < tupdesc->natts; i++)
2413 {
2414 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2415 Node *outarg = (Node *) list_nth(stmt->outargs, i);
2416
2417 TupleDescInitEntry(tupdesc,
2418 i + 1,
2419 NameStr(att->attname),
2420 exprType(outarg),
2421 -1,
2422 0);
2423 }
2424 }
2425
2426 return tupdesc;
2427}
TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple)
Definition: funcapi.c:1705
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
static int list_length(const List *l)
Definition: pg_list.h:152
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
Oid funcid
Definition: primnodes.h:767
Definition: nodes.h:135
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:835
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

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

Referenced by UtilityTupleDescriptor().

◆ CheckIndexCompatible()

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

Definition at line 178 of file indexcmds.c.

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

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 2604 of file indexcmds.c.

2607{
2608 int pass = 0;
2609 char *relname = NULL;
2610 char modlabel[NAMEDATALEN];
2611
2612 /* try the unmodified label first */
2613 strlcpy(modlabel, label, sizeof(modlabel));
2614
2615 for (;;)
2616 {
2617 relname = makeObjectName(name1, name2, modlabel);
2618
2619 if (!OidIsValid(get_relname_relid(relname, namespaceid)))
2620 {
2621 if (!isconstraint ||
2622 !ConstraintNameExists(relname, namespaceid))
2623 break;
2624 }
2625
2626 /* found a conflict, so try a new name component */
2627 pfree(relname);
2628 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2629 }
2630
2631 return relname;
2632}
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2518
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:2025
static char * label
NameData relname
Definition: pg_class.h:38
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition: port.h:239
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())
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 {
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
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:450
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
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:193
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109

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 1539 of file functioncmds.c.

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

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())
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)
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 */
660
661 /* Post creation hook for new foreign data wrapper */
662 InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
663
665
666 return myself;
667}
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition: foreign.c:96
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignServer()

ObjectAddress CreateForeignServer ( CreateForeignServerStmt stmt)

Definition at line 838 of file foreigncmds.c.

839{
840 Relation rel;
841 Datum srvoptions;
842 Datum values[Natts_pg_foreign_server];
843 bool nulls[Natts_pg_foreign_server];
844 HeapTuple tuple;
845 Oid srvId;
846 Oid ownerId;
847 AclResult aclresult;
848 ObjectAddress myself;
849 ObjectAddress referenced;
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 */
876 errmsg("server \"%s\" already exists, skipping",
877 stmt->servername)));
880 }
881 else
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 */
960
961 /* Post creation hook for new foreign server */
962 InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
963
965
966 return myself;
967}
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:704
@ OBJECT_FDW
Definition: parsenodes.h:2333
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:258
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
1478}
char * servername
Definition: foreign.h:39
void CommandCounterIncrement(void)
Definition: xact.c:1100

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 1026 of file functioncmds.c.

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

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{
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)
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))
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)
132 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
133 errmsg("cannot define statistics for relation \"%s\"",
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 */
145 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
146 errmsg("permission denied: \"%s\" is a system catalog",
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 */
187 errmsg("statistics object \"%s\" already exists, skipping",
188 namestr)));
191 }
192
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)
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))
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)
246 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
247 errmsg("statistics creation on system columns is not supported")));
248
249 /* Disallow use of virtual generated columns in extended stats */
250 if (attForm->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
252 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
253 errmsg("statistics creation on virtual generated columns is not supported")));
254
255 /* Disallow data types without a less-than operator */
256 type = lookup_type_cache(attForm->atttypid, TYPECACHE_LT_OPR);
257 if (type->lt_opr == InvalidOid)
259 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
260 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
261 attname, format_type_be(attForm->atttypid))));
262
263 attnums[nattnums] = attForm->attnum;
264 nattnums++;
265 ReleaseSysCache(atttuple);
266 }
267 else if (IsA(selem->expr, Var)) /* column reference in parens */
268 {
269 Var *var = (Var *) selem->expr;
271
272 /* Disallow use of system attributes in extended stats */
273 if (var->varattno <= 0)
275 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
276 errmsg("statistics creation on system columns is not supported")));
277
278 /* Disallow use of virtual generated columns in extended stats */
279 if (get_attgenerated(relid, var->varattno) == ATTRIBUTE_GENERATED_VIRTUAL)
281 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
282 errmsg("statistics creation on virtual generated columns is not supported")));
283
284 /* Disallow data types without a less-than operator */
285 type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
286 if (type->lt_opr == InvalidOid)
288 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
289 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
290 get_attname(relid, var->varattno, false), format_type_be(var->vartype))));
291
292 attnums[nattnums] = var->varattno;
293 nattnums++;
294 }
295 else /* expression */
296 {
297 Node *expr = selem->expr;
298 Oid atttype;
300 Bitmapset *attnums = NULL;
301 int k;
302
303 Assert(expr != NULL);
304
305 pull_varattnos(expr, 1, &attnums);
306
307 k = -1;
308 while ((k = bms_next_member(attnums, k)) >= 0)
309 {
311
312 /* Disallow expressions referencing system attributes. */
313 if (attnum <= 0)
315 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
316 errmsg("statistics creation on system columns is not supported")));
317
318 /* Disallow use of virtual generated columns in extended stats */
319 if (get_attgenerated(relid, attnum) == ATTRIBUTE_GENERATED_VIRTUAL)
321 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
322 errmsg("statistics creation on virtual generated columns is not supported")));
323 }
324
325 /*
326 * Disallow data types without a less-than operator.
327 *
328 * We ignore this for statistics on a single expression, in which
329 * case we'll build the regular statistics only (and that code can
330 * deal with such data types).
331 */
332 if (list_length(stmt->exprs) > 1)
333 {
334 atttype = exprType(expr);
336 if (type->lt_opr == InvalidOid)
338 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
339 errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
340 format_type_be(atttype))));
341 }
342
343 stxexprs = lappend(stxexprs, expr);
344 }
345 }
346
347 /*
348 * Parse the statistics kinds.
349 *
350 * First check that if this is the case with a single expression, there
351 * are no statistics kinds specified (we don't allow that for the simple
352 * CREATE STATISTICS form).
353 */
354 if ((list_length(stmt->exprs) == 1) && (list_length(stxexprs) == 1))
355 {
356 /* statistics kinds not specified */
357 if (stmt->stat_types != NIL)
359 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
360 errmsg("when building statistics on a single expression, statistics kinds may not be specified")));
361 }
362
363 /* OK, let's check that we recognize the statistics kinds. */
364 build_ndistinct = false;
365 build_dependencies = false;
366 build_mcv = false;
367 foreach(cell, stmt->stat_types)
368 {
369 char *type = strVal(lfirst(cell));
370
371 if (strcmp(type, "ndistinct") == 0)
372 {
373 build_ndistinct = true;
374 requested_type = true;
375 }
376 else if (strcmp(type, "dependencies") == 0)
377 {
378 build_dependencies = true;
379 requested_type = true;
380 }
381 else if (strcmp(type, "mcv") == 0)
382 {
383 build_mcv = true;
384 requested_type = true;
385 }
386 else
388 (errcode(ERRCODE_SYNTAX_ERROR),
389 errmsg("unrecognized statistics kind \"%s\"",
390 type)));
391 }
392
393 /*
394 * If no statistic type was specified, build them all (but only when the
395 * statistics is defined on more than one column/expression).
396 */
397 if ((!requested_type) && (numcols >= 2))
398 {
399 build_ndistinct = true;
400 build_dependencies = true;
401 build_mcv = true;
402 }
403
404 /*
405 * When there are non-trivial expressions, build the expression stats
406 * automatically. This allows calculating good estimates for stats that
407 * consider per-clause estimates (e.g. functional dependencies).
408 */
409 build_expressions = (stxexprs != NIL);
410
411 /*
412 * Check that at least two columns were specified in the statement, or
413 * that we're building statistics on a single expression.
414 */
415 if ((numcols < 2) && (list_length(stxexprs) != 1))
417 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
418 errmsg("extended statistics require at least 2 columns")));
419
420 /*
421 * Sort the attnums, which makes detecting duplicates somewhat easier, and
422 * it does not hurt (it does not matter for the contents, unlike for
423 * indexes, for example).
424 */
425 qsort(attnums, nattnums, sizeof(int16), compare_int16);
426
427 /*
428 * Check for duplicates in the list of columns. The attnums are sorted so
429 * just check consecutive elements.
430 */
431 for (i = 1; i < nattnums; i++)
432 {
433 if (attnums[i] == attnums[i - 1])
435 (errcode(ERRCODE_DUPLICATE_COLUMN),
436 errmsg("duplicate column name in statistics definition")));
437 }
438
439 /*
440 * Check for duplicate expressions. We do two loops, counting the
441 * occurrences of each expression. This is O(N^2) but we only allow small
442 * number of expressions and it's not executed often.
443 *
444 * XXX We don't cross-check attributes and expressions, because it does
445 * not seem worth it. In principle we could check that expressions don't
446 * contain trivial attribute references like "(a)", but the reasoning is
447 * similar to why we don't bother with extracting columns from
448 * expressions. It's either expensive or very easy to defeat for
449 * determined user, and there's no risk if we allow such statistics (the
450 * statistics is useless, but harmless).
451 */
452 foreach(cell, stxexprs)
453 {
454 Node *expr1 = (Node *) lfirst(cell);
455 int cnt = 0;
456
457 foreach(cell2, stxexprs)
458 {
459 Node *expr2 = (Node *) lfirst(cell2);
460
461 if (equal(expr1, expr2))
462 cnt += 1;
463 }
464
465 /* every expression should find at least itself */
466 Assert(cnt >= 1);
467
468 if (cnt > 1)
470 (errcode(ERRCODE_DUPLICATE_COLUMN),
471 errmsg("duplicate expression in statistics definition")));
472 }
473
474 /* Form an int2vector representation of the sorted column list */
475 stxkeys = buildint2vector(attnums, nattnums);
476
477 /* construct the char array of enabled statistic types */
478 ntypes = 0;
479 if (build_ndistinct)
480 types[ntypes++] = CharGetDatum(STATS_EXT_NDISTINCT);
481 if (build_dependencies)
482 types[ntypes++] = CharGetDatum(STATS_EXT_DEPENDENCIES);
483 if (build_mcv)
484 types[ntypes++] = CharGetDatum(STATS_EXT_MCV);
485 if (build_expressions)
486 types[ntypes++] = CharGetDatum(STATS_EXT_EXPRESSIONS);
487 Assert(ntypes > 0 && ntypes <= lengthof(types));
488 stxkind = construct_array_builtin(types, ntypes, CHAROID);
489
490 /* convert the expressions (if any) to a text datum */
491 if (stxexprs != NIL)
492 {
493 char *exprsString;
494
495 exprsString = nodeToString(stxexprs);
496 exprsDatum = CStringGetTextDatum(exprsString);
497 pfree(exprsString);
498 }
499 else
500 exprsDatum = (Datum) 0;
501
502 statrel = table_open(StatisticExtRelationId, RowExclusiveLock);
503
504 /*
505 * Everything seems fine, so let's build the pg_statistic_ext tuple.
506 */
507 memset(values, 0, sizeof(values));
508 memset(nulls, false, sizeof(nulls));
509
510 statoid = GetNewOidWithIndex(statrel, StatisticExtOidIndexId,
511 Anum_pg_statistic_ext_oid);
512 values[Anum_pg_statistic_ext_oid - 1] = ObjectIdGetDatum(statoid);
513 values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
514 values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
515 values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
516 values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
517 values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
518 nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
519 values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
520
521 values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum;
522 if (exprsDatum == (Datum) 0)
523 nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
524
525 /* insert it into pg_statistic_ext */
526 htup = heap_form_tuple(statrel->rd_att, values, nulls);
527 CatalogTupleInsert(statrel, htup);
528 heap_freetuple(htup);
529
531
532 /*
533 * We used to create the pg_statistic_ext_data tuple too, but it's not
534 * clear what value should the stxdinherit flag have (it depends on
535 * whether the rel is partitioned, contains data, etc.)
536 */
537
538 InvokeObjectPostCreateHook(StatisticExtRelationId, statoid, 0);
539
540 /*
541 * Invalidate relcache so that others see the new statistics object.
542 */
544
546
547 /*
548 * Add an AUTO dependency on each column used in the stats, so that the
549 * stats object goes away if any or all of them get dropped.
550 */
551 ObjectAddressSet(myself, StatisticExtRelationId, statoid);
552
553 /* add dependencies for plain column references */
554 for (i = 0; i < nattnums; i++)
555 {
556 ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
557 recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
558 }
559
560 /*
561 * If there are no dependencies on a column, give the statistics object an
562 * auto dependency on the whole table. In most cases, this will be
563 * redundant, but it might not be if the statistics expressions contain no
564 * Vars (which might seem strange but possible). This is consistent with
565 * what we do for indexes in index_create.
566 *
567 * XXX We intentionally don't consider the expressions before adding this
568 * dependency, because recordDependencyOnSingleRelExpr may not create any
569 * dependencies for whole-row Vars.
570 */
571 if (!nattnums)
572 {
573 ObjectAddressSet(parentobject, RelationRelationId, relid);
574 recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
575 }
576
577 /*
578 * Store dependencies on anything mentioned in statistics expressions,
579 * just like we do for index expressions.
580 */
581 if (stxexprs)
583 (Node *) stxexprs,
584 relid,
586 DEPENDENCY_AUTO, false);
587
588 /*
589 * Also add dependencies on namespace and owner. These are required
590 * because the stats object might have a different namespace and/or owner
591 * than the underlying table(s).
592 */
593 ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
594 recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
595
596 recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
597
598 /*
599 * XXX probably there should be a recordDependencyOnCurrentExtension call
600 * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
601 * STATISTICS, which is more work than it seems worth.
602 */
603
604 /* Add any requested comment */
605 if (stmt->stxcomment != NULL)
606 CreateComments(statoid, StatisticExtRelationId, 0,
607 stmt->stxcomment);
608
609 /* Return stats object's address */
610 return myself;
611}
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:759
bool IsSystemRelation(Relation relation)
Definition: catalog.c:74
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1596
@ DEPENDENCY_AUTO
Definition: dependency.h:34
struct typedefs * types
Definition: ecpg.c:30
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
bool allowSystemTableMods
Definition: globals.c:131
int2vector * buildint2vector(const int16 *int2s, int n)
Definition: int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition: inval.c:1631
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:980
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:919
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
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:797
NameData attname
Definition: pg_attribute.h:41
int16 attnum
Definition: pg_attribute.h:74
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define qsort(a, b, c, d)
Definition: port.h:479
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
#define RelationGetRelid(relation)
Definition: rel.h:516
#define RelationGetRelationName(relation)
Definition: rel.h:550
#define RelationGetNamespace(relation)
Definition: rel.h:557
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:869
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: statscmds.c:827
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:3501
Node * expr
Definition: parsenodes.h:3502
Definition: primnodes.h:262
AttrNumber varattno
Definition: primnodes.h:274
Definition: c.h:686
Definition: c.h:712
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition: syscache.c:480
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_LT_OPR
Definition: typcache.h:139
#define strVal(v)
Definition: value.h:82
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296
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_attgenerated(), 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 1832 of file functioncmds.c.

1833{
1834 Oid typeid;
1835 char typtype;
1836 Oid langid;
1837 Oid fromsqlfuncid;
1838 Oid tosqlfuncid;
1839 AclResult aclresult;
1840 Form_pg_proc procstruct;
1841 Datum values[Natts_pg_transform];
1842 bool nulls[Natts_pg_transform] = {0};
1843 bool replaces[Natts_pg_transform] = {0};
1844 Oid transformid;
1845 HeapTuple tuple;
1846 HeapTuple newtuple;
1847 Relation relation;
1848 ObjectAddress myself,
1849 referenced;
1850 ObjectAddresses *addrs;
1851 bool is_replace;
1852
1853 /*
1854 * Get the type
1855 */
1856 typeid = typenameTypeId(NULL, stmt->type_name);
1857 typtype = get_typtype(typeid);
1858
1859 if (typtype == TYPTYPE_PSEUDO)
1860 ereport(ERROR,
1861 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1862 errmsg("data type %s is a pseudo-type",
1863 TypeNameToString(stmt->type_name))));
1864
1865 if (typtype == TYPTYPE_DOMAIN)
1866 ereport(ERROR,
1867 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1868 errmsg("data type %s is a domain",
1869 TypeNameToString(stmt->type_name))));
1870
1871 if (!object_ownercheck(TypeRelationId, typeid, GetUserId()))
1873
1874 aclresult = object_aclcheck(TypeRelationId, typeid, GetUserId(), ACL_USAGE);
1875 if (aclresult != ACLCHECK_OK)
1876 aclcheck_error_type(aclresult, typeid);
1877
1878 /*
1879 * Get the language
1880 */
1881 langid = get_language_oid(stmt->lang, false);
1882
1883 aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE);
1884 if (aclresult != ACLCHECK_OK)
1885 aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang);
1886
1887 /*
1888 * Get the functions
1889 */
1890 if (stmt->fromsql)
1891 {
1892 fromsqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->fromsql, false);
1893
1894 if (!object_ownercheck(ProcedureRelationId, fromsqlfuncid, GetUserId()))
1896
1897 aclresult = object_aclcheck(ProcedureRelationId, fromsqlfuncid, GetUserId(), ACL_EXECUTE);
1898 if (aclresult != ACLCHECK_OK)
1899 aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->fromsql->objname));
1900
1901 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(fromsqlfuncid));
1902 if (!HeapTupleIsValid(tuple))
1903 elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1904 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1905 if (procstruct->prorettype != INTERNALOID)
1906 ereport(ERROR,
1907 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1908 errmsg("return data type of FROM SQL function must be %s",
1909 "internal")));
1910 check_transform_function(procstruct);
1911 ReleaseSysCache(tuple);
1912 }
1913 else
1914 fromsqlfuncid = InvalidOid;
1915
1916 if (stmt->tosql)
1917 {
1918 tosqlfuncid = LookupFuncWithArgs(OBJECT_FUNCTION, stmt->tosql, false);
1919
1920 if (!object_ownercheck(ProcedureRelationId, tosqlfuncid, GetUserId()))
1922
1923 aclresult = object_aclcheck(ProcedureRelationId, tosqlfuncid, GetUserId(), ACL_EXECUTE);
1924 if (aclresult != ACLCHECK_OK)
1925 aclcheck_error(aclresult, OBJECT_FUNCTION, NameListToString(stmt->tosql->objname));
1926
1927 tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(tosqlfuncid));
1928 if (!HeapTupleIsValid(tuple))
1929 elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1930 procstruct = (Form_pg_proc) GETSTRUCT(tuple);
1931 if (procstruct->prorettype != typeid)
1932 ereport(ERROR,
1933 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1934 errmsg("return data type of TO SQL function must be the transform data type")));
1935 check_transform_function(procstruct);
1936 ReleaseSysCache(tuple);
1937 }
1938 else
1939 tosqlfuncid = InvalidOid;
1940
1941 /*
1942 * Ready to go
1943 */
1944 values[Anum_pg_transform_trftype - 1] = ObjectIdGetDatum(typeid);
1945 values[Anum_pg_transform_trflang - 1] = ObjectIdGetDatum(langid);
1946 values[Anum_pg_transform_trffromsql - 1] = ObjectIdGetDatum(fromsqlfuncid);
1947 values[Anum_pg_transform_trftosql - 1] = ObjectIdGetDatum(tosqlfuncid);
1948
1949 relation = table_open(TransformRelationId, RowExclusiveLock);
1950
1951 tuple = SearchSysCache2(TRFTYPELANG,
1952 ObjectIdGetDatum(typeid),
1953 ObjectIdGetDatum(langid));
1954 if (HeapTupleIsValid(tuple))
1955 {
1957
1958 if (!stmt->replace)
1959 ereport(ERROR,
1961 errmsg("transform for type %s language \"%s\" already exists",
1962 format_type_be(typeid),
1963 stmt->lang)));
1964
1965 replaces[Anum_pg_transform_trffromsql - 1] = true;
1966 replaces[Anum_pg_transform_trftosql - 1] = true;
1967
1968 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1969 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1970
1971 transformid = form->oid;
1972 ReleaseSysCache(tuple);
1973 is_replace = true;
1974 }
1975 else
1976 {
1977 transformid = GetNewOidWithIndex(relation, TransformOidIndexId,
1978 Anum_pg_transform_oid);
1979 values[Anum_pg_transform_oid - 1] = ObjectIdGetDatum(transformid);
1980 newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1981 CatalogTupleInsert(relation, newtuple);
1982 is_replace = false;
1983 }
1984
1985 if (is_replace)
1986 deleteDependencyRecordsFor(TransformRelationId, transformid, true);
1987
1988 addrs = new_object_addresses();
1989
1990 /* make dependency entries */
1991 ObjectAddressSet(myself, TransformRelationId, transformid);
1992
1993 /* dependency on language */
1994 ObjectAddressSet(referenced, LanguageRelationId, langid);
1995 add_exact_object_address(&referenced, addrs);
1996
1997 /* dependency on type */
1998 ObjectAddressSet(referenced, TypeRelationId, typeid);
1999 add_exact_object_address(&referenced, addrs);
2000
2001 /* dependencies on functions */
2002 if (OidIsValid(fromsqlfuncid))
2003 {
2004 ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
2005 add_exact_object_address(&referenced, addrs);
2006 }
2007 if (OidIsValid(tosqlfuncid))
2008 {
2009 ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
2010 add_exact_object_address(&referenced, addrs);
2011 }
2012
2014 free_object_addresses(addrs);
2015
2016 /* dependency on extension */
2017 recordDependencyOnCurrentExtension(&myself, is_replace);
2018
2019 /* Post creation hook for new transform */
2020 InvokeObjectPostCreateHook(TransformRelationId, transformid, 0);
2021
2022 heap_freetuple(newtuple);
2023
2024 table_close(relation, RowExclusiveLock);
2025
2026 return myself;
2027}
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
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:301
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:232

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),
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 */
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 94 of file define.c.

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

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

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

◆ defGetInt32()

int32 defGetInt32 ( DefElem def)

Definition at line 149 of file define.c.

150{
151 if (def->arg == NULL)
153 (errcode(ERRCODE_SYNTAX_ERROR),
154 errmsg("%s requires an integer value",
155 def->defname)));
156 switch (nodeTag(def->arg))
157 {
158 case T_Integer:
159 return (int32) intVal(def->arg);
160 default:
162 (errcode(ERRCODE_SYNTAX_ERROR),
163 errmsg("%s requires an integer value",
164 def->defname)));
165 }
166 return 0; /* keep compiler quiet */
167}
int32_t int32
Definition: c.h:498

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

174{
175 if (def->arg == NULL)
177 (errcode(ERRCODE_SYNTAX_ERROR),
178 errmsg("%s requires a numeric value",
179 def->defname)));
180 switch (nodeTag(def->arg))
181 {
182 case T_Integer:
183 return (int64) intVal(def->arg);
184 case T_Float:
185
186 /*
187 * Values too large for int4 will be represented as Float
188 * constants by the lexer. Accept these if they are valid int8
189 * strings.
190 */
192 CStringGetDatum(castNode(Float, def->arg)->fval)));
193 default:
195 (errcode(ERRCODE_SYNTAX_ERROR),
196 errmsg("%s requires a numeric value",
197 def->defname)));
198 }
199 return 0; /* keep compiler quiet */
200}
int64_t int64
Definition: c.h:499
Datum int8in(PG_FUNCTION_ARGS)
Definition: int8.c:50
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:390
Definition: value.h:48

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

Referenced by defGetCopyRejectLimitOption(), init_params(), and parse_basebackup_options().

◆ defGetNumeric()

double defGetNumeric ( DefElem def)

Definition at line 68 of file define.c.

69{
70 if (def->arg == NULL)
72 (errcode(ERRCODE_SYNTAX_ERROR),
73 errmsg("%s requires a numeric value",
74 def->defname)));
75 switch (nodeTag(def->arg))
76 {
77 case T_Integer:
78 return (double) intVal(def->arg);
79 case T_Float:
80 return floatVal(def->arg);
81 default:
83 (errcode(ERRCODE_SYNTAX_ERROR),
84 errmsg("%s requires a numeric value",
85 def->defname)));
86 }
87 return 0; /* keep compiler quiet */
88}
#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 206 of file define.c.

207{
208 if (def->arg == NULL)
210 (errcode(ERRCODE_SYNTAX_ERROR),
211 errmsg("%s requires a numeric value",
212 def->defname)));
213 switch (nodeTag(def->arg))
214 {
215 case T_Integer:
216 return (Oid) intVal(def->arg);
217 case T_Float:
218
219 /*
220 * Values too large for int4 will be represented as Float
221 * constants by the lexer. Accept these if they are valid OID
222 * strings.
223 */
225 CStringGetDatum(castNode(Float, def->arg)->fval)));
226 default:
228 (errcode(ERRCODE_SYNTAX_ERROR),
229 errmsg("%s requires a numeric value",
230 def->defname)));
231 }
232 return 0; /* keep compiler quiet */
233}
Datum oidin(PG_FUNCTION_ARGS)
Definition: oid.c:37
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:247

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

240{
241 if (def->arg == NULL)
243 (errcode(ERRCODE_SYNTAX_ERROR),
244 errmsg("%s requires a parameter",
245 def->defname)));
246 switch (nodeTag(def->arg))
247 {
248 case T_TypeName:
249 return ((TypeName *) def->arg)->names;
250 case T_List:
251 return (List *) def->arg;
252 case T_String:
253 /* Allow quoted name for backwards compatibility */
254 return list_make1(def->arg);
255 default:
257 (errcode(ERRCODE_SYNTAX_ERROR),
258 errmsg("argument of %s must be a name",
259 def->defname)));
260 }
261 return NIL; /* keep compiler quiet */
262}
#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 35 of file define.c.

36{
37 if (def->arg == NULL)
39 (errcode(ERRCODE_SYNTAX_ERROR),
40 errmsg("%s requires a parameter",
41 def->defname)));
42 switch (nodeTag(def->arg))
43 {
44 case T_Integer:
45 return psprintf("%ld", (long) intVal(def->arg));
46 case T_Float:
47 return castNode(Float, def->arg)->fval;
48 case T_Boolean:
49 return boolVal(def->arg) ? "true" : "false";
50 case T_String:
51 return strVal(def->arg);
52 case T_TypeName:
53 return TypeNameToString((TypeName *) def->arg);
54 case T_List:
55 return NameListToString((List *) def->arg);
56 case T_A_Star:
57 return pstrdup("*");
58 default:
59 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
60 }
61 return NULL; /* keep compiler quiet */
62}
char * pstrdup(const char *in)
Definition: mcxt.c:2322
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

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(), defGetGeneratedColsOption(), defGetStreamingMode(), defGetTypeLength(), DefineAggregate(), DefineCollation(), DefineType(), deparseAnalyzeSql(), deparseColumnRef(), deparseRelation(), dintdict_init(), dispell_init(), dsimple_init(), dsnowball_init(), dsynonym_init(), dxsyn_init(), ExecReindex(), ExecVacuum(), 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(), ParseExplainOptionList(), postgres_fdw_validator(), postgresAcquireSampleRowsFunc(), ProcessCopyOptions(), prsd_headline(), serialize_deflist(), thesaurus_init(), transformRelOptions(), and unaccent_init().

◆ defGetStringList()

List * defGetStringList ( DefElem def)

Definition at line 343 of file define.c.

344{
345 ListCell *cell;
346
347 if (def->arg == NULL)
349 (errcode(ERRCODE_SYNTAX_ERROR),
350 errmsg("%s requires a parameter",
351 def->defname)));
352 if (nodeTag(def->arg) != T_List)
353 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
354
355 foreach(cell, (List *) def->arg)
356 {
357 Node *str = (Node *) lfirst(cell);
358
359 if (!IsA(str, String))
360 elog(ERROR, "unexpected node type in name list: %d",
361 (int) nodeTag(str));
362 }
363
364 return (List *) def->arg;
365}
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 299 of file define.c.

300{
301 if (def->arg == NULL)
303 (errcode(ERRCODE_SYNTAX_ERROR),
304 errmsg("%s requires a parameter",
305 def->defname)));
306 switch (nodeTag(def->arg))
307 {
308 case T_Integer:
309 return intVal(def->arg);
310 case T_Float:
312 (errcode(ERRCODE_SYNTAX_ERROR),
313 errmsg("%s requires an integer value",
314 def->defname)));
315 break;
316 case T_String:
317 if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
318 return -1; /* variable length */
319 break;
320 case T_TypeName:
321 /* cope if grammar chooses to believe "variable" is a typename */
323 "variable") == 0)
324 return -1; /* variable length */
325 break;
326 case T_List:
327 /* must be an operator name */
328 break;
329 default:
330 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
331 }
333 (errcode(ERRCODE_SYNTAX_ERROR),
334 errmsg("invalid argument for %s: \"%s\"",
335 def->defname, defGetString(def))));
336 return 0; /* keep compiler quiet */
337}

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

272{
273 if (def->arg == NULL)
275 (errcode(ERRCODE_SYNTAX_ERROR),
276 errmsg("%s requires a parameter",
277 def->defname)));
278 switch (nodeTag(def->arg))
279 {
280 case T_TypeName:
281 return (TypeName *) def->arg;
282 case T_String:
283 /* Allow quoted typename for backwards compatibility */
285 default:
287 (errcode(ERRCODE_SYNTAX_ERROR),
288 errmsg("argument of %s must be a type name",
289 def->defname)));
290 }
291 return NULL; /* keep compiler quiet */
292}
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531

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)
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)
201 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
202 errmsg("aggregate stype must be specified")));
203 if (transfuncName == NIL)
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)
217 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
218 errmsg("aggregate msfunc must be specified when mstype is specified")));
219 if (minvtransfuncName == NIL)
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)
228 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
229 errmsg("aggregate msfunc must not be specified without mstype")));
230 if (minvtransfuncName != NIL)
232 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
233 errmsg("aggregate minvfunc must not be specified without mstype")));
234 if (mfinalfuncName != NIL)
236 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
237 errmsg("aggregate mfinalfunc must not be specified without mstype")));
238 if (mtransSpace != 0)
240 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
241 errmsg("aggregate msspace must not be specified without mstype")));
242 if (minitval != NULL)
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)
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)
303 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
304 errmsg("basetype is redundant with aggregate input type specification")));
305
306 numArgs = list_length(args);
308 args,
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
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)
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 */
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
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
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)
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:271
int32 defGetInt32(DefElem *def)
Definition: define.c:149
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:3014
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2318
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 542 of file indexcmds.c.

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

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(), bms_next_member(), BTEqualStrategyNumber, build_attrmap_by_name(), BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CatalogTupleUpdate(), CheckPredicate(), CheckTableNotInUse(), ChooseIndexColumnNames(), ChooseIndexName(), CommandCounterIncrement(), CommitTransactionCommand(), COMPARE_EQ, CompareIndexInfo(), ComputeIndexAttrs(), ConstraintSetParentConstraint(), CreateComments(), LockRelId::dbId, DEBUG1, DefineIndex(), elog, ereport, errcode(), errdetail(), errdetail_relkind_not_supported(), errmsg(), errmsg_internal(), ERROR, find_all_inheritors(), FirstLowInvalidHeapAttributeNumber, format_type_be(), free_attrmap(), generateClonedIndexStmt(), get_am_name(), get_index_isvalid(), get_namespace_name(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_opfamily_member_for_cmptype(), get_opfamily_method(), get_opfamily_name(), 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, 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(), IndexSetParentIndex(), InvalidOid, InvalidTransactionId, IsBootstrapProcessingMode, j, sort-test::key, lfirst_oid, list_concat_copy(), list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeIndexInfo(), MyDatabaseTableSpace, MyProc, NameStr, NewGUCNestLevel(), NIL, NoLock, NOTICE, PartitionDescData::nparts, object_aclcheck(), OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, PartitionDescData::oids, 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(), 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(), PGPROC::xmin, and SnapshotData::xmin.

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

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

Definition at line 333 of file opclasscmds.c.

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

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)
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)
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)
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)
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))
182 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
183 errmsg("operator argument types must be specified")));
184 if (!OidIsValid(typeId2))
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)
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:1795
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2144
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:281

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 772 of file opclasscmds.c.

773{
774 char *opfname; /* name of opfamily we're creating */
775 Oid amoid, /* our AM's oid */
776 namespaceoid; /* namespace to create opfamily in */
777 AclResult aclresult;
778
779 /* Convert list of names to a name and namespace */
780 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
781 &opfname);
782
783 /* Check we have creation rights in target namespace */
784 aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
785 if (aclresult != ACLCHECK_OK)
786 aclcheck_error(aclresult, OBJECT_SCHEMA,
787 get_namespace_name(namespaceoid));
788
789 /* Get access method OID, throwing an error if it doesn't exist. */
790 amoid = get_index_am_oid(stmt->amname, false);
791
792 /* XXX Should we make any privilege check against the AM? */
793
794 /*
795 * Currently, we require superuser privileges to create an opfamily. See
796 * comments in DefineOpClass.
797 */
798 if (!superuser())
800 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
801 errmsg("must be superuser to create an operator family")));
802
803 /* Insert pg_opfamily catalog entry */
804 return CreateOpFamily(stmt, opfname, namespaceoid, amoid);
805}
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;
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
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))
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 {
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))
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,
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)
1100
1101 return address;
1102}
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1427
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1443
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1741
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
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:2716
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:3152
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:458

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))
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] =
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
485
486 return address;
487}
Oid get_ts_template_oid(List *names, bool missing_ok)
Definition: namespace.c:3007
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())
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
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])))
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])))
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])))
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])))
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
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())
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
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])))
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
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:658
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:225

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()

◆ ExecReindex()

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

Definition at line 2790 of file indexcmds.c.

2791{
2792 ReindexParams params = {0};
2793 ListCell *lc;
2794 bool concurrently = false;
2795 bool verbose = false;
2796 char *tablespacename = NULL;
2797
2798 /* Parse option list */
2799 foreach(lc, stmt->params)
2800 {
2801 DefElem *opt = (DefElem *) lfirst(lc);
2802
2803 if (strcmp(opt->defname, "verbose") == 0)
2804 verbose = defGetBoolean(opt);
2805 else if (strcmp(opt->defname, "concurrently") == 0)
2806 concurrently = defGetBoolean(opt);
2807 else if (strcmp(opt->defname, "tablespace") == 0)
2808 tablespacename = defGetString(opt);
2809 else
2810 ereport(ERROR,
2811 (errcode(ERRCODE_SYNTAX_ERROR),
2812 errmsg("unrecognized REINDEX option \"%s\"",
2813 opt->defname),
2814 parser_errposition(pstate, opt->location)));
2815 }
2816
2817 if (concurrently)
2818 PreventInTransactionBlock(isTopLevel,
2819 "REINDEX CONCURRENTLY");
2820
2821 params.options =
2822 (verbose ? REINDEXOPT_VERBOSE : 0) |
2823 (concurrently ? REINDEXOPT_CONCURRENTLY : 0);
2824
2825 /*
2826 * Assign the tablespace OID to move indexes to, with InvalidOid to do
2827 * nothing.
2828 */
2829 if (tablespacename != NULL)
2830 {
2831 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
2832
2833 /* Check permissions except when moving to database's default */
2834 if (OidIsValid(params.tablespaceOid) &&
2836 {
2837 AclResult aclresult;
2838
2839 aclresult = object_aclcheck(TableSpaceRelationId, params.tablespaceOid,
2841 if (aclresult != ACLCHECK_OK)
2844 }
2845 }
2846 else
2847 params.tablespaceOid = InvalidOid;
2848
2849 switch (stmt->kind)
2850 {
2852 ReindexIndex(stmt, &params, isTopLevel);
2853 break;
2855 ReindexTable(stmt, &params, isTopLevel);
2856 break;
2860
2861 /*
2862 * This cannot run inside a user transaction block; if we were
2863 * inside a transaction, then its commit- and
2864 * start-transaction-command calls would not have the intended
2865 * effect!
2866 */
2867 PreventInTransactionBlock(isTopLevel,
2868 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
2869 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
2870 "REINDEX DATABASE");
2871 ReindexMultipleTables(stmt, &params);
2872 break;
2873 default:
2874 elog(ERROR, "unrecognized object type: %d",
2875 (int) stmt->kind);
2876 break;
2877 }
2878}
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:2885
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition: indexcmds.c:3074
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition: indexcmds.c:3015
@ REINDEX_OBJECT_DATABASE
Definition: parsenodes.h:4067
@ REINDEX_OBJECT_INDEX
Definition: parsenodes.h:4063
@ REINDEX_OBJECT_SCHEMA
Definition: parsenodes.h:4065
@ REINDEX_OBJECT_SYSTEM
Definition: parsenodes.h:4066
@ REINDEX_OBJECT_TABLE
Definition: parsenodes.h:4064
Oid tablespaceOid
Definition: index.h:36
bits32 options
Definition: index.h:35
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3648

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 2206 of file functioncmds.c.

2207{
2208 LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS);
2209 ListCell *lc;
2210 FuncExpr *fexpr;
2211 int nargs;
2212 int i;
2213 AclResult aclresult;
2214 FmgrInfo flinfo;
2215 CallContext *callcontext;
2216 EState *estate;
2217 ExprContext *econtext;
2218 HeapTuple tp;
2220 Datum retval;
2221
2222 fexpr = stmt->funcexpr;
2223 Assert(fexpr);
2224 Assert(IsA(fexpr, FuncExpr));
2225
2226 aclresult = object_aclcheck(ProcedureRelationId, fexpr->funcid, GetUserId(), ACL_EXECUTE);
2227 if (aclresult != ACLCHECK_OK)
2229
2230 /* Prep the context object we'll pass to the procedure */
2231 callcontext = makeNode(CallContext);
2232 callcontext->atomic = atomic;
2233
2234 tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(fexpr->funcid));
2235 if (!HeapTupleIsValid(tp))
2236 elog(ERROR, "cache lookup failed for function %u", fexpr->funcid);
2237
2238 /*
2239 * If proconfig is set we can't allow transaction commands because of the
2240 * way the GUC stacking works: The transaction boundary would have to pop
2241 * the proconfig setting off the stack. That restriction could be lifted
2242 * by redesigning the GUC nesting mechanism a bit.
2243 */
2244 if (!heap_attisnull(tp, Anum_pg_proc_proconfig, NULL))
2245 callcontext->atomic = true;
2246
2247 /*
2248 * In security definer procedures, we can't allow transaction commands.
2249 * StartTransaction() insists that the security context stack is empty,
2250 * and AbortTransaction() resets the security context. This could be
2251 * reorganized, but right now it doesn't work.
2252 */
2253 if (((Form_pg_proc) GETSTRUCT(tp))->prosecdef)
2254 callcontext->atomic = true;
2255
2256 ReleaseSysCache(tp);
2257
2258 /* safety check; see ExecInitFunc() */
2259 nargs = list_length(fexpr->args);
2260 if (nargs > FUNC_MAX_ARGS)
2261 ereport(ERROR,
2262 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2263 errmsg_plural("cannot pass more than %d argument to a procedure",
2264 "cannot pass more than %d arguments to a procedure",
2266 FUNC_MAX_ARGS)));
2267
2268 /* Initialize function call structure */
2270 fmgr_info(fexpr->funcid, &flinfo);
2271 fmgr_info_set_expr((Node *) fexpr, &flinfo);
2272 InitFunctionCallInfoData(*fcinfo, &flinfo, nargs, fexpr->inputcollid,
2273 (Node *) callcontext, NULL);
2274
2275 /*
2276 * Evaluate procedure arguments inside a suitable execution context. Note
2277 * we can't free this context till the procedure returns.
2278 */
2279 estate = CreateExecutorState();
2280 estate->es_param_list_info = params;
2281 econtext = CreateExprContext(estate);
2282
2283 /*
2284 * If we're called in non-atomic context, we also have to ensure that the
2285 * argument expressions run with an up-to-date snapshot. Our caller will
2286 * have provided a current snapshot in atomic contexts, but not in
2287 * non-atomic contexts, because the possibility of a COMMIT/ROLLBACK
2288 * destroying the snapshot makes higher-level management too complicated.
2289 */
2290 if (!atomic)
2292
2293 i = 0;
2294 foreach(lc, fexpr->args)
2295 {
2296 ExprState *exprstate;
2297 Datum val;
2298 bool isnull;
2299
2300 exprstate = ExecPrepareExpr(lfirst(lc), estate);
2301
2302 val = ExecEvalExprSwitchContext(exprstate, econtext, &isnull);
2303
2304 fcinfo->args[i].value = val;
2305 fcinfo->args[i].isnull = isnull;
2306
2307 i++;
2308 }
2309
2310 /* Get rid of temporary snapshot for arguments, if we made one */
2311 if (!atomic)
2313
2314 /* Here we actually call the procedure */
2315 pgstat_init_function_usage(fcinfo, &fcusage);
2316 retval = FunctionCallInvoke(fcinfo);
2317 pgstat_end_function_usage(&fcusage, true);
2318
2319 /* Handle the procedure's outputs */
2320 if (fexpr->funcresulttype == VOIDOID)
2321 {
2322 /* do nothing */
2323 }
2324 else if (fexpr->funcresulttype == RECORDOID)
2325 {
2326 /* send tuple to client */
2327 HeapTupleHeader td;
2328 Oid tupType;
2329 int32 tupTypmod;
2330 TupleDesc retdesc;
2331 HeapTupleData rettupdata;
2332 TupOutputState *tstate;
2333 TupleTableSlot *slot;
2334
2335 if (fcinfo->isnull)
2336 elog(ERROR, "procedure returned null record");
2337
2338 /*
2339 * Ensure there's an active snapshot whilst we execute whatever's
2340 * involved here. Note that this is *not* sufficient to make the
2341 * world safe for TOAST pointers to be included in the returned data:
2342 * the referenced data could have gone away while we didn't hold a
2343 * snapshot. Hence, it's incumbent on PLs that can do COMMIT/ROLLBACK
2344 * to not return TOAST pointers, unless those pointers were fetched
2345 * after the last COMMIT/ROLLBACK in the procedure.
2346 *
2347 * XXX that is a really nasty, hard-to-test requirement. Is there a
2348 * way to remove it?
2349 */
2351
2352 td = DatumGetHeapTupleHeader(retval);
2353 tupType = HeapTupleHeaderGetTypeId(td);
2354 tupTypmod = HeapTupleHeaderGetTypMod(td);
2355 retdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
2356
2357 tstate = begin_tup_output_tupdesc(dest, retdesc,
2359
2360 rettupdata.t_len = HeapTupleHeaderGetDatumLength(td);
2361 ItemPointerSetInvalid(&(rettupdata.t_self));
2362 rettupdata.t_tableOid = InvalidOid;
2363 rettupdata.t_data = td;
2364
2365 slot = ExecStoreHeapTuple(&rettupdata, tstate->slot, false);
2366 tstate->dest->receiveSlot(slot, tstate->dest);
2367
2368 end_tup_output(tstate);
2369
2370 ReleaseTupleDesc(retdesc);
2371 }
2372 else
2373 elog(ERROR, "unexpected result type for procedure: %u",
2374 fexpr->funcresulttype);
2375
2376 FreeExecutorState(estate);
2377}
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1181
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2522
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2444
TupleTableSlot * ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1541
ExprContext * CreateExprContext(EState *estate)
Definition: execUtils.c:308
void FreeExecutorState(EState *estate)
Definition: execUtils.c:193
EState * CreateExecutorState(void)
Definition: execUtils.c:88
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:458
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
static int32 HeapTupleHeaderGetTypMod(const HeapTupleHeaderData *tup)
Definition: htup_details.h:516
static uint32 HeapTupleHeaderGetDatumLength(const HeapTupleHeaderData *tup)
Definition: htup_details.h:492
static Oid HeapTupleHeaderGetTypeId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:504
long val
Definition: informix.c:689
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:1813
ParamListInfo es_param_list_info
Definition: execnodes.h:702
Definition: fmgr.h:57
List * args
Definition: primnodes.h:785
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:634
DestReceiver * dest
Definition: executor.h:635
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:219
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1922

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 2084 of file functioncmds.c.

2085{
2087 ListCell *arg;
2088 DefElem *as_item = NULL;
2089 DefElem *language_item = NULL;
2090 char *language;
2091 Oid laninline;
2092 HeapTuple languageTuple;
2093 Form_pg_language languageStruct;
2094
2095 /* Process options we got from gram.y */
2096 foreach(arg, stmt->args)
2097 {
2098 DefElem *defel = (DefElem *) lfirst(arg);
2099
2100 if (strcmp(defel->defname, "as") == 0)
2101 {
2102 if (as_item)
2103 errorConflictingDefElem(defel, pstate);
2104 as_item = defel;
2105 }
2106 else if (strcmp(defel->defname, "language") == 0)
2107 {
2108 if (language_item)
2109 errorConflictingDefElem(defel, pstate);
2110 language_item = defel;
2111 }
2112 else
2113 elog(ERROR, "option \"%s\" not recognized",
2114 defel->defname);
2115 }
2116
2117 if (as_item)
2118 codeblock->source_text = strVal(as_item->arg);
2119 else
2120 ereport(ERROR,
2121 (errcode(ERRCODE_SYNTAX_ERROR),
2122 errmsg("no inline code specified")));
2123
2124 /* if LANGUAGE option wasn't specified, use the default */
2125 if (language_item)
2126 language = strVal(language_item->arg);
2127 else
2128 language = "plpgsql";
2129
2130 /* Look up the language and validate permissions */
2131 languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
2132 if (!HeapTupleIsValid(languageTuple))
2133 ereport(ERROR,
2134 (errcode(ERRCODE_UNDEFINED_OBJECT),
2135 errmsg("language \"%s\" does not exist", language),
2136 (extension_file_exists(language) ?
2137 errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
2138
2139 languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
2140 codeblock->langOid = languageStruct->oid;
2141 codeblock->langIsTrusted = languageStruct->lanpltrusted;
2142 codeblock->atomic = atomic;
2143
2144 if (languageStruct->lanpltrusted)
2145 {
2146 /* if trusted language, need USAGE privilege */
2147 AclResult aclresult;
2148
2149 aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(),
2150 ACL_USAGE);
2151 if (aclresult != ACLCHECK_OK)
2153 NameStr(languageStruct->lanname));
2154 }
2155 else
2156 {
2157 /* if untrusted language, must be superuser */
2158 if (!superuser())
2160 NameStr(languageStruct->lanname));
2161 }
2162
2163 /* get the handler function's OID */
2164 laninline = languageStruct->laninline;
2165 if (!OidIsValid(laninline))
2166 ereport(ERROR,
2167 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2168 errmsg("language \"%s\" does not support inline code execution",
2169 NameStr(languageStruct->lanname))));
2170
2171 ReleaseSysCache(languageTuple);
2172
2173 /* execute the inline handler */
2174 OidFunctionCall1(laninline, PointerGetDatum(codeblock));
2175}
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:720
void * arg
char * source_text
Definition: parsenodes.h:3581

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(), ATAddForeignKeyConstraint(), DefineIndex(), getObjectIdentityParts(), GetOperatorFromCompareType(), 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 220 of file opclasscmds.c.

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

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 139 of file opclasscmds.c.

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

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 2037 of file functioncmds.c.

2038{
2039 Oid oid;
2040
2041 oid = GetSysCacheOid2(TRFTYPELANG, Anum_pg_transform_oid,
2042 ObjectIdGetDatum(type_id),
2043 ObjectIdGetDatum(lang_id));
2044 if (!OidIsValid(oid) && !missing_ok)
2045 ereport(ERROR,
2046 (errcode(ERRCODE_UNDEFINED_OBJECT),
2047 errmsg("transform for type %s language \"%s\" does not exist",
2048 format_type_be(type_id),
2049 get_language_name(lang_id, false))));
2050 return oid;
2051}
char * get_language_name(Oid langoid, bool missing_ok)
Definition: lsyscache.c:1253

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

Referenced by CreateFunction(), and get_object_address().

◆ GetDefaultOpClass()

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 2345 of file indexcmds.c.

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

◆ GetOperatorFromCompareType()

void GetOperatorFromCompareType ( Oid  opclass,
Oid  rhstype,
CompareType  cmptype,
Oid opid,
StrategyNumber strat 
)

Definition at line 2447 of file indexcmds.c.

2449{
2450 Oid amid;
2451 Oid opfamily;
2452 Oid opcintype;
2453
2454 Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
2455
2456 amid = get_opclass_method(opclass);
2457
2458 *opid = InvalidOid;
2459
2460 if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2461 {
2462 /*
2463 * Ask the index AM to translate to its internal stratnum
2464 */
2465 *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, true);
2466 if (*strat == InvalidStrategy)
2467 ereport(ERROR,
2468 errcode(ERRCODE_UNDEFINED_OBJECT),
2469 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2470 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2471 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2472 errdetail("Could not translate compare type %d for operator family \"%s\", input type %s, access method \"%s\".",
2473 cmptype, get_opfamily_name(opfamily, false), format_type_be(opcintype), get_am_name(amid)));
2474
2475 /*
2476 * We parameterize rhstype so foreign keys can ask for a <@ operator
2477 * whose rhs matches the aggregate function. For example range_agg
2478 * returns anymultirange.
2479 */
2480 if (!OidIsValid(rhstype))
2481 rhstype = opcintype;
2482 *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2483 }
2484
2485 if (!OidIsValid(*opid))
2486 ereport(ERROR,
2487 errcode(ERRCODE_UNDEFINED_OBJECT),
2488 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2489 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2490 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2491 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2492 get_opfamily_name(opfamily, false), get_am_name(amid)));
2493}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition: amapi.c:148
@ COMPARE_OVERLAP
Definition: cmptype.h:40
@ COMPARE_CONTAINED_BY
Definition: cmptype.h:41
Oid get_opclass_method(Oid opclass)
Definition: lsyscache.c:1352
#define InvalidStrategy
Definition: stratnum.h:24

References Assert(), COMPARE_CONTAINED_BY, COMPARE_EQ, COMPARE_OVERLAP, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), get_am_name(), get_opclass_method(), get_opclass_opfamily_and_input_type(), get_opfamily_member(), get_opfamily_name(), IndexAmTranslateCompareType(), InvalidOid, InvalidStrategy, and OidIsValid.

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 = &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:95
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition: foreign.c:482
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition: foreign.c:325
static void import_error_callback(void *arg)
Definition: foreigncmds.c:1600
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3428
@ CMD_UTILITY
Definition: nodes.h:276
List * pg_parse_query(const char *query_string)
Definition: postgres.c:603
RangeVar * relation
Definition: parsenodes.h:2739
struct ErrorContextCallback * previous
Definition: elog.h:297
void(* callback)(void *arg)
Definition: elog.h:298
ImportForeignSchema_function ImportForeignSchema
Definition: fdwapi.h:260
char * relname
Definition: primnodes.h:83
char * schemaname
Definition: primnodes.h:80
ParseLoc stmt_location
Definition: parsenodes.h:2072
ParseLoc stmt_len
Definition: parsenodes.h:2073
Node * stmt
Definition: parsenodes.h:2071
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 183 of file functioncmds.c.

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

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(), TypeName::location, FunctionParameter::location, LookupTypeName(), makeString(), FunctionParameter::mode, FunctionParameter::name, NIL, NOTICE, object_aclcheck(), OBJECT_AGGREGATE, OBJECT_PROCEDURE, ObjectIdGetDatum(), OidIsValid, ParseState::p_rtable, palloc(), palloc0(), parser_errposition(), 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 2061 of file functioncmds.c.

2063{
2064 /* check for duplicate name (more friendly than unique-index failure) */
2065 if (SearchSysCacheExists3(PROCNAMEARGSNSP,
2067 PointerGetDatum(proargtypes),
2068 ObjectIdGetDatum(nspOid)))
2069 ereport(ERROR,
2070 (errcode(ERRCODE_DUPLICATE_FUNCTION),
2071 errmsg("function %s already exists in schema \"%s\"",
2073 NIL, proargtypes->values),
2074 get_namespace_name(nspOid))));
2075}
const char * funcname_signature_string(const char *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1993
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 1830 of file opclasscmds.c.

1832{
1833 /* make sure the new name doesn't exist */
1834 if (SearchSysCacheExists3(CLAAMNAMENSP,
1835 ObjectIdGetDatum(opcmethod),
1836 CStringGetDatum(opcname),
1837 ObjectIdGetDatum(opcnamespace)))
1838 ereport(ERROR,
1840 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1841 opcname,
1842 get_am_name(opcmethod),
1843 get_namespace_name(opcnamespace))));
1844}

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 1853 of file opclasscmds.c.

1855{
1856 /* make sure the new name doesn't exist */
1857 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1858 ObjectIdGetDatum(opfmethod),
1859 CStringGetDatum(opfname),
1860 ObjectIdGetDatum(opfnamespace)))
1861 ereport(ERROR,
1863 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1864 opfname,
1865 get_am_name(opfmethod),
1866 get_namespace_name(opfnamespace))));
1867}

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 2518 of file indexcmds.c.

2519{
2520 char *name;
2521 int overhead = 0; /* chars needed for label and underscores */
2522 int availchars; /* chars available for name(s) */
2523 int name1chars; /* chars allocated to name1 */
2524 int name2chars; /* chars allocated to name2 */
2525 int ndx;
2526
2527 name1chars = strlen(name1);
2528 if (name2)
2529 {
2530 name2chars = strlen(name2);
2531 overhead++; /* allow for separating underscore */
2532 }
2533 else
2534 name2chars = 0;
2535 if (label)
2536 overhead += strlen(label) + 1;
2537
2538 availchars = NAMEDATALEN - 1 - overhead;
2539 Assert(availchars > 0); /* else caller chose a bad label */
2540
2541 /*
2542 * If we must truncate, preferentially truncate the longer name. This
2543 * logic could be expressed without a loop, but it's simple and obvious as
2544 * a loop.
2545 */
2546 while (name1chars + name2chars > availchars)
2547 {
2548 if (name1chars > name2chars)
2549 name1chars--;
2550 else
2551 name2chars--;
2552 }
2553
2554 name1chars = pg_mbcliplen(name1, name1chars, name1chars);
2555 if (name2)
2556 name2chars = pg_mbcliplen(name2, name2chars, name2chars);
2557
2558 /* Now construct the string using the chosen lengths */
2559 name = palloc(name1chars + name2chars + overhead + 1);
2560 memcpy(name, name1, name1chars);
2561 ndx = name1chars;
2562 if (name2)
2563 {
2564 name[ndx++] = '_';
2565 memcpy(name + ndx, name2, name2chars);
2566 ndx += name2chars;
2567 }
2568 if (label)
2569 {
2570 name[ndx++] = '_';
2571 strcpy(name + ndx, label);
2572 }
2573 else
2574 name[ndx] = '\0';
2575
2576 return name;
2577}
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 1311 of file functioncmds.c.

1312{
1313 Relation relation;
1314 HeapTuple tup;
1315 char prokind;
1316
1317 /*
1318 * Delete the pg_proc tuple.
1319 */
1320 relation = table_open(ProcedureRelationId, RowExclusiveLock);
1321
1322 tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
1323 if (!HeapTupleIsValid(tup)) /* should not happen */
1324 elog(ERROR, "cache lookup failed for function %u", funcOid);
1325
1326 prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
1327
1328 CatalogTupleDelete(relation, &tup->t_self);
1329
1330 ReleaseSysCache(tup);
1331
1332 table_close(relation, RowExclusiveLock);
1333
1334 pgstat_drop_function(funcOid);
1335
1336 /*
1337 * If there's a pg_aggregate tuple, delete that too.
1338 */
1339 if (prokind == PROKIND_AGGREGATE)
1340 {
1341 relation = table_open(AggregateRelationId, RowExclusiveLock);
1342
1343 tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
1344 if (!HeapTupleIsValid(tup)) /* should not happen */
1345 elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1346
1347 CatalogTupleDelete(relation, &tup->t_self);
1348
1349 ReleaseSysCache(tup);
1350
1351 table_close(relation, RowExclusiveLock);
1352 }
1353}
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)
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:1958
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
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:136
#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;
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 765 of file statscmds.c.

766{
767 Relation relation;
768 Relation rel;
769 HeapTuple tup;
770 Form_pg_statistic_ext statext;
771 Oid relid;
772
773 /*
774 * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
775 * associated table, so that dependent plans will be rebuilt.
776 */
777 relation = table_open(StatisticExtRelationId, RowExclusiveLock);
778
779 tup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statsOid));
780
781 if (!HeapTupleIsValid(tup)) /* should not happen */
782 elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
783
784 statext = (Form_pg_statistic_ext) GETSTRUCT(tup);
785 relid = statext->stxrelid;
786
787 /*
788 * Delete the pg_statistic_ext_data tuples holding the actual statistical
789 * data. There might be data with/without inheritance, so attempt deleting
790 * both. We lock the user table first, to prevent other processes (e.g.
791 * DROP STATISTICS) from removing the row concurrently.
792 */
794
795 RemoveStatisticsDataById(statsOid, true);
796 RemoveStatisticsDataById(statsOid, false);
797
799
800 CatalogTupleDelete(relation, &tup->t_self);
801
802 ReleaseSysCache(tup);
803
804 /* Keep lock until the end of the transaction. */
805 table_close(rel, NoLock);
806
807 table_close(relation, RowExclusiveLock);
808}
FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition: statscmds.c:740

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 740 of file statscmds.c.

741{
742 Relation relation;
743 HeapTuple tup;
744
745 relation = table_open(StatisticExtDataRelationId, RowExclusiveLock);
746
747 tup = SearchSysCache2(STATEXTDATASTXOID, ObjectIdGetDatum(statsOid),
748 BoolGetDatum(inh));
749
750 /* We don't know if the data row for inh value exists. */
751 if (HeapTupleIsValid(tup))
752 {
753 CatalogTupleDelete(relation, &tup->t_self);
754
755 ReleaseSysCache(tup);
756 }
757
758 table_close(relation, RowExclusiveLock);
759}

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
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
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 */
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),
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 */
1379 (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1380 MappingUserName(useId), stmt->servername)));
1381 return InvalidOid;
1382 }
1383
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:2391
char * rolename
Definition: parsenodes.h:416

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 2260 of file indexcmds.c.

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

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
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))
1601 }
1602 appendStringInfoChar(&buf, '\'');
1603 }
1604 if (lnext(deflist, l) != NULL)
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:1137
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition: c.h:1134
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
static char * buf
Definition: pg_test_fsync.c:72
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13019
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
Definition: value.h:29
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:204

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 916 of file statscmds.c.

917{
918 HeapTuple tuple;
920 Oid result;
921
922 tuple = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statId));
923 if (!HeapTupleIsValid(tuple))
924 {
925 if (missing_ok)
926 return InvalidOid;
927 elog(ERROR, "cache lookup failed for statistics object %u", statId);
928 }
929 stx = (Form_pg_statistic_ext) GETSTRUCT(tuple);
930 Assert(stx->oid == statId);
931
932 result = stx->stxrelid;
933 ReleaseSysCache(tuple);
934 return result;
935}

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)
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)
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)
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:3580
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:722
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:816
@ DEFELEM_DROP
Definition: parsenodes.h:819
@ DEFELEM_SET
Definition: parsenodes.h:817
@ DEFELEM_ADD
Definition: parsenodes.h:818
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1342
DefElemAction defaction
Definition: parsenodes.h:829

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().