PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 (ParseState *pstate, Oid tableId, const 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)
 
charmakeObjectName (const char *name1, const char *name2, const char *label)
 
charChooseRelationName (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, bool check_rights)
 
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)
 
charget_am_name (Oid amOid)
 
chardefGetString (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 
)
extern

Definition at line 736 of file foreigncmds.c.

737{
738 Relation rel;
739 HeapTuple tp;
744 Oid fdwId;
745 bool isnull;
746 Datum datum;
747 bool handler_given;
748 bool validator_given;
749 bool connection_given;
750 Oid fdwhandler;
751 Oid fdwvalidator;
752 Oid fdwconnection;
754
756
757 /* Must be superuser */
758 if (!superuser())
761 errmsg("permission denied to alter foreign-data wrapper \"%s\"",
762 stmt->fdwname),
763 errhint("Must be superuser to alter a foreign-data wrapper.")));
764
766 CStringGetDatum(stmt->fdwname));
767
768 if (!HeapTupleIsValid(tp))
771 errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
772
774 fdwId = fdwForm->oid;
775
776 memset(repl_val, 0, sizeof(repl_val));
777 memset(repl_null, false, sizeof(repl_null));
778 memset(repl_repl, false, sizeof(repl_repl));
779
780 parse_func_options(pstate, stmt->func_options,
781 &handler_given, &fdwhandler,
782 &validator_given, &fdwvalidator,
783 &connection_given, &fdwconnection);
784
785 if (handler_given)
786 {
789
790 /*
791 * It could be that the behavior of accessing foreign table changes
792 * with the new handler. Warn about this.
793 */
795 (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
796 }
797 else
798 {
799 /* handler unchanged */
800 fdwhandler = fdwForm->fdwhandler;
801 }
802
803 if (validator_given)
804 {
807
808 /*
809 * It could be that existing options for the FDW or dependent SERVER,
810 * USER MAPPING or FOREIGN TABLE objects are no longer valid according
811 * to the new validator. Warn about this.
812 */
813 if (OidIsValid(fdwvalidator))
815 (errmsg("changing the foreign-data wrapper validator can cause "
816 "the options for dependent objects to become invalid")));
817 }
818 else
819 {
820 /*
821 * Validator is not changed, but we need it for validating options.
822 */
823 fdwvalidator = fdwForm->fdwvalidator;
824 }
825
827 {
830
831 /*
832 * If the connection function is changed, behavior of dependent
833 * subscriptions can change. If NO CONNECTION, dependent
834 * subscriptions will fail.
835 */
836 if (OidIsValid(fdwForm->fdwconnection))
837 {
838 if (OidIsValid(fdwconnection))
840 (errmsg("changing the foreign-data wrapper connection function can cause "
841 "the options for dependent objects to become invalid")));
842 else
844 (errmsg("removing the foreign-data wrapper connection function will cause "
845 "dependent subscriptions to fail")));
846 }
847 }
848 else
849 {
850 /* connection function unchanged */
851 fdwconnection = fdwForm->fdwconnection;
852 }
853
854 /*
855 * If options specified, validate and update.
856 */
857 if (stmt->options)
858 {
859 /* Extract the current options */
861 tp,
863 &isnull);
864 if (isnull)
865 datum = PointerGetDatum(NULL);
866
867 /* Transform the options */
869 datum,
870 stmt->options,
871 fdwvalidator);
872
873 if (DatumGetPointer(datum) != NULL)
875 else
877
879 }
880
881 /* Everything looks good - update the tuple */
884
885 CatalogTupleUpdate(rel, &tp->t_self, tp);
886
887 heap_freetuple(tp);
888
890
891 /* Update function dependencies if we changed them */
893 {
895
896 /*
897 * Flush all existing dependency records of this FDW on functions; we
898 * assume there can be none other than the ones we are fixing.
899 */
901 fdwId,
904
905 /* And build new ones. */
906
907 if (OidIsValid(fdwhandler))
908 {
910 referenced.objectId = fdwhandler;
911 referenced.objectSubId = 0;
913 }
914
915 if (OidIsValid(fdwvalidator))
916 {
918 referenced.objectId = fdwvalidator;
919 referenced.objectSubId = 0;
921 }
922
923 if (OidIsValid(fdwconnection))
924 {
926 referenced.objectId = fdwconnection;
927 referenced.objectSubId = 0;
929 }
930 }
931
933
935
936 return myself;
937}
#define OidIsValid(objectId)
Definition c.h:917
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
static void parse_func_options(ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator, bool *connection_given, Oid *fdwconnection)
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
#define RowExclusiveLock
Definition lockdefs.h:38
static char * errmsg
#define InvokeObjectPostAlterHook(classId, objectId, subId)
#define ObjectAddressSet(addr, class_id, object_id)
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition pg_depend.c:364
END_CATALOG_STRUCT typedef FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
#define PointerGetDatum(X)
Definition postgres.h:354
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:542
ItemPointerData t_self
Definition htup.h:65
bool superuser(void)
Definition superuser.c:47
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
#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(), CStringGetDatum(), DatumGetPointer(), deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg, ERROR, fb(), Form_pg_foreign_data_wrapper, GETSTRUCT(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, parse_func_options(), PointerGetDatum, 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 
)
extern

Definition at line 286 of file foreigncmds.c.

287{
288 Oid fdwId;
290 Relation rel;
291 ObjectAddress address;
293
294
296
298
299 if (!HeapTupleIsValid(tup))
302 errmsg("foreign-data wrapper \"%s\" does not exist", name)));
303
305 fdwId = form->oid;
306
308
310
312
314
315 return address;
316}
static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
const char * name

References AlterForeignDataWrapperOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_foreign_data_wrapper, 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 
)
extern

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)
extern

Definition at line 1080 of file foreigncmds.c.

1081{
1082 Relation rel;
1083 HeapTuple tp;
1087 Oid srvId;
1089 ObjectAddress address;
1090
1092
1094 CStringGetDatum(stmt->servername));
1095
1096 if (!HeapTupleIsValid(tp))
1097 ereport(ERROR,
1099 errmsg("server \"%s\" does not exist", stmt->servername)));
1100
1102 srvId = srvForm->oid;
1103
1104 /*
1105 * Only owner or a superuser can ALTER a SERVER.
1106 */
1109 stmt->servername);
1110
1111 memset(repl_val, 0, sizeof(repl_val));
1112 memset(repl_null, false, sizeof(repl_null));
1113 memset(repl_repl, false, sizeof(repl_repl));
1114
1115 if (stmt->has_version)
1116 {
1117 /*
1118 * Change the server VERSION string.
1119 */
1120 if (stmt->version)
1122 CStringGetTextDatum(stmt->version);
1123 else
1125
1127 }
1128
1129 if (stmt->options)
1130 {
1132 Datum datum;
1133 bool isnull;
1134
1135 /* Extract the current srvoptions */
1137 tp,
1139 &isnull);
1140 if (isnull)
1141 datum = PointerGetDatum(NULL);
1142
1143 /* Prepare the options array */
1145 datum,
1146 stmt->options,
1147 fdw->fdwvalidator);
1148
1149 if (DatumGetPointer(datum) != NULL)
1151 else
1153
1155 }
1156
1157 /* Everything looks good - update the tuple */
1158 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1160
1161 CatalogTupleUpdate(rel, &tp->t_self, tp);
1162
1164
1166
1167 heap_freetuple(tp);
1168
1170
1171 return address;
1172}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
#define CStringGetTextDatum(s)
Definition builtins.h:98
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition foreign.c:39
Oid GetUserId(void)
Definition miscinit.c:470
@ OBJECT_FOREIGN_SERVER
END_CATALOG_STRUCT typedef FormData_pg_foreign_server * Form_pg_foreign_server

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_foreign_server, GetForeignDataWrapper(), GETSTRUCT(), GetUserId(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, OBJECT_FOREIGN_SERVER, object_ownercheck(), ObjectAddressSet, PointerGetDatum, 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 
)
extern

◆ AlterForeignServerOwner_oid()

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)
extern

◆ AlterFunction()

ObjectAddress AlterFunction ( ParseState pstate,
AlterFunctionStmt stmt 
)
extern

Definition at line 1364 of file functioncmds.c.

1365{
1366 HeapTuple tup;
1367 Oid funcOid;
1369 bool is_procedure;
1370 Relation rel;
1371 ListCell *l;
1376 List *set_items = NIL;
1381 ObjectAddress address;
1382
1384
1385 funcOid = LookupFuncWithArgs(stmt->objtype, stmt->func, false);
1386
1387 ObjectAddressSet(address, ProcedureRelationId, funcOid);
1388
1390 if (!HeapTupleIsValid(tup)) /* should not happen */
1391 elog(ERROR, "cache lookup failed for function %u", funcOid);
1392
1394
1395 /* Permission check: must own function */
1398 NameListToString(stmt->func->objname));
1399
1400 if (procForm->prokind == PROKIND_AGGREGATE)
1401 ereport(ERROR,
1403 errmsg("\"%s\" is an aggregate function",
1404 NameListToString(stmt->func->objname))));
1405
1406 is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
1407
1408 /* Examine requested actions. */
1409 foreach(l, stmt->actions)
1410 {
1411 DefElem *defel = (DefElem *) lfirst(l);
1412
1413 if (compute_common_attribute(pstate,
1414 is_procedure,
1415 defel,
1417 &strict_item,
1420 &set_items,
1421 &cost_item,
1422 &rows_item,
1423 &support_item,
1424 &parallel_item) == false)
1425 elog(ERROR, "option \"%s\" not recognized", defel->defname);
1426 }
1427
1428 if (volatility_item)
1430 if (strict_item)
1431 procForm->proisstrict = boolVal(strict_item->arg);
1433 procForm->prosecdef = boolVal(security_def_item->arg);
1434 if (leakproof_item)
1435 {
1436 procForm->proleakproof = boolVal(leakproof_item->arg);
1437 if (procForm->proleakproof && !superuser())
1438 ereport(ERROR,
1440 errmsg("only superuser can define a leakproof function")));
1441 }
1442 if (cost_item)
1443 {
1444 procForm->procost = defGetNumeric(cost_item);
1445 if (procForm->procost <= 0)
1446 ereport(ERROR,
1448 errmsg("COST must be positive")));
1449 }
1450 if (rows_item)
1451 {
1452 procForm->prorows = defGetNumeric(rows_item);
1453 if (procForm->prorows <= 0)
1454 ereport(ERROR,
1456 errmsg("ROWS must be positive")));
1457 if (!procForm->proretset)
1458 ereport(ERROR,
1460 errmsg("ROWS is not applicable when function does not return a set")));
1461 }
1462 if (support_item)
1463 {
1464 /* interpret_func_support handles the privilege check */
1466
1467 /* Add or replace dependency on support function */
1468 if (OidIsValid(procForm->prosupport))
1469 {
1471 ProcedureRelationId, procForm->prosupport,
1472 newsupport) != 1)
1473 elog(ERROR, "could not change support dependency for function %s",
1474 get_func_name(funcOid));
1475 }
1476 else
1477 {
1479
1481 referenced.objectId = newsupport;
1482 referenced.objectSubId = 0;
1484 }
1485
1486 procForm->prosupport = newsupport;
1487 }
1488 if (parallel_item)
1490 if (set_items)
1491 {
1492 Datum datum;
1493 bool isnull;
1494 ArrayType *a;
1498
1499 /* extract existing proconfig setting */
1501 a = isnull ? NULL : DatumGetArrayTypeP(datum);
1502
1503 /* update according to each SET or RESET item, left to right */
1505
1506 /* update the tuple */
1507 memset(repl_repl, false, sizeof(repl_repl));
1509
1510 if (a == NULL)
1511 {
1514 }
1515 else
1516 {
1518 repl_null[Anum_pg_proc_proconfig - 1] = false;
1519 }
1520
1523 }
1524 /* DO NOT put more touches of procForm below here; it's now dangling. */
1525
1526 /* Do the update */
1527 CatalogTupleUpdate(rel, &tup->t_self, tup);
1528
1530
1531 table_close(rel, NoLock);
1533
1534 return address;
1535}
#define DatumGetArrayTypeP(X)
Definition array.h:261
double defGetNumeric(DefElem *def)
Definition define.c:67
#define elog(elevel,...)
Definition elog.h:228
static Oid interpret_func_support(DefElem *defel)
static bool compute_common_attribute(ParseState *pstate, bool is_procedure, DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, DefElem **leakproof_item, List **set_items, DefElem **cost_item, DefElem **rows_item, DefElem **support_item, DefElem **parallel_item)
static char interpret_func_volatility(DefElem *defel)
static ArrayType * update_proconfig_value(ArrayType *a, List *set_items)
static char interpret_func_parallel(DefElem *defel)
int a
Definition isn.c:73
#define NoLock
Definition lockdefs.h:34
char * get_func_name(Oid funcid)
Definition lsyscache.c:1922
char * NameListToString(const List *names)
Definition namespace.c:3666
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:470
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
Definition pg_list.h:54
#define boolVal(v)
Definition value.h:81

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

Referenced by ProcessUtilitySlow().

◆ AlterOperator()

ObjectAddress AlterOperator ( AlterOperatorStmt stmt)
extern

Definition at line 495 of file operatorcmds.c.

496{
497 ObjectAddress address;
498 Oid oprId;
502 int i;
503 ListCell *pl;
505 bool nulls[Natts_pg_operator];
507 List *restrictionName = NIL; /* optional restrict. sel. function */
508 bool updateRestriction = false;
510 List *joinName = NIL; /* optional join sel. function */
511 bool updateJoin = false;
512 Oid joinOid;
513 List *commutatorName = NIL; /* optional commutator operator name */
515 List *negatorName = NIL; /* optional negator operator name */
517 bool canMerge = false;
518 bool updateMerges = false;
519 bool canHash = false;
520 bool updateHashes = false;
521
522 /* Look up the operator */
523 oprId = LookupOperWithArgs(stmt->opername, false);
526 if (!HeapTupleIsValid(tup))
527 elog(ERROR, "cache lookup failed for operator %u", oprId);
529
530 /* Process options */
531 foreach(pl, stmt->options)
532 {
533 DefElem *defel = (DefElem *) lfirst(pl);
534 List *param;
535
536 if (defel->arg == NULL)
537 param = NIL; /* NONE, removes the function */
538 else
539 param = defGetQualifiedName(defel);
540
541 if (strcmp(defel->defname, "restrict") == 0)
542 {
543 restrictionName = param;
544 updateRestriction = true;
545 }
546 else if (strcmp(defel->defname, "join") == 0)
547 {
548 joinName = param;
549 updateJoin = true;
550 }
551 else if (strcmp(defel->defname, "commutator") == 0)
552 {
554 }
555 else if (strcmp(defel->defname, "negator") == 0)
556 {
558 }
559 else if (strcmp(defel->defname, "merges") == 0)
560 {
562 updateMerges = true;
563 }
564 else if (strcmp(defel->defname, "hashes") == 0)
565 {
567 updateHashes = true;
568 }
569
570 /*
571 * The rest of the options that CREATE accepts cannot be changed.
572 * Check for them so that we can give a meaningful error message.
573 */
574 else if (strcmp(defel->defname, "leftarg") == 0 ||
575 strcmp(defel->defname, "rightarg") == 0 ||
576 strcmp(defel->defname, "function") == 0 ||
577 strcmp(defel->defname, "procedure") == 0)
578 {
581 errmsg("operator attribute \"%s\" cannot be changed",
582 defel->defname)));
583 }
584 else
587 errmsg("operator attribute \"%s\" not recognized",
588 defel->defname)));
589 }
590
591 /* Check permissions. Must be owner. */
594 NameStr(oprForm->oprname));
595
596 /*
597 * Look up OIDs for any parameters specified
598 */
599 if (restrictionName)
601 else
603 if (joinName)
605 else
607
608 if (commutatorName)
609 {
610 /* commutator has reversed arg types */
612 oprForm->oprright,
613 oprForm->oprleft);
614
615 /*
616 * We don't need to do anything extra for a self commutator as in
617 * OperatorCreate, since the operator surely exists already.
618 */
619 }
620 else
622
623 if (negatorName)
624 {
626 oprForm->oprleft,
627 oprForm->oprright);
628
629 /* Must reject self-negation */
630 if (negatorOid == oprForm->oid)
633 errmsg("operator cannot be its own negator")));
634 }
635 else
636 {
638 }
639
640 /*
641 * Check that we're not changing any attributes that might be depended on
642 * by plans, while allowing no-op updates.
643 */
644 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
645 commutatorOid != oprForm->oprcom)
648 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
649 "commutator")));
650
651 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
652 negatorOid != oprForm->oprnegate)
655 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
656 "negator")));
657
658 if (updateMerges && oprForm->oprcanmerge && !canMerge)
661 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
662 "merges")));
663
664 if (updateHashes && oprForm->oprcanhash && !canHash)
667 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
668 "hashes")));
669
670 /* Perform additional checks, like OperatorCreate does */
672 oprForm->oprright,
673 oprForm->oprresult,
678 canMerge,
679 canHash);
680
681 /* Update the tuple */
682 for (i = 0; i < Natts_pg_operator; ++i)
683 {
684 values[i] = (Datum) 0;
685 replaces[i] = false;
686 nulls[i] = false;
687 }
689 {
692 }
693 if (updateJoin)
694 {
697 }
699 {
702 }
704 {
707 }
708 if (updateMerges)
709 {
712 }
713 if (updateHashes)
714 {
717 }
718
720 values, nulls, replaces);
721
722 CatalogTupleUpdate(catalog, &tup->t_self, tup);
723
724 address = makeOperatorDependencies(tup, false, true);
725
728
730
732
733 return address;
734}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define NameStr(name)
Definition c.h:894
bool defGetBoolean(DefElem *def)
Definition define.c:93
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
int i
Definition isn.c:77
static Oid ValidateJoinEstimator(List *joinName)
static Oid ValidateOperatorReference(List *name, Oid leftTypeId, Oid rightTypeId)
static Oid ValidateRestrictionEstimator(List *restrictionName)
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition parse_oper.c:136
@ OBJECT_OPERATOR
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
#define InvalidOid

References aclcheck_error(), ACLCHECK_NOT_OWNER, BoolGetDatum(), CatalogTupleUpdate(), defGetBoolean(), defGetQualifiedName(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_operator, 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, table_close(), table_open(), ValidateJoinEstimator(), ValidateOperatorReference(), ValidateRestrictionEstimator(), and values.

Referenced by ProcessUtilitySlow().

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)
extern

Definition at line 837 of file opclasscmds.c.

838{
839 Oid amoid, /* our AM's oid */
840 opfamilyoid; /* oid of opfamily */
841 int maxOpNumber, /* amstrategies value */
842 optsProcNumber, /* amoptsprocnum value */
843 maxProcNumber; /* amsupport value */
847
848 /* Get necessary info about access method */
850 if (!HeapTupleIsValid(tup))
853 errmsg("access method \"%s\" does not exist",
854 stmt->amname)));
855
857 amoid = amform->oid;
860
861 maxOpNumber = amroutine->amstrategies;
862 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
863 if (maxOpNumber <= 0)
865 maxProcNumber = amroutine->amsupport;
866 optsProcNumber = amroutine->amoptsprocnum;
867
868 /* XXX Should we make any privilege check against the AM? */
869
870 /* Look up the opfamily */
871 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
872
873 /*
874 * Currently, we require superuser privileges to alter an opfamily.
875 *
876 * XXX re-enable NOT_USED code sections below if you remove this test.
877 */
878 if (!superuser())
881 errmsg("must be superuser to alter an operator family")));
882
883 /*
884 * ADD and DROP cases need separate code from here on down.
885 */
886 if (stmt->isDrop)
889 else
892 stmt->items);
893
894 return opfamilyoid;
895}
const IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition amapi.c:69
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int optsProcNumber, List *items)
END_CATALOG_STRUCT typedef FormData_pg_am * Form_pg_am
Definition pg_am.h:52
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), CStringGetDatum(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_am, get_opfamily_oid(), GetIndexAmRoutineByAmId(), GETSTRUCT(), HeapTupleIsValid, ReleaseSysCache(), SearchSysCache1(), stmt, and superuser().

Referenced by ProcessUtilitySlow().

◆ AlterStatistics()

ObjectAddress AlterStatistics ( AlterStatsStmt stmt)
extern

Definition at line 669 of file statscmds.c.

670{
671 Relation rel;
672 Oid stxoid;
678 ObjectAddress address;
679 int newtarget = 0;
681
682 /* -1 was used in previous versions for the default setting */
683 if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
684 {
685 newtarget = intVal(stmt->stxstattarget);
686 newtarget_default = false;
687 }
688 else
689 newtarget_default = true;
690
692 {
693 /* Limit statistics target to a sane range */
694 if (newtarget < 0)
695 {
698 errmsg("statistics target %d is too low",
699 newtarget)));
700 }
702 {
706 errmsg("lowering statistics target to %d",
707 newtarget)));
708 }
709 }
710
711 /* lookup OID of the statistics object */
712 stxoid = get_statistics_object_oid(stmt->defnames, stmt->missing_ok);
713
714 /*
715 * If we got here and the OID is not valid, it means the statistics object
716 * does not exist, but the command specified IF EXISTS. So report this as
717 * a simple NOTICE and we're done.
718 */
719 if (!OidIsValid(stxoid))
720 {
721 char *schemaname;
722 char *statname;
723
724 Assert(stmt->missing_ok);
725
726 DeconstructQualifiedName(stmt->defnames, &schemaname, &statname);
727
728 if (schemaname)
730 (errmsg("statistics object \"%s.%s\" does not exist, skipping",
731 schemaname, statname)));
732 else
734 (errmsg("statistics object \"%s\" does not exist, skipping",
735 statname)));
736
738 }
739
740 /* Search pg_statistic_ext */
742
745 elog(ERROR, "cache lookup failed for extended statistics object %u", stxoid);
746
747 /* Must be owner of the existing statistics object */
750 NameListToString(stmt->defnames));
751
752 /* Build new tuple. */
753 memset(repl_val, 0, sizeof(repl_val));
754 memset(repl_null, false, sizeof(repl_null));
755 memset(repl_repl, false, sizeof(repl_repl));
756
757 /* replace the stxstattarget column */
761 else
763
766
767 /* Update system catalog. */
768 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
769
771
773
774 /*
775 * NOTE: because we only support altering the statistics target, not the
776 * other fields, there is no need to update dependencies.
777 */
778
781
783
784 return address;
785}
#define Assert(condition)
Definition c.h:1002
#define NOTICE
Definition elog.h:36
Oid get_statistics_object_oid(List *names, bool missing_ok)
Definition namespace.c:2644
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3373
const ObjectAddress InvalidObjectAddress
@ OBJECT_STATISTIC_EXT
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
#define MAX_STATISTICS_TARGET
Definition vacuum.h:350
#define intVal(v)
Definition value.h:79

References aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, CatalogTupleUpdate(), DeconstructQualifiedName(), elog, ereport, errcode(), errmsg, ERROR, fb(), 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, table_close(), table_open(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ AlterTSConfiguration()

ObjectAddress AlterTSConfiguration ( AlterTSConfigurationStmt stmt)
extern

Definition at line 1156 of file tsearchcmds.c.

1157{
1158 HeapTuple tup;
1159 Oid cfgId;
1161 ObjectAddress address;
1162
1163 /* Find the configuration */
1164 tup = GetTSConfigTuple(stmt->cfgname);
1165 if (!HeapTupleIsValid(tup))
1166 ereport(ERROR,
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 */
1176 NameListToString(stmt->cfgname));
1177
1179
1180 /* Add or drop mappings */
1181 if (stmt->dicts)
1183 else if (stmt->tokentype)
1185
1186 /* Update dependencies */
1188
1190
1191 ObjectAddressSet(address, TSConfigRelationId, cfgId);
1192
1194
1196
1197 return address;
1198}
@ OBJECT_TSCONFIGURATION
END_CATALOG_STRUCT typedef FormData_pg_ts_config * Form_pg_ts_config
static ObjectAddress makeConfigurationDependencies(HeapTuple tuple, bool removeOld, Relation mapRel)
static HeapTuple GetTSConfigTuple(List *names)
static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)
static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt, HeapTuple tup, Relation relMap)

References aclcheck_error(), ACLCHECK_NOT_OWNER, DropConfigurationMapping(), ereport, errcode(), errmsg, ERROR, fb(), Form_pg_ts_config, 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)
extern

Definition at line 493 of file tsearchcmds.c.

494{
496 newtup;
497 Relation rel;
498 Oid dictId;
499 ListCell *pl;
501 Datum opt;
502 bool isnull;
506 ObjectAddress address;
507
508 dictId = get_ts_dict_oid(stmt->dictname, false);
509
511
513
514 if (!HeapTupleIsValid(tup))
515 elog(ERROR, "cache lookup failed for text search dictionary %u",
516 dictId);
517
518 /* must be owner */
521 NameListToString(stmt->dictname));
522
523 /* deserialize the existing set of options */
526 &isnull);
527 if (isnull)
529 else
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)
549 }
550
551 /*
552 * and add new value if it's got one
553 */
554 if (defel->arg)
556 }
557
558 /*
559 * Validate
560 */
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)
574 else
577
580
581 CatalogTupleUpdate(rel, &newtup->t_self, newtup);
582
584
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
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:2933
@ OBJECT_TSDICTIONARY
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:423
END_CATALOG_STRUCT typedef FormData_pg_ts_dict * Form_pg_ts_dict
Definition pg_ts_dict.h:56
List * deserialize_deflist(Datum txt)
text * serialize_deflist(List *deflist)
static void verify_dictoptions(Oid tmplId, List *dictoptions)

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), deserialize_deflist(), elog, ERROR, fb(), foreach_delete_current, Form_pg_ts_dict, 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(), table_close(), table_open(), and verify_dictoptions().

Referenced by ProcessUtilitySlow().

◆ AlterUserMapping()

ObjectAddress AlterUserMapping ( AlterUserMappingStmt stmt)
extern

Definition at line 1332 of file foreigncmds.c.

1333{
1334 Relation rel;
1335 HeapTuple tp;
1339 Oid useId;
1340 Oid umId;
1342 ObjectAddress address;
1343 RoleSpec *role = (RoleSpec *) stmt->user;
1344
1346
1347 if (role->roletype == ROLESPEC_PUBLIC)
1349 else
1350 useId = get_rolespec_oid(stmt->user, false);
1351
1352 srv = GetForeignServerByName(stmt->servername, false);
1353
1356 ObjectIdGetDatum(srv->serverid));
1357 if (!OidIsValid(umId))
1358 ereport(ERROR,
1360 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1361 MappingUserName(useId), stmt->servername)));
1362
1363 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1364
1366
1367 if (!HeapTupleIsValid(tp))
1368 elog(ERROR, "cache lookup failed for user mapping %u", umId);
1369
1370 memset(repl_val, 0, sizeof(repl_val));
1371 memset(repl_null, false, sizeof(repl_null));
1372 memset(repl_repl, false, sizeof(repl_repl));
1373
1374 if (stmt->options)
1375 {
1377 Datum datum;
1378 bool isnull;
1379
1380 /*
1381 * Process the options.
1382 */
1383
1384 fdw = GetForeignDataWrapper(srv->fdwid);
1385
1387 tp,
1389 &isnull);
1390 if (isnull)
1391 datum = PointerGetDatum(NULL);
1392
1393 /* Prepare the options array */
1395 datum,
1396 stmt->options,
1397 fdw->fdwvalidator);
1398
1399 if (DatumGetPointer(datum) != NULL)
1401 else
1403
1405 }
1406
1407 /* Everything looks good - update the tuple */
1408 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1410
1411 CatalogTupleUpdate(rel, &tp->t_self, tp);
1412
1414 umId, 0);
1415
1417
1418 heap_freetuple(tp);
1419
1421
1422 return address;
1423}
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition acl.c:5642
#define ACL_ID_PUBLIC
Definition acl.h:46
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition foreign.c:185
#define MappingUserName(userid)
Definition foreign.h:20
static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
@ ROLESPEC_PUBLIC
Definition parsenodes.h:428
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition syscache.h:111

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

Referenced by ProcessUtilitySlow().

◆ CallStmtResultDesc()

TupleDesc CallStmtResultDesc ( CallStmt stmt)
extern

Definition at line 2386 of file functioncmds.c.

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

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

Referenced by UtilityTupleDescriptor().

◆ CheckIndexCompatible()

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

Definition at line 189 of file indexcmds.c.

194{
195 bool isconstraint;
196 Oid *typeIds;
202 HeapTuple tuple;
206 bool amcanorder;
207 bool amsummarizing;
209 IndexInfo *indexInfo;
211 int old_natts;
212 bool ret = true;
215 Relation irel;
216 int i;
217 Datum d;
218
219 /* Caller should already have the relation locked in some way. */
221
222 /*
223 * We can pretend isconstraint = false unconditionally. It only serves to
224 * decide the text of an error message that should never happen for us.
225 */
226 isconstraint = false;
227
231
232 /* look up the access method */
234 if (!HeapTupleIsValid(tuple))
237 errmsg("access method \"%s\" does not exist",
242 ReleaseSysCache(tuple);
243
244 amcanorder = amRoutine->amcanorder;
245 amsummarizing = amRoutine->amsummarizing;
246
247 /*
248 * Compute the operator classes, collations, and exclusion operators for
249 * the new index, so we can test whether it's compatible with the existing
250 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
251 * DefineIndex would have failed later. Our attributeList contains only
252 * key attributes, thus we're filling ii_NumIndexAttrs and
253 * ii_NumIndexKeyAttrs with same value.
254 */
256 accessMethodId, NIL, NIL, false, false,
257 false, false, amsummarizing, isWithoutOverlaps);
263 ComputeIndexAttrs(NULL, indexInfo,
268 amcanorder, isconstraint, isWithoutOverlaps, InvalidOid,
269 0, NULL);
270
271 /* Get the soon-obsolete pg_index tuple. */
273 if (!HeapTupleIsValid(tuple))
274 elog(ERROR, "cache lookup failed for index %u", oldId);
276
277 /*
278 * We don't assess expressions or predicates; assume incompatibility.
279 * Also, if the index is invalid for any reason, treat it as incompatible.
280 */
283 indexForm->indisvalid))
284 {
285 ReleaseSysCache(tuple);
286 return false;
287 }
288
289 /* Any change in operator class or collation breaks compatibility. */
290 old_natts = indexForm->indnkeyatts;
292
295
298
299 ret = (memcmp(old_indclass->values, opclassIds, old_natts * sizeof(Oid)) == 0 &&
300 memcmp(old_indcollation->values, collationIds, old_natts * sizeof(Oid)) == 0);
301
302 ReleaseSysCache(tuple);
303
304 if (!ret)
305 return false;
306
307 /* For polymorphic opcintype, column type changes break compatibility. */
308 irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
309 for (i = 0; i < old_natts; i++)
310 {
312 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
313 {
314 ret = false;
315 break;
316 }
317 }
318
319 /* Any change in opclass options break compatibility. */
320 if (ret)
321 {
323
324 for (i = 0; i < old_natts; i++)
326
328
330 }
331
332 /* Any change in exclusion operator selections breaks compatibility. */
333 if (ret && indexInfo->ii_ExclusionOps != NULL)
334 {
336 *old_procs;
338
340 ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
341 old_natts * sizeof(Oid)) == 0;
342
343 /* Require an exact input type match for polymorphic operators. */
344 if (ret)
345 {
346 for (i = 0; i < old_natts && ret; i++)
347 {
348 Oid left,
349 right;
350
351 op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
352 if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
353 TupleDescAttr(irel->rd_att, i)->atttypid != typeIds[i])
354 {
355 ret = false;
356 break;
357 }
358 }
359 }
360 }
361
362 index_close(irel, NoLock);
363 return ret;
364}
const IndexAmRoutine * GetIndexAmRoutine(Oid amhandler)
Definition amapi.c:33
int16_t int16
Definition c.h:678
uint16_t uint16
Definition c.h:682
#define palloc_array(type, count)
Definition fe_memutils.h:91
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition heaptuple.c:456
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition index.c:3604
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
static bool CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
Definition indexcmds.c:373
static void ComputeIndexAttrs(ParseState *pstate, 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:1891
#define AccessShareLock
Definition lockdefs.h:36
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1464
Datum get_attoptions(Oid relid, int16 attnum)
Definition lsyscache.c:1196
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1658
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:1619
#define INDEX_MAX_KEYS
END_CATALOG_STRUCT typedef FormData_pg_index * Form_pg_index
Definition pg_index.h:74
void RelationGetExclusionInfo(Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
Definition relcache.c:5663
Oid * ii_ExclusionOps
Definition execnodes.h:202
TupleDesc rd_att
Definition rel.h:112
Definition c.h:874
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626

References AccessShareLock, Assert, CompareOpclassOptions(), ComputeIndexAttrs(), DatumGetPointer(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_am, Form_pg_index, 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(), and TupleDescAttr().

Referenced by TryReuseIndex().

◆ ChooseRelationName()

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

Definition at line 2644 of file indexcmds.c.

2647{
2648 int pass = 0;
2649 char *relname = NULL;
2650 char modlabel[NAMEDATALEN];
2653
2654 /* prepare to search pg_class with a dirty snapshot */
2657
2658 /* try the unmodified label first */
2659 strlcpy(modlabel, label, sizeof(modlabel));
2660
2661 for (;;)
2662 {
2663 ScanKeyData key[2];
2664 SysScanDesc scan;
2665 bool collides;
2666
2668
2669 /* is there any conflicting relation name? */
2670 ScanKeyInit(&key[0],
2674 ScanKeyInit(&key[1],
2678
2680 true /* indexOK */ ,
2682 2, key);
2683
2685
2686 systable_endscan(scan);
2687
2688 /* break out of loop if no conflict */
2689 if (!collides)
2690 {
2691 if (!isconstraint ||
2693 break;
2694 }
2695
2696 /* found a conflict, so try a new name component */
2697 pfree(relname);
2698 snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
2699 }
2700
2702
2703 return relname;
2704}
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition indexcmds.c:2556
static char * label
NameData relname
Definition pg_class.h:40
#define NAMEDATALEN
bool ConstraintNameExists(const char *conname, Oid namespaceid)
#define snprintf
Definition port.h:261
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define InitDirtySnapshot(snapshotdata)
Definition snapmgr.h:42
#define BTEqualStrategyNumber
Definition stratnum.h:31

References AccessShareLock, BTEqualStrategyNumber, ConstraintNameExists(), CStringGetDatum(), fb(), HeapTupleIsValid, InitDirtySnapshot, label, makeObjectName(), NAMEDATALEN, ObjectIdGetDatum(), pfree(), relname, ScanKeyInit(), snprintf, strlcpy(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

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

◆ CreateAccessMethod()

ObjectAddress CreateAccessMethod ( CreateAmStmt stmt)
extern

Definition at line 43 of file amcmds.c.

44{
45 Relation rel;
48 Oid amoid;
49 Oid amhandler;
50 bool nulls[Natts_pg_am];
53
55
56 /* Must be superuser */
57 if (!superuser())
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 */
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
92
94
97
99 myself.objectId = amoid;
100 myself.objectSubId = 0;
101
102 /* Record dependency on handler function */
104 referenced.objectId = amhandler;
105 referenced.objectSubId = 0;
106
108
110
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:475
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:206
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition syscache.h:109

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

Referenced by ProcessUtilitySlow().

◆ CreateCast()

ObjectAddress CreateCast ( CreateCastStmt stmt)
extern

Definition at line 1542 of file functioncmds.c.

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

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, CastCreate(), COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_proc, 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 
)
extern

Definition at line 608 of file foreigncmds.c.

609{
610 Relation rel;
613 HeapTuple tuple;
614 Oid fdwId;
615 bool handler_given;
616 bool validator_given;
617 bool connection_given;
618 Oid fdwhandler;
619 Oid fdwvalidator;
620 Oid fdwconnection;
621 Datum fdwoptions;
622 Oid ownerId;
625
627
628 /* Must be superuser */
629 if (!superuser())
632 errmsg("permission denied to create foreign-data wrapper \"%s\"",
633 stmt->fdwname),
634 errhint("Must be superuser to create a foreign-data wrapper.")));
635
636 /* For now the owner cannot be specified on create. Use effective user ID. */
637 ownerId = GetUserId();
638
639 /*
640 * Check that there is no other foreign-data wrapper by this name.
641 */
642 if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
645 errmsg("foreign-data wrapper \"%s\" already exists",
646 stmt->fdwname)));
647
648 /*
649 * Insert tuple into pg_foreign_data_wrapper.
650 */
651 memset(values, 0, sizeof(values));
652 memset(nulls, false, sizeof(nulls));
653
660
661 /* Lookup handler and validator functions, if given */
662 parse_func_options(pstate, stmt->func_options,
663 &handler_given, &fdwhandler,
664 &validator_given, &fdwvalidator,
665 &connection_given, &fdwconnection);
666
670
671 nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
672
675 stmt->options,
676 fdwvalidator);
677
678 if (DatumGetPointer(fdwoptions) != NULL)
680 else
682
683 tuple = heap_form_tuple(rel->rd_att, values, nulls);
684
685 CatalogTupleInsert(rel, tuple);
686
687 heap_freetuple(tuple);
688
689 /* record dependencies */
691 myself.objectId = fdwId;
692 myself.objectSubId = 0;
693
694 if (OidIsValid(fdwhandler))
695 {
697 referenced.objectId = fdwhandler;
698 referenced.objectSubId = 0;
700 }
701
702 if (OidIsValid(fdwvalidator))
703 {
705 referenced.objectId = fdwvalidator;
706 referenced.objectSubId = 0;
708 }
709
710 if (OidIsValid(fdwconnection))
711 {
713 referenced.objectId = fdwconnection;
714 referenced.objectSubId = 0;
716 }
717
719
720 /* dependency on extension */
722
723 /* Post creation hook for new foreign data wrapper */
725
727
728 return myself;
729}
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition foreign.c:99
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)

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

Referenced by ProcessUtilitySlow().

◆ CreateForeignServer()

ObjectAddress CreateForeignServer ( CreateForeignServerStmt stmt)
extern

Definition at line 944 of file foreigncmds.c.

945{
946 Relation rel;
947 Datum srvoptions;
949 bool nulls[Natts_pg_foreign_server];
950 HeapTuple tuple;
951 Oid srvId;
952 Oid ownerId;
957
959
960 /* For now the owner cannot be specified on create. Use effective user ID. */
961 ownerId = GetUserId();
962
963 /*
964 * Check that there is no other foreign server by this name. If there is
965 * one, do nothing if IF NOT EXISTS was specified.
966 */
967 srvId = get_foreign_server_oid(stmt->servername, true);
968 if (OidIsValid(srvId))
969 {
970 if (stmt->if_not_exists)
971 {
972 /*
973 * If we are in an extension script, insist that the pre-existing
974 * object be a member of the extension, to avoid security risks.
975 */
978
979 /* OK to skip */
982 errmsg("server \"%s\" already exists, skipping",
983 stmt->servername)));
986 }
987 else
990 errmsg("server \"%s\" already exists",
991 stmt->servername)));
992 }
993
994 /*
995 * Check that the FDW exists and that we have USAGE on it. Also get the
996 * actual FDW for option validation etc.
997 */
998 fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
999
1001 if (aclresult != ACLCHECK_OK)
1003
1004 /*
1005 * Insert tuple into pg_foreign_server.
1006 */
1007 memset(values, 0, sizeof(values));
1008 memset(nulls, false, sizeof(nulls));
1009
1017
1018 /* Add server type if supplied */
1019 if (stmt->servertype)
1021 CStringGetTextDatum(stmt->servertype);
1022 else
1023 nulls[Anum_pg_foreign_server_srvtype - 1] = true;
1024
1025 /* Add server version if supplied */
1026 if (stmt->version)
1028 CStringGetTextDatum(stmt->version);
1029 else
1030 nulls[Anum_pg_foreign_server_srvversion - 1] = true;
1031
1032 /* Start with a blank acl */
1033 nulls[Anum_pg_foreign_server_srvacl - 1] = true;
1034
1035 /* Add server options */
1038 stmt->options,
1039 fdw->fdwvalidator);
1040
1041 if (DatumGetPointer(srvoptions) != NULL)
1042 values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
1043 else
1044 nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
1045
1046 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1047
1048 CatalogTupleInsert(rel, tuple);
1049
1050 heap_freetuple(tuple);
1051
1052 /* record dependencies */
1054 myself.objectId = srvId;
1055 myself.objectSubId = 0;
1056
1058 referenced.objectId = fdw->fdwid;
1059 referenced.objectSubId = 0;
1061
1063
1064 /* dependency on extension */
1066
1067 /* Post creation hook for new foreign server */
1069
1071
1072 return myself;
1073}
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition foreign.c:736
@ OBJECT_FDW
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition pg_depend.c:271

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), checkMembershipInCurrentExtension(), CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), get_foreign_server_oid(), GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, namein(), NOTICE, object_aclcheck(), OBJECT_FDW, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, PointerGetDatum, 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 
)
extern

Definition at line 1510 of file foreigncmds.c.

1511{
1515 bool nulls[Natts_pg_foreign_table];
1516 HeapTuple tuple;
1520 Oid ownerId;
1522 ForeignServer *server;
1523
1524 /*
1525 * Advance command counter to ensure the pg_attribute tuple is visible;
1526 * the tuple might be updated to add constraints in previous step.
1527 */
1529
1531
1532 /*
1533 * For now the owner cannot be specified on create. Use effective user ID.
1534 */
1535 ownerId = GetUserId();
1536
1537 /*
1538 * Check that the foreign server exists and that we have USAGE on it. Also
1539 * get the actual FDW for option validation etc.
1540 */
1541 server = GetForeignServerByName(stmt->servername, false);
1543 if (aclresult != ACLCHECK_OK)
1545
1546 fdw = GetForeignDataWrapper(server->fdwid);
1547
1548 /*
1549 * Insert tuple into pg_foreign_table.
1550 */
1551 memset(values, 0, sizeof(values));
1552 memset(nulls, false, sizeof(nulls));
1553
1556 /* Add table generic options */
1559 stmt->options,
1560 fdw->fdwvalidator);
1561
1564 else
1565 nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1566
1567 tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1568
1569 CatalogTupleInsert(ftrel, tuple);
1570
1571 heap_freetuple(tuple);
1572
1573 /* Add pg_class dependency on the server */
1574 myself.classId = RelationRelationId;
1575 myself.objectId = relid;
1576 myself.objectSubId = 0;
1577
1579 referenced.objectId = server->serverid;
1580 referenced.objectSubId = 0;
1582
1584}
char * servername
Definition foreign.h:40
void CommandCounterIncrement(void)
Definition xact.c:1130

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), CommandCounterIncrement(), DatumGetPointer(), DEPENDENCY_NORMAL, fb(), ForeignServer::fdwid, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_form_tuple(), heap_freetuple(), object_aclcheck(), OBJECT_FOREIGN_SERVER, ObjectIdGetDatum(), PointerGetDatum, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, stmt, table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateFunction()

ObjectAddress CreateFunction ( ParseState pstate,
CreateFunctionStmt stmt 
)
extern

Definition at line 1029 of file functioncmds.c.

1030{
1031 char *probin_str;
1032 char *prosrc_str;
1034 Oid prorettype;
1035 bool returnsSet;
1036 char *language;
1040 char *funcname;
1043 oidvector *parameterTypes;
1053 ArrayType *trftypes;
1055 bool isWindowFunc,
1056 isStrict,
1057 security,
1059 char volatility;
1066 List *as_clause;
1067 char parallel;
1068
1069 /* Convert list of names to a name and namespace */
1071 &funcname);
1072
1073 /* Check we have creation rights in target namespace */
1075 if (aclresult != ACLCHECK_OK)
1078
1079 /* Set default attributes */
1080 as_clause = NIL;
1081 language = NULL;
1082 isWindowFunc = false;
1083 isStrict = false;
1084 security = false;
1085 isLeakProof = false;
1087 proconfig = NULL;
1088 procost = -1; /* indicates not set */
1089 prorows = -1; /* indicates not set */
1092
1093 /* Extract non-default attributes from stmt->options list */
1095 stmt->is_procedure,
1096 stmt->options,
1101 &prosupport, &parallel);
1102
1103 if (!language)
1104 {
1105 if (stmt->sql_body)
1106 language = "sql";
1107 else
1108 ereport(ERROR,
1110 errmsg("no language specified")));
1111 }
1112
1113 /* Look up the language and validate permissions */
1116 ereport(ERROR,
1118 errmsg("language \"%s\" does not exist", language),
1120 errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
1121
1124
1125 if (languageStruct->lanpltrusted)
1126 {
1127 /* if trusted language, need USAGE privilege */
1129 if (aclresult != ACLCHECK_OK)
1131 NameStr(languageStruct->lanname));
1132 }
1133 else
1134 {
1135 /* if untrusted language, must be superuser */
1136 if (!superuser())
1138 NameStr(languageStruct->lanname));
1139 }
1140
1141 languageValidator = languageStruct->lanvalidator;
1142
1144
1145 /*
1146 * Only superuser is allowed to create leakproof functions because
1147 * leakproof functions can see tuples which have not yet been filtered out
1148 * by security barrier views or row-level security policies.
1149 */
1150 if (isLeakProof && !superuser())
1151 ereport(ERROR,
1153 errmsg("only superuser can define a leakproof function")));
1154
1155 if (transformDefElem)
1156 {
1157 ListCell *lc;
1158
1159 foreach(lc, castNode(List, transformDefElem))
1160 {
1161 Oid typeid = typenameTypeId(NULL,
1163 Oid elt = get_base_element_type(typeid);
1165
1166 typeid = elt ? elt : typeid;
1167 transformid = get_transform_oid(typeid, languageOid, false);
1170 }
1171 }
1172
1173 /*
1174 * Convert remaining parameters of CREATE to form wanted by
1175 * ProcedureCreate.
1176 */
1178 stmt->parameters,
1180 stmt->is_procedure ? OBJECT_PROCEDURE : OBJECT_FUNCTION,
1181 &parameterTypes,
1190
1191 if (stmt->is_procedure)
1192 {
1193 Assert(!stmt->returnType);
1195 returnsSet = false;
1196 }
1197 else if (stmt->returnType)
1198 {
1199 /* explicit RETURNS clause */
1201 &prorettype, &returnsSet);
1202 if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
1203 ereport(ERROR,
1205 errmsg("function result type must be %s because of OUT parameters",
1207 }
1209 {
1210 /* default RETURNS clause from OUT parameters */
1211 prorettype = requiredResultType;
1212 returnsSet = false;
1213 }
1214 else
1215 {
1216 ereport(ERROR,
1218 errmsg("function result type must be specified")));
1219 /* Alternative possibility: default to RETURNS VOID */
1220 prorettype = VOIDOID;
1221 returnsSet = false;
1222 }
1223
1224 if (trftypes_list != NIL)
1225 {
1226 ListCell *lc;
1227 Datum *arr;
1228 int i;
1229
1230 arr = palloc(list_length(trftypes_list) * sizeof(Datum));
1231 i = 0;
1232 foreach(lc, trftypes_list)
1233 arr[i++] = ObjectIdGetDatum(lfirst_oid(lc));
1235 }
1236 else
1237 {
1238 /* store SQL NULL instead of empty array */
1239 trftypes = NULL;
1240 }
1241
1245 pstate->p_sourcetext);
1246
1247 /*
1248 * Set default values for COST and ROWS depending on other parameters;
1249 * reject ROWS if it's not returnsSet. NB: pg_dump knows these default
1250 * values, keep it in sync if you change them.
1251 */
1252 if (procost < 0)
1253 {
1254 /* SQL and PL-language functions are assumed more expensive */
1257 procost = 1;
1258 else
1259 procost = 100;
1260 }
1261 if (prorows < 0)
1262 {
1263 if (returnsSet)
1264 prorows = 1000;
1265 else
1266 prorows = 0; /* dummy value if not returnsSet */
1267 }
1268 else if (!returnsSet)
1269 ereport(ERROR,
1271 errmsg("ROWS is not applicable when function does not return a set")));
1272
1273 /*
1274 * And now that we have all the parameters, and know we're permitted to do
1275 * so, go ahead and create the function.
1276 */
1279 stmt->replace,
1280 returnsSet,
1281 prorettype,
1282 GetUserId(),
1285 prosrc_str, /* converted to text later */
1286 probin_str, /* converted to text later */
1287 prosqlbody,
1289 security,
1291 isStrict,
1292 volatility,
1293 parallel,
1294 parameterTypes,
1299 PointerGetDatum(trftypes),
1302 prosupport,
1303 procost,
1304 prorows);
1305}
@ ACLCHECK_NO_PRIV
Definition acl.h:185
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
float float4
Definition c.h:772
bool extension_file_exists(const char *extensionName)
Definition extension.c:2687
static void compute_return_type(TypeName *returnType, Oid languageOid, Oid *prorettype_p, bool *returnsSet_p)
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)
void interpret_function_parameter_list(ParseState *pstate, List *parameters, Oid languageOid, ObjectType objtype, oidvector **parameterTypes, List **parameterTypes_list, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **inParameterNames_list, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType)
static 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)
Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok)
#define funcname
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
Oid get_base_element_type(Oid typid)
Definition lsyscache.c:3148
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
void * palloc(Size size)
Definition mcxt.c:1390
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3559
#define castNode(_type_, nodeptr)
Definition nodes.h:180
@ OBJECT_SCHEMA
@ OBJECT_PROCEDURE
@ OBJECT_LANGUAGE
#define ACL_CREATE
Definition parsenodes.h:85
END_CATALOG_STRUCT typedef FormData_pg_language * Form_pg_language
Definition pg_language.h:69
#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:99
const char * p_sourcetext
Definition parse_node.h:214

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(), fb(), Form_pg_language, 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,
bool  check_rights 
)
extern

Definition at line 64 of file statscmds.c.

65{
67 int nattnums = 0;
68 int numcols;
69 char *namestr;
74 HeapTuple htup;
76 bool nulls[Natts_pg_statistic_ext];
78 List *stxexprs = NIL;
81 Relation rel = NULL;
82 Oid relid;
84 myself;
85 Datum types[4]; /* one for each possible type of statistic */
86 int ntypes;
88 bool build_ndistinct;
90 bool build_mcv;
92 bool requested_type = false;
93 int i;
94 ListCell *cell;
96
98
99 /*
100 * Examine the FROM clause. Currently, we only allow it to be a single
101 * simple table, but later we'll probably allow multiple tables and JOIN
102 * syntax. The grammar is already prepared for that, so we have to check
103 * here that what we got is what we can support.
104 */
105 if (list_length(stmt->relations) != 1)
108 errmsg("only a single relation is allowed in CREATE STATISTICS")));
109
110 foreach(cell, stmt->relations)
111 {
112 Node *rln = (Node *) lfirst(cell);
113
114 if (!IsA(rln, RangeVar))
117 errmsg("only a single relation is allowed in CREATE STATISTICS")));
118
119 /*
120 * CREATE STATISTICS will influence future execution plans but does
121 * not interfere with currently executing plans. So it should be
122 * enough to take only ShareUpdateExclusiveLock on relation,
123 * conflicting with ANALYZE and other DDL that sets statistical
124 * information, but not with normal queries.
125 */
127
128 /* Restrict to allowed relation types */
129 if (rel->rd_rel->relkind != RELKIND_RELATION &&
130 rel->rd_rel->relkind != RELKIND_MATVIEW &&
131 rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
132 rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
135 errmsg("cannot define statistics for relation \"%s\"",
138
139 /*
140 * You must own the relation to create stats on it.
141 *
142 * NB: Concurrent changes could cause this function's lookup to find a
143 * different relation than a previous lookup by the caller, so we must
144 * perform this check even when check_rights == false.
145 */
149
150 /*
151 * Conflict log tables are system-managed tables used internally for
152 * logical replication conflict logging. Unlike user tables, they are
153 * not expected to have complex query usage, so to keep things simple,
154 * user-defined extended statistics are not required or supported at
155 * present.
156 */
160 errmsg("cannot create statistics on conflict log table \"%s\"",
162 errdetail("Conflict log tables are system-managed tables for logical replication conflicts.")));
163
164 /* Creating statistics on system catalogs is not allowed */
168 errmsg("permission denied: \"%s\" is a system catalog",
170 }
171
172 Assert(rel);
173 relid = RelationGetRelid(rel);
174
175 /*
176 * If the node has a name, split it up and determine creation namespace.
177 * If not, put the object in the same namespace as the relation, and cons
178 * up a name for it. (This can happen either via "CREATE STATISTICS ..."
179 * or via "CREATE TABLE ... (LIKE)".)
180 */
181 if (stmt->defnames)
183 &namestr);
184 else
185 {
189 "stat",
191 }
193
194 /*
195 * Check we have creation rights in target namespace. Skip check if
196 * caller doesn't want it.
197 */
198 if (check_rights)
199 {
201
204 if (aclresult != ACLCHECK_OK)
207 }
208
209 /*
210 * Deal with the possibility that the statistics object already exists.
211 */
215 {
216 if (stmt->if_not_exists)
217 {
218 /*
219 * Since stats objects aren't members of extensions (see comments
220 * below), no need for checkMembershipInCurrentExtension here.
221 */
224 errmsg("statistics object \"%s\" already exists, skipping",
225 namestr)));
228 }
229
232 errmsg("statistics object \"%s\" already exists", namestr)));
233 }
234
235 /*
236 * Make sure no more than STATS_MAX_DIMENSIONS columns are used. There
237 * might be duplicates and so on, but we'll deal with those later.
238 */
239 numcols = list_length(stmt->exprs);
243 errmsg("cannot have more than %d columns in statistics",
245
246 /*
247 * Convert the expression list to a simple array of attnums, but also keep
248 * a list of more complex expressions. While at it, enforce some
249 * constraints - we don't allow extended statistics on system attributes,
250 * and we require the data type to have a less-than operator, if we're
251 * building multivariate statistics.
252 *
253 * There are many ways to "mask" a simple attribute reference as an
254 * expression, for example "(a+0)" etc. We can't possibly detect all of
255 * them, but we handle at least the simple case with the attribute in
256 * parens. There'll always be a way around this, if the user is determined
257 * (like the "(a+0)" example), but this makes it somewhat consistent with
258 * how indexes treat attributes/expressions.
259 */
260 foreach(cell, stmt->exprs)
261 {
263
264 if (selem->name) /* column reference */
265 {
266 char *attname;
270
271 attname = selem->name;
272
277 errmsg("column \"%s\" does not exist",
278 attname)));
280
281 /* Disallow use of system attributes in extended stats */
282 if (attForm->attnum <= 0)
285 errmsg("statistics creation on system columns is not supported")));
286
287 /*
288 * Disallow data types without a less-than operator in
289 * multivariate statistics.
290 */
291 if (numcols > 1)
292 {
294 if (type->lt_opr == InvalidOid)
297 errmsg("cannot create multivariate statistics on column \"%s\"",
298 attname),
299 errdetail("The type %s has no default btree operator class.",
300 format_type_be(attForm->atttypid))));
301 }
302
303 /* Treat virtual generated columns as expressions */
304 if (attForm->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
305 {
306 Node *expr;
307
308 expr = (Node *) makeVar(1,
309 attForm->attnum,
310 attForm->atttypid,
311 attForm->atttypmod,
312 attForm->attcollation,
313 0);
314 stxexprs = lappend(stxexprs, expr);
315 }
316 else
317 {
318 attnums[nattnums] = attForm->attnum;
319 nattnums++;
320 }
322 }
323 else if (IsA(selem->expr, Var)) /* column reference in parens */
324 {
325 Var *var = (Var *) selem->expr;
327
328 /* Disallow use of system attributes in extended stats */
329 if (var->varattno <= 0)
332 errmsg("statistics creation on system columns is not supported")));
333
334 /*
335 * Disallow data types without a less-than operator in
336 * multivariate statistics.
337 */
338 if (numcols > 1)
339 {
340 type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
341 if (type->lt_opr == InvalidOid)
344 errmsg("cannot create multivariate statistics on column \"%s\"",
345 get_attname(relid, var->varattno, false)),
346 errdetail("The type %s has no default btree operator class.",
347 format_type_be(var->vartype))));
348 }
349
350 /* Treat virtual generated columns as expressions */
351 if (get_attgenerated(relid, var->varattno) == ATTRIBUTE_GENERATED_VIRTUAL)
352 {
353 stxexprs = lappend(stxexprs, (Node *) var);
354 }
355 else
356 {
357 attnums[nattnums] = var->varattno;
358 nattnums++;
359 }
360 }
361 else /* expression */
362 {
363 Node *expr = selem->expr;
364 Oid atttype;
366 Bitmapset *attnums = NULL;
367 int k;
368
369 Assert(expr != NULL);
370
371 pull_varattnos(expr, 1, &attnums);
372
373 k = -1;
374 while ((k = bms_next_member(attnums, k)) >= 0)
375 {
377
378 /* Disallow expressions referencing system attributes. */
379 if (attnum <= 0)
382 errmsg("statistics creation on system columns is not supported")));
383 }
384
385 /*
386 * Disallow data types without a less-than operator in
387 * multivariate statistics.
388 */
389 if (numcols > 1)
390 {
391 atttype = exprType(expr);
393 if (type->lt_opr == InvalidOid)
396 errmsg("cannot create multivariate statistics on this expression"),
397 errdetail("The type %s has no default btree operator class.",
398 format_type_be(atttype))));
399 }
400
401 stxexprs = lappend(stxexprs, expr);
402 }
403 }
404
405 /*
406 * Check that at least two columns were specified in the statement, or
407 * that we're building statistics on a single expression (or virtual
408 * generated column).
409 */
410 if (numcols < 2 && list_length(stxexprs) != 1)
413 errmsg("cannot create extended statistics on a single non-virtual column"),
414 errdetail("Univariate statistics are already built for each individual non-virtual table column."));
415
416 /*
417 * Parse the statistics kinds (not allowed when building univariate
418 * statistics).
419 */
420 if (numcols == 1 && stmt->stat_types != NIL)
423 errmsg("cannot specify statistics kinds when building univariate statistics"));
424
425 build_ndistinct = false;
426 build_dependencies = false;
427 build_mcv = false;
428 foreach(cell, stmt->stat_types)
429 {
430 char *type = strVal(lfirst(cell));
431
432 if (strcmp(type, "ndistinct") == 0)
433 {
434 build_ndistinct = true;
435 requested_type = true;
436 }
437 else if (strcmp(type, "dependencies") == 0)
438 {
439 build_dependencies = true;
440 requested_type = true;
441 }
442 else if (strcmp(type, "mcv") == 0)
443 {
444 build_mcv = true;
445 requested_type = true;
446 }
447 else
450 errmsg("unrecognized statistics kind \"%s\"",
451 type)));
452 }
453
454 /*
455 * If no statistic type was specified, build them all (but only when the
456 * statistics is defined on more than one column/expression).
457 */
458 if ((!requested_type) && (numcols >= 2))
459 {
460 build_ndistinct = true;
461 build_dependencies = true;
462 build_mcv = true;
463 }
464
465 /*
466 * When there are non-trivial expressions, build the expression stats
467 * automatically. This allows calculating good estimates for stats that
468 * consider per-clause estimates (e.g. functional dependencies).
469 */
471
472 /*
473 * Sort the attnums, which makes detecting duplicates somewhat easier, and
474 * it does not hurt (it does not matter for the contents, unlike for
475 * indexes, for example).
476 */
477 qsort(attnums, nattnums, sizeof(int16), compare_int16);
478
479 /*
480 * Check for duplicates in the list of columns. The attnums are sorted so
481 * just check consecutive elements.
482 */
483 for (i = 1; i < nattnums; i++)
484 {
485 if (attnums[i] == attnums[i - 1])
488 errmsg("duplicate column name in statistics definition")));
489 }
490
491 /*
492 * Check for duplicate expressions. We do two loops, counting the
493 * occurrences of each expression. This is O(N^2) but we only allow small
494 * number of expressions and it's not executed often.
495 *
496 * XXX We don't cross-check attributes and expressions, because it does
497 * not seem worth it. In principle we could check that expressions don't
498 * contain trivial attribute references like "(a)", but the reasoning is
499 * similar to why we don't bother with extracting columns from
500 * expressions. It's either expensive or very easy to defeat for
501 * determined user, and there's no risk if we allow such statistics (the
502 * statistics is useless, but harmless).
503 */
504 foreach(cell, stxexprs)
505 {
506 Node *expr1 = (Node *) lfirst(cell);
507 int cnt = 0;
508
509 foreach(cell2, stxexprs)
510 {
511 Node *expr2 = (Node *) lfirst(cell2);
512
513 if (equal(expr1, expr2))
514 cnt += 1;
515 }
516
517 /* every expression should find at least itself */
518 Assert(cnt >= 1);
519
520 if (cnt > 1)
523 errmsg("duplicate expression in statistics definition")));
524 }
525
526 /* Form an int2vector representation of the sorted column list */
527 stxkeys = buildint2vector(attnums, nattnums);
528
529 /* construct the char array of enabled statistic types */
530 ntypes = 0;
531 if (build_ndistinct)
535 if (build_mcv)
539 Assert(ntypes > 0 && ntypes <= lengthof(types));
541
542 /* convert the expressions (if any) to a text datum */
543 if (stxexprs != NIL)
544 {
545 char *exprsString;
546
550 }
551 else
552 exprsDatum = (Datum) 0;
553
555
556 /*
557 * Everything seems fine, so let's build the pg_statistic_ext tuple.
558 */
559 memset(values, 0, sizeof(values));
560 memset(nulls, false, sizeof(nulls));
561
570 nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
572
574 if (exprsDatum == (Datum) 0)
575 nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
576
577 /* insert it into pg_statistic_ext */
578 htup = heap_form_tuple(statrel->rd_att, values, nulls);
580 heap_freetuple(htup);
581
583
584 /*
585 * We used to create the pg_statistic_ext_data tuple too, but it's not
586 * clear what value should the stxdinherit flag have (it depends on
587 * whether the rel is partitioned, contains data, etc.)
588 */
589
591
592 /*
593 * Invalidate relcache so that others see the new statistics object.
594 */
596
598
599 /*
600 * Add an AUTO dependency on each column used in the stats, so that the
601 * stats object goes away if any or all of them get dropped.
602 */
604
605 /* add dependencies for plain column references */
606 for (i = 0; i < nattnums; i++)
607 {
610 }
611
612 /*
613 * If there are no dependencies on a column, give the statistics object an
614 * auto dependency on the whole table. In most cases, this will be
615 * redundant, but it might not be if the statistics expressions contain no
616 * Vars (which might seem strange but possible). This is consistent with
617 * what we do for indexes in index_create.
618 *
619 * XXX We intentionally don't consider the expressions before adding this
620 * dependency, because recordDependencyOnSingleRelExpr may not create any
621 * dependencies for whole-row Vars.
622 */
623 if (!nattnums)
624 {
627 }
628
629 /*
630 * Store dependencies on anything mentioned in statistics expressions,
631 * just like we do for index expressions.
632 */
633 if (stxexprs)
635 (Node *) stxexprs,
636 relid,
638 DEPENDENCY_AUTO, false);
639
640 /*
641 * Also add dependencies on namespace and owner. These are required
642 * because the stats object might have a different namespace and/or owner
643 * than the underlying table(s).
644 */
647
649
650 /*
651 * XXX probably there should be a recordDependencyOnCurrentExtension call
652 * here too, but we'd have to add support for ALTER EXTENSION ADD/DROP
653 * STATISTICS, which is more work than it seems worth.
654 */
655
656 /* Add any requested comment */
657 if (stmt->stxcomment != NULL)
659 stmt->stxcomment);
660
661 /* Return stats object's address */
662 return myself;
663}
int16 AttrNumber
Definition attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
#define lengthof(array)
Definition c.h:932
bool IsConflictLogTableClass(Form_pg_class reltuple)
Definition catalog.c:242
bool IsSystemRelation(Relation relation)
Definition catalog.c:74
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition comment.c:153
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
@ DEPENDENCY_AUTO
Definition dependency.h:34
struct typedefs * types
Definition ecpg.c:30
int errdetail(const char *fmt,...) pg_attribute_printf(1
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
bool allowSystemTableMods
Definition globals.c:132
int2vector * buildint2vector(const int16 *int2s, int n)
Definition int.c:114
void CacheInvalidateRelcache(Relation relation)
Definition inval.c:1632
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition lsyscache.c:1114
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition lsyscache.c:1053
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition makefuncs.c:66
void namestrcpy(Name name, const char *str)
Definition name.c:233
#define IsA(nodeptr, _type_)
Definition nodes.h:162
ObjectType get_relkind_objtype(char relkind)
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
NameData attname
int16 attnum
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
#define qsort(a, b, c, d)
Definition port.h:496
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
#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:206
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition relation.c:138
#define STATS_MAX_DIMENSIONS
Definition statistics.h:19
static char * ChooseExtendedStatisticNameAddition(List *exprs)
Definition statscmds.c:921
static char * ChooseExtendedStatisticName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition statscmds.c:879
static int compare_int16(const void *a, const void *b)
Definition statscmds.c:51
Form_pg_class rd_rel
Definition rel.h:111
Definition c.h:889
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
HeapTuple SearchSysCacheAttName(Oid relid, const char *attname)
Definition syscache.c:476
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition syscache.h:102
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#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 ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, 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(), errdetail_relkind_not_supported(), errmsg, ERROR, exprType(), fb(), FirstLowInvalidHeapAttributeNumber, format_type_be(), get_attgenerated(), get_attname(), get_namespace_name(), get_relkind_objtype(), GetNewOidWithIndex(), GETSTRUCT(), GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, i, InvalidObjectAddress, InvalidOid, InvokeObjectPostCreateHook, IsA, IsConflictLogTableClass(), IsSystemRelation(), lappend(), lengthof, lfirst, lfirst_node, list_length(), lookup_type_cache(), makeVar(), NameGetDatum(), namestrcpy(), NIL, nodeToString(), NoLock, NOTICE, object_aclcheck(), object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectAddressSubSet, ObjectIdGetDatum(), pfree(), PointerGetDatum, pull_varattnos(), qsort, QualifiedNameGetCreationNamespace(), 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)
extern

Definition at line 1835 of file functioncmds.c.

1836{
1837 Oid typeid;
1838 char typtype;
1839 Oid langid;
1845 bool nulls[Natts_pg_transform] = {0};
1846 bool replaces[Natts_pg_transform] = {0};
1848 HeapTuple tuple;
1849 HeapTuple newtuple;
1850 Relation relation;
1852 referenced;
1853 ObjectAddresses *addrs;
1854 bool is_replace;
1855
1856 /*
1857 * Get the type
1858 */
1859 typeid = typenameTypeId(NULL, stmt->type_name);
1860 typtype = get_typtype(typeid);
1861
1862 if (typtype == TYPTYPE_PSEUDO)
1863 ereport(ERROR,
1865 errmsg("data type %s is a pseudo-type",
1866 TypeNameToString(stmt->type_name))));
1867
1868 if (typtype == TYPTYPE_DOMAIN)
1869 ereport(ERROR,
1871 errmsg("data type %s is a domain",
1872 TypeNameToString(stmt->type_name))));
1873
1876
1878 if (aclresult != ACLCHECK_OK)
1880
1881 /*
1882 * Get the language
1883 */
1884 langid = get_language_oid(stmt->lang, false);
1885
1887 if (aclresult != ACLCHECK_OK)
1889
1890 /*
1891 * Get the functions
1892 */
1893 if (stmt->fromsql)
1894 {
1896
1899
1901 if (aclresult != ACLCHECK_OK)
1903
1905 if (!HeapTupleIsValid(tuple))
1906 elog(ERROR, "cache lookup failed for function %u", fromsqlfuncid);
1908 if (procstruct->prorettype != INTERNALOID)
1909 ereport(ERROR,
1911 errmsg("return data type of FROM SQL function must be %s",
1912 "internal")));
1914 ReleaseSysCache(tuple);
1915 }
1916 else
1918
1919 if (stmt->tosql)
1920 {
1922
1925
1927 if (aclresult != ACLCHECK_OK)
1929
1931 if (!HeapTupleIsValid(tuple))
1932 elog(ERROR, "cache lookup failed for function %u", tosqlfuncid);
1934 if (procstruct->prorettype != typeid)
1935 ereport(ERROR,
1937 errmsg("return data type of TO SQL function must be the transform data type")));
1939 ReleaseSysCache(tuple);
1940 }
1941 else
1943
1944 /*
1945 * Ready to go
1946 */
1951
1953
1955 ObjectIdGetDatum(typeid),
1956 ObjectIdGetDatum(langid));
1957 if (HeapTupleIsValid(tuple))
1958 {
1960
1961 if (!stmt->replace)
1962 ereport(ERROR,
1964 errmsg("transform for type %s language \"%s\" already exists",
1965 format_type_be(typeid),
1966 stmt->lang)));
1967
1970
1971 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
1972 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1973
1974 transformid = form->oid;
1975 ReleaseSysCache(tuple);
1976 is_replace = true;
1977 }
1978 else
1979 {
1983 newtuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
1984 CatalogTupleInsert(relation, newtuple);
1985 is_replace = false;
1986 }
1987
1988 if (is_replace)
1990
1991 addrs = new_object_addresses();
1992
1993 /* make dependency entries */
1995
1996 /* dependency on language */
1999
2000 /* dependency on type */
2003
2004 /* dependencies on functions */
2006 {
2009 }
2011 {
2014 }
2015
2017 free_object_addresses(addrs);
2018
2019 /* dependency on extension */
2021
2022 /* Post creation hook for new transform */
2024
2025 heap_freetuple(newtuple);
2026
2027 table_close(relation, RowExclusiveLock);
2028
2029 return myself;
2030}
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
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:314
END_CATALOG_STRUCT typedef FormData_pg_transform * Form_pg_transform
Oid get_language_oid(const char *langname, bool missing_ok)
Definition proclang.c:227
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231

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, fb(), Form_pg_proc, Form_pg_transform, 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)
extern

Definition at line 1206 of file foreigncmds.c.

1207{
1208 Relation rel;
1211 bool nulls[Natts_pg_user_mapping];
1212 HeapTuple tuple;
1213 Oid useId;
1214 Oid umId;
1219 RoleSpec *role = (RoleSpec *) stmt->user;
1220
1222
1223 if (role->roletype == ROLESPEC_PUBLIC)
1225 else
1226 useId = get_rolespec_oid(stmt->user, false);
1227
1228 /* Check that the server exists. */
1229 srv = GetForeignServerByName(stmt->servername, false);
1230
1231 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1232
1233 /*
1234 * Check that the user mapping is unique within server.
1235 */
1238 ObjectIdGetDatum(srv->serverid));
1239
1240 if (OidIsValid(umId))
1241 {
1242 if (stmt->if_not_exists)
1243 {
1244 /*
1245 * Since user mappings aren't members of extensions (see comments
1246 * below), no need for checkMembershipInCurrentExtension here.
1247 */
1250 errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
1252 stmt->servername)));
1253
1255 return InvalidObjectAddress;
1256 }
1257 else
1258 ereport(ERROR,
1260 errmsg("user mapping for \"%s\" already exists for server \"%s\"",
1262 stmt->servername)));
1263 }
1264
1265 fdw = GetForeignDataWrapper(srv->fdwid);
1266
1267 /*
1268 * Insert tuple into pg_user_mapping.
1269 */
1270 memset(values, 0, sizeof(values));
1271 memset(nulls, false, sizeof(nulls));
1272
1278
1279 /* Add user options */
1282 stmt->options,
1283 fdw->fdwvalidator);
1284
1287 else
1288 nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1289
1290 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1291
1292 CatalogTupleInsert(rel, tuple);
1293
1294 heap_freetuple(tuple);
1295
1296 /* Add dependency on the server */
1297 myself.classId = UserMappingRelationId;
1298 myself.objectId = umId;
1299 myself.objectSubId = 0;
1300
1302 referenced.objectId = srv->serverid;
1303 referenced.objectSubId = 0;
1305
1306 if (OidIsValid(useId))
1307 {
1308 /* Record the mapped user dependency */
1310 }
1311
1312 /*
1313 * Perhaps someday there should be a recordDependencyOnCurrentExtension
1314 * call here; but since roles aren't members of extensions, it seems like
1315 * user mappings shouldn't be either. Note that the grammar and pg_dump
1316 * would need to be extended too if we change this.
1317 */
1318
1319 /* Post creation hook for new user mapping */
1321
1323
1324 return myself;
1325}

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

Referenced by ProcessUtilitySlow().

◆ defGetBoolean()

bool defGetBoolean ( DefElem def)
extern

Definition at line 93 of file define.c.

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

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

Referenced by AlterDatabase(), AlterOperator(), AlterReplicationSlot(), apply_server_options(), apply_table_options(), createdb(), CreateExtension(), dblink_fdw_validator(), DefineAggregate(), DefineCollation(), DefineOperator(), DefineType(), dintdict_init(), dsimple_init(), dsynonym_init(), dxsyn_init(), ExecCheckpoint(), ExecReindex(), ExecRepack(), ExecVacuum(), ExecWaitStmt(), 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(), pg_plan_advice_explain_option_handler(), postgres_fdw_validator(), postgresExecForeignTruncate(), postgresImportForeignSchema(), postgresImportForeignStatistics(), postgresIsForeignRelUpdatable(), ProcessCopyOptions(), transformExplainStmt(), transformRelOptions(), UserMappingPasswordRequired(), UseScramPassthrough(), and UseScramPassthrough().

◆ defGetInt32()

int32 defGetInt32 ( DefElem def)
extern

Definition at line 148 of file define.c.

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

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

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

◆ defGetInt64()

int64 defGetInt64 ( DefElem def)
extern

Definition at line 172 of file define.c.

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

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

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

◆ defGetNumeric()

double defGetNumeric ( DefElem def)
extern

Definition at line 67 of file define.c.

68{
69 if (def->arg == NULL)
72 errmsg("%s requires a numeric value",
73 def->defname)));
74 switch (nodeTag(def->arg))
75 {
76 case T_Integer:
77 return (double) intVal(def->arg);
78 case T_Float:
79 return floatVal(def->arg);
80 default:
83 errmsg("%s requires a numeric value",
84 def->defname)));
85 }
86 return 0; /* keep compiler quiet */
87}
#define floatVal(v)
Definition value.h:80

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

Referenced by AlterFunction(), and compute_function_attributes().

◆ defGetObjectId()

Oid defGetObjectId ( DefElem def)
extern

Definition at line 205 of file define.c.

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

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

Referenced by createdb().

◆ defGetQualifiedName()

List * defGetQualifiedName ( DefElem def)
extern

Definition at line 238 of file define.c.

239{
240 if (def->arg == NULL)
243 errmsg("%s requires a parameter",
244 def->defname)));
245 switch (nodeTag(def->arg))
246 {
247 case T_TypeName:
248 return ((TypeName *) def->arg)->names;
249 case T_List:
250 return (List *) def->arg;
251 case T_String:
252 /* Allow quoted name for backwards compatibility */
253 return list_make1(def->arg);
254 default:
257 errmsg("argument of %s must be a name",
258 def->defname)));
259 }
260 return NIL; /* keep compiler quiet */
261}
#define list_make1(x1)
Definition pg_list.h:244

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg, ERROR, fb(), 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)
extern

Definition at line 34 of file define.c.

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

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

Referenced by AlterDatabase(), AlterType(), apply_server_options(), apply_table_options(), build_remattrmap(), check_selective_binary_conversion(), createdb(), CreateExtension(), defGetBoolean(), defGetCopyHeaderOption(), defGetCopyLogVerbosityChoice(), defGetCopyOnErrorChoice(), defGetGeneratedColsOption(), defGetStreamingMode(), defGetTypeLength(), DefineAggregate(), DefineCollation(), DefineType(), deparseAnalyzeSql(), deparseColumnRef(), deparseRelation(), dintdict_init(), dispell_init(), dsimple_init(), dsnowball_init(), dsynonym_init(), dxsyn_init(), ExecCheckpoint(), ExecReindex(), ExecVacuum(), ExecWaitStmt(), ExplainResultDesc(), ExtractConnectionOptions(), extractModify(), fetch_remote_statistics(), 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)
extern

Definition at line 342 of file define.c.

343{
344 ListCell *cell;
345
346 if (def->arg == NULL)
349 errmsg("%s requires a parameter",
350 def->defname)));
351 if (!IsA(def->arg, List))
352 elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
353
354 foreach(cell, (List *) def->arg)
355 {
356 Node *str = (Node *) lfirst(cell);
357
358 if (!IsA(str, String))
359 elog(ERROR, "unexpected node type in name list: %d",
360 (int) nodeTag(str));
361 }
362
363 return (List *) def->arg;
364}
const char * str
Definition value.h:64

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

◆ defGetTypeLength()

int defGetTypeLength ( DefElem def)
extern

Definition at line 298 of file define.c.

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

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

Referenced by DefineType().

◆ defGetTypeName()

TypeName * defGetTypeName ( DefElem def)
extern

Definition at line 270 of file define.c.

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

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg, ERROR, fb(), 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 
)
extern

Definition at line 53 of file aggregatecmds.c.

59{
60 char *aggName;
72 bool finalfuncExtraArgs = false;
73 bool mfinalfuncExtraArgs = false;
74 char finalfuncModify = 0;
75 char mfinalfuncModify = 0;
77 TypeName *baseType = NULL;
80 int32 transSpace = 0;
82 char *initval = NULL;
83 char *minitval = NULL;
84 char *parallel = NULL;
85 int numArgs;
86 int numDirectArgs = 0;
87 oidvector *parameterTypes;
95 char transTypeType;
96 char mtransTypeType = 0;
98 ListCell *pl;
99
100 /* Convert list of names to a name and namespace */
102
103 /* Check we have creation rights in target namespace */
105 if (aclresult != ACLCHECK_OK)
108
109 /* Deconstruct the output of the aggr_args grammar production */
110 if (!oldstyle)
111 {
112 Assert(list_length(args) == 2);
114 if (numDirectArgs >= 0)
116 else
117 numDirectArgs = 0;
118 args = linitial_node(List, args);
119 }
120
121 /* Examine aggregate's definition clauses */
122 foreach(pl, parameters)
123 {
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)
132 else if (strcmp(defel->defname, "sfunc1") == 0)
134 else if (strcmp(defel->defname, "finalfunc") == 0)
136 else if (strcmp(defel->defname, "combinefunc") == 0)
138 else if (strcmp(defel->defname, "serialfunc") == 0)
140 else if (strcmp(defel->defname, "deserialfunc") == 0)
142 else if (strcmp(defel->defname, "msfunc") == 0)
144 else if (strcmp(defel->defname, "minvfunc") == 0)
146 else if (strcmp(defel->defname, "mfinalfunc") == 0)
148 else if (strcmp(defel->defname, "finalfunc_extra") == 0)
150 else if (strcmp(defel->defname, "mfinalfunc_extra") == 0)
152 else if (strcmp(defel->defname, "finalfunc_modify") == 0)
154 else if (strcmp(defel->defname, "mfinalfunc_modify") == 0)
156 else if (strcmp(defel->defname, "sortop") == 0)
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)
167 errmsg("only ordered-set aggregates can be hypothetical")));
169 }
170 }
171 else if (strcmp(defel->defname, "stype") == 0)
173 else if (strcmp(defel->defname, "stype1") == 0)
175 else if (strcmp(defel->defname, "sspace") == 0)
177 else if (strcmp(defel->defname, "mstype") == 0)
179 else if (strcmp(defel->defname, "msspace") == 0)
181 else if (strcmp(defel->defname, "initcond") == 0)
183 else if (strcmp(defel->defname, "initcond1") == 0)
185 else if (strcmp(defel->defname, "minitcond") == 0)
187 else if (strcmp(defel->defname, "parallel") == 0)
189 else
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)
202 errmsg("aggregate stype must be specified")));
203 if (transfuncName == NIL)
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)
218 errmsg("aggregate msfunc must be specified when mstype is specified")));
219 if (minvtransfuncName == NIL)
222 errmsg("aggregate minvfunc must be specified when mstype is specified")));
223 }
224 else
225 {
226 if (mtransfuncName != NIL)
229 errmsg("aggregate msfunc must not be specified without mstype")));
230 if (minvtransfuncName != NIL)
233 errmsg("aggregate minvfunc must not be specified without mstype")));
234 if (mfinalfuncName != NIL)
237 errmsg("aggregate mfinalfunc must not be specified without mstype")));
238 if (mtransSpace != 0)
241 errmsg("aggregate msspace must not be specified without mstype")));
242 if (minitval != NULL)
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)
254 if (mfinalfuncModify == 0)
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)
274 errmsg("aggregate input type must be specified")));
275
276 if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
277 {
278 numArgs = 0;
280 }
281 else
282 {
283 numArgs = 1;
284 aggArgTypes[0] = typenameTypeId(NULL, baseType);
285 }
286 parameterTypes = buildoidvector(aggArgTypes, numArgs);
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 */
300
301 if (baseType != NULL)
304 errmsg("basetype is redundant with aggregate input type specification")));
305
306 numArgs = list_length(args);
308 args,
311 &parameterTypes,
312 NULL,
316 NULL,
320 /* Parameter defaults are not currently allowed by the grammar */
322 /* There shouldn't have been any OUT parameters, either */
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 */
341 {
343 /* okay */ ;
344 else
347 errmsg("aggregate transition data type cannot be %s",
349 }
350
352 {
353 /*
354 * Serialization is only needed/allowed for transtype INTERNAL.
355 */
359 errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
361 }
363 {
364 /*
365 * Cannot specify one function without the other.
366 */
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 {
382 {
384 /* okay */ ;
385 else
388 errmsg("aggregate transition data type cannot be %s",
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 */
403 {
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 */
415 {
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)
427 else if (strcmp(parallel, "restricted") == 0)
429 else if (strcmp(parallel, "unsafe") == 0)
431 else
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,
446 parameterTypes,
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 */
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:270
int32 defGetInt32(DefElem *def)
Definition define.c:148
Datum OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
Definition fmgr.c:1755
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition lsyscache.c:3190
oidvector * buildoidvector(const Oid *oids, int n)
Definition oid.c:87
@ OBJECT_AGGREGATE
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)
#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(), Assert, buildoidvector(), defGetBoolean(), defGetInt32(), defGetQualifiedName(), defGetString(), defGetTypeName(), ereport, errcode(), errmsg, ERROR, extractModify(), fb(), 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 ( ParseState pstate,
Oid  tableId,
const 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 
)
extern

Definition at line 555 of file indexcmds.c.

567{
568 bool concurrent;
569 char *indexRelationName;
570 char *accessMethodName;
571 Oid *typeIds;
581 Relation rel;
582 HeapTuple tuple;
585 bool amcanorder;
586 bool amissummarizing;
587 amoptions_function amoptions;
588 bool exclusion;
589 bool partitioned;
590 bool safe_index;
591 Datum reloptions;
593 IndexInfo *indexInfo;
594 uint16 flags;
599 ObjectAddress address;
600 LockRelId heaprelid;
602 LOCKMODE lockmode;
603 Snapshot snapshot;
607
609
611
612 /*
613 * Some callers need us to run with an empty default_tablespace; this is a
614 * necessary hack to be able to reproduce catalog state accurately when
615 * recreating indexes after table-rewriting ALTER TABLE.
616 */
617 if (stmt->reset_default_tblspc)
618 (void) set_config_option("default_tablespace", "",
620 GUC_ACTION_SAVE, true, 0, false);
621
622 /*
623 * Force non-concurrent build on temporary relations, even if CONCURRENTLY
624 * was requested. Other backends can't access a temporary relation, so
625 * there's no harm in grabbing a stronger lock, and a non-concurrent DROP
626 * is more efficient. Do this before any use of the concurrent option is
627 * done.
628 */
630 concurrent = true;
631 else
632 concurrent = false;
633
634 /*
635 * Start progress report. If we're building a partition, this was already
636 * done.
637 */
639 {
642 concurrent ?
645 }
646
647 /*
648 * No index OID to report yet
649 */
651 InvalidOid);
652
653 /*
654 * count key attributes in index
655 */
656 numberOfKeyAttributes = list_length(stmt->indexParams);
657
658 /*
659 * Calculate the new list of index columns including both key columns and
660 * INCLUDE columns. Later we can determine which of these are key
661 * columns, and which are just part of the INCLUDE list by checking the
662 * list position. A list item in a position less than ii_NumIndexKeyAttrs
663 * is part of the key columns, and anything equal to and over is part of
664 * the INCLUDE columns.
665 */
666 allIndexParams = list_concat_copy(stmt->indexParams,
667 stmt->indexIncludingParams);
669
670 if (numberOfKeyAttributes <= 0)
673 errmsg("must specify at least one column")));
677 errmsg("cannot use more than %d columns in an index",
679
680 /*
681 * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
682 * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
683 * (but not VACUUM).
684 *
685 * NB: Caller is responsible for making sure that tableId refers to the
686 * relation on which the index should be built; except in bootstrap mode,
687 * this will typically require the caller to have already locked the
688 * relation. To avoid lock upgrade hazards, that lock should be at least
689 * as strong as the one we take here.
690 *
691 * NB: If the lock strength here ever changes, code that is run by
692 * parallel workers under the control of certain particular ambuild
693 * functions will need to be updated, too.
694 */
695 lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
696 rel = table_open(tableId, lockmode);
697
698 /*
699 * Switch to the table owner's userid, so that any index functions are run
700 * as that user. Also lock down security-restricted operations. We
701 * already arranged to make GUC variable changes local to this command.
702 */
704 SetUserIdAndSecContext(rel->rd_rel->relowner,
706
708
709 /*
710 * It has exclusion constraint behavior if it's an EXCLUDE constraint or a
711 * temporal PRIMARY KEY/UNIQUE constraint
712 */
713 exclusion = stmt->excludeOpNames || stmt->iswithoutoverlaps;
714
715 /* Ensure that it makes sense to index this kind of relation */
716 switch (rel->rd_rel->relkind)
717 {
718 case RELKIND_RELATION:
719 case RELKIND_MATVIEW:
721 /* OK */
722 break;
723 default:
726 errmsg("cannot create index on relation \"%s\"",
729 break;
730 }
731
732 /*
733 * Establish behavior for partitioned tables, and verify sanity of
734 * parameters.
735 *
736 * We do not build an actual index in this case; we only create a few
737 * catalog entries. The actual indexes are built by recursing for each
738 * partition.
739 */
741 if (partitioned)
742 {
743 /*
744 * Note: we check 'stmt->concurrent' rather than 'concurrent', so that
745 * the error is thrown also for temporary tables. Seems better to be
746 * consistent, even though we could do it on temporary table because
747 * we're not actually doing it concurrently.
748 */
749 if (stmt->concurrent)
752 errmsg("cannot create index on partitioned table \"%s\" concurrently",
754 }
755
756 /*
757 * Don't try to CREATE INDEX on temp tables of other backends.
758 */
759 if (RELATION_IS_OTHER_TEMP(rel))
762 errmsg("cannot create indexes on temporary tables of other sessions")));
763
764 /*
765 * Unless our caller vouches for having checked this already, insist that
766 * the table not be in use by our own session, either. Otherwise we might
767 * fail to make entries in the new index (for instance, if an INSERT or
768 * UPDATE is in progress and has already made its list of target indexes).
769 */
771 CheckTableNotInUse(rel, "CREATE INDEX");
772
773 /*
774 * Verify we (still) have CREATE rights in the rel's namespace.
775 * (Presumably we did when the rel was created, but maybe not anymore.)
776 * Skip check if caller doesn't want it. Also skip check if
777 * bootstrapping, since permissions machinery may not be working yet.
778 */
780 {
782
784 ACL_CREATE);
785 if (aclresult != ACLCHECK_OK)
788 }
789
790 /*
791 * Select tablespace to use. If not specified, use default tablespace
792 * (which may in turn default to database's default).
793 */
794 if (stmt->tableSpace)
795 {
796 tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
800 errmsg("cannot specify default tablespace for partitioned relations")));
801 }
802 else
803 {
804 tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence,
806 /* note InvalidOid is OK in this case */
807 }
808
809 /* Check tablespace permissions */
810 if (check_rights &&
812 {
814
816 ACL_CREATE);
817 if (aclresult != ACLCHECK_OK)
820 }
821
822 /*
823 * Force shared indexes into the pg_global tablespace. This is a bit of a
824 * hack but seems simpler than marking them in the BKI commands. On the
825 * other hand, if it's not shared, don't allow it to be placed there.
826 */
827 if (rel->rd_rel->relisshared)
832 errmsg("only shared relations can be placed in pg_global tablespace")));
833
834 /*
835 * Choose the index column names.
836 */
838
839 /*
840 * Select name for index if caller didn't specify
841 */
842 indexRelationName = stmt->idxname;
843 if (indexRelationName == NULL)
847 stmt->excludeOpNames,
848 stmt->primary,
849 stmt->isconstraint);
850
851 /*
852 * look up the access method, verify it can handle the requested features
853 */
854 accessMethodName = stmt->accessMethod;
856 if (!HeapTupleIsValid(tuple))
857 {
858 /*
859 * Hack to provide more-or-less-transparent updating of old RTREE
860 * indexes to GiST: if RTREE is requested and not found, use GIST.
861 */
862 if (strcmp(accessMethodName, "rtree") == 0)
863 {
865 (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
866 accessMethodName = "gist";
868 }
869
870 if (!HeapTupleIsValid(tuple))
873 errmsg("access method \"%s\" does not exist",
875 }
879
882
883 if (stmt->unique && !stmt->iswithoutoverlaps && !amRoutine->amcanunique)
886 errmsg("access method \"%s\" does not support unique indexes",
888 if (stmt->indexIncludingParams != NIL && !amRoutine->amcaninclude)
891 errmsg("access method \"%s\" does not support included columns",
893 if (numberOfKeyAttributes > 1 && !amRoutine->amcanmulticol)
896 errmsg("access method \"%s\" does not support multicolumn indexes",
898 if (exclusion && amRoutine->amgettuple == NULL)
901 errmsg("access method \"%s\" does not support exclusion constraints",
903 if (stmt->iswithoutoverlaps && strcmp(accessMethodName, "gist") != 0)
906 errmsg("access method \"%s\" does not support WITHOUT OVERLAPS constraints",
908
909 amcanorder = amRoutine->amcanorder;
910 amoptions = amRoutine->amoptions;
911 amissummarizing = amRoutine->amsummarizing;
912
913 ReleaseSysCache(tuple);
914
915 /*
916 * Validate predicate, if given
917 */
918 if (stmt->whereClause)
919 CheckPredicate((Expr *) stmt->whereClause);
920
921 /*
922 * Parse AM-specific options, convert to text array form, validate.
923 */
924 reloptions = transformRelOptions((Datum) 0, stmt->options,
925 NULL, NULL, false, false);
926
927 (void) index_reloptions(amoptions, reloptions, true);
928
929 /*
930 * Prepare arguments for index_create, primarily an IndexInfo structure.
931 * Note that predicates must be in implicit-AND format. In a concurrent
932 * build, mark it not-ready-for-inserts.
933 */
937 NIL, /* expressions, NIL for now */
938 make_ands_implicit((Expr *) stmt->whereClause),
939 stmt->unique,
940 stmt->nulls_not_distinct,
941 !concurrent,
942 concurrent,
944 stmt->iswithoutoverlaps);
945
951 ComputeIndexAttrs(pstate,
952 indexInfo,
955 stmt->excludeOpNames, tableId,
957 amcanorder, stmt->isconstraint, stmt->iswithoutoverlaps,
960
961 /*
962 * Extra checks when creating a PRIMARY KEY index.
963 */
964 if (stmt->primary)
966
967 /*
968 * If this table is partitioned and we're creating a unique index, primary
969 * key, or exclusion constraint, make sure that the partition key is a
970 * subset of the index's columns. Otherwise it would be possible to
971 * violate uniqueness by putting values that ought to be unique in
972 * different partitions.
973 *
974 * We could lift this limitation if we had global indexes, but those have
975 * their own problems, so this is a useful feature combination.
976 */
977 if (partitioned && (stmt->unique || exclusion))
978 {
980 const char *constraint_type;
981 int i;
982
983 if (stmt->primary)
984 constraint_type = "PRIMARY KEY";
985 else if (stmt->unique)
986 constraint_type = "UNIQUE";
987 else if (stmt->excludeOpNames)
988 constraint_type = "EXCLUDE";
989 else
990 {
991 elog(ERROR, "unknown constraint type");
992 constraint_type = NULL; /* keep compiler quiet */
993 }
994
995 /*
996 * Verify that all the columns in the partition key appear in the
997 * unique key definition, with the same notion of equality.
998 */
999 for (i = 0; i < key->partnatts; i++)
1000 {
1001 bool found = false;
1002 int eq_strategy;
1004 int j;
1005
1006 /*
1007 * Identify the equality operator associated with this partkey
1008 * column. For list and range partitioning, partkeys use btree
1009 * operator classes; hash partitioning uses hash operator classes.
1010 * (Keep this in sync with ComputePartitionAttrs!)
1011 */
1012 if (key->strategy == PARTITION_STRATEGY_HASH)
1014 else
1016
1017 ptkey_eqop = get_opfamily_member(key->partopfamily[i],
1018 key->partopcintype[i],
1019 key->partopcintype[i],
1020 eq_strategy);
1021 if (!OidIsValid(ptkey_eqop))
1022 elog(ERROR, "missing operator %d(%u,%u) in partition opfamily %u",
1023 eq_strategy, key->partopcintype[i], key->partopcintype[i],
1024 key->partopfamily[i]);
1025
1026 /*
1027 * It may be possible to support UNIQUE constraints when partition
1028 * keys are expressions, but is it worth it? Give up for now.
1029 */
1030 if (key->partattrs[i] == 0)
1031 ereport(ERROR,
1033 errmsg("unsupported %s constraint with partition key definition",
1035 errdetail("%s constraints cannot be used when partition keys include expressions.",
1036 constraint_type)));
1037
1038 /* Search the index column(s) for a match */
1039 for (j = 0; j < indexInfo->ii_NumIndexKeyAttrs; j++)
1040 {
1041 if (key->partattrs[i] == indexInfo->ii_IndexAttrNumbers[j])
1042 {
1043 /*
1044 * Matched the column, now what about the collation and
1045 * equality op?
1046 */
1049
1050 if (key->partcollation[i] != collationIds[j])
1051 continue;
1052
1054 &idx_opfamily,
1055 &idx_opcintype))
1056 {
1058
1059 if (stmt->unique && !stmt->iswithoutoverlaps)
1063 COMPARE_EQ);
1064 else if (exclusion)
1065 idx_eqop = indexInfo->ii_ExclusionOps[j];
1066
1067 if (!idx_eqop)
1068 ereport(ERROR,
1070 errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
1071 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
1073
1074 if (ptkey_eqop == idx_eqop)
1075 {
1076 found = true;
1077 break;
1078 }
1079 else if (exclusion)
1080 {
1081 /*
1082 * We found a match, but it's not an equality
1083 * operator. Instead of failing below with an
1084 * error message about a missing column, fail now
1085 * and explain that the operator is wrong.
1086 */
1087 Form_pg_attribute att = TupleDescAttr(RelationGetDescr(rel), key->partattrs[i] - 1);
1088
1089 ereport(ERROR,
1091 errmsg("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"",
1092 NameStr(att->attname),
1093 get_opname(indexInfo->ii_ExclusionOps[j]))));
1094 }
1095 }
1096 }
1097 }
1098
1099 if (!found)
1100 {
1102
1104 key->partattrs[i] - 1);
1105 ereport(ERROR,
1107 /* translator: %s is UNIQUE, PRIMARY KEY, etc */
1108 errmsg("%s constraint on partitioned table must include all partitioning columns",
1110 /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
1111 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
1113 NameStr(att->attname))));
1114 }
1115 }
1116 }
1117
1118
1119 /*
1120 * We disallow indexes on system columns. They would not necessarily get
1121 * updated correctly, and they don't seem useful anyway.
1122 *
1123 * Also disallow virtual generated columns in indexes (use expression
1124 * index instead).
1125 */
1126 for (int i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
1127 {
1128 AttrNumber attno = indexInfo->ii_IndexAttrNumbers[i];
1129
1130 if (attno < 0)
1131 ereport(ERROR,
1133 errmsg("index creation on system columns is not supported")));
1134
1135
1136 if (attno > 0 &&
1137 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1138 ereport(ERROR,
1140 stmt->primary ?
1141 errmsg("primary keys on virtual generated columns are not supported") :
1142 stmt->isconstraint ?
1143 errmsg("unique constraints on virtual generated columns are not supported") :
1144 errmsg("indexes on virtual generated columns are not supported"));
1145 }
1146
1147 /*
1148 * Also check for system and generated columns used in expressions or
1149 * predicates.
1150 */
1151 if (indexInfo->ii_Expressions || indexInfo->ii_Predicate)
1152 {
1154 int j;
1155
1156 pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);
1157 pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);
1158
1159 for (int i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++)
1160 {
1162 indexattrs))
1163 ereport(ERROR,
1165 errmsg("index creation on system columns is not supported")));
1166 }
1167
1168 /*
1169 * XXX Virtual generated columns in index expressions or predicates
1170 * could be supported, but it needs support in
1171 * RelationGetIndexExpressions() and RelationGetIndexPredicate().
1172 */
1173 j = -1;
1174 while ((j = bms_next_member(indexattrs, j)) >= 0)
1175 {
1177
1178 if (attno > 0 &&
1179 TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1180 ereport(ERROR,
1182 stmt->isconstraint ?
1183 errmsg("unique constraints on virtual generated columns are not supported") :
1184 errmsg("indexes on virtual generated columns are not supported")));
1185 }
1186 }
1187
1188 /* Is index safe for others to ignore? See set_indexsafe_procflags() */
1189 safe_index = indexInfo->ii_Expressions == NIL &&
1190 indexInfo->ii_Predicate == NIL;
1191
1192 /*
1193 * Report index creation if appropriate (delay this till after most of the
1194 * error checks)
1195 */
1196 if (stmt->isconstraint && !quiet)
1197 {
1198 const char *constraint_type;
1199
1200 if (stmt->primary)
1201 constraint_type = "PRIMARY KEY";
1202 else if (stmt->unique)
1203 constraint_type = "UNIQUE";
1204 else if (stmt->excludeOpNames)
1205 constraint_type = "EXCLUDE";
1206 else
1207 {
1208 elog(ERROR, "unknown constraint type");
1209 constraint_type = NULL; /* keep compiler quiet */
1210 }
1211
1213 (errmsg_internal("%s %s will create implicit index \"%s\" for table \"%s\"",
1214 is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
1217 }
1218
1219 /*
1220 * A valid stmt->oldNumber implies that we already have a built form of
1221 * the index. The caller should also decline any index build.
1222 */
1223 Assert(!RelFileNumberIsValid(stmt->oldNumber) || (skip_build && !concurrent));
1224
1225 /*
1226 * Make the catalog entries for the index, including constraints. This
1227 * step also actually builds the index, except if caller requested not to
1228 * or in concurrent mode, in which case it'll be done later, or doing a
1229 * partitioned index (because those don't have storage).
1230 */
1231 flags = constr_flags = 0;
1232 if (stmt->isconstraint)
1234 if (skip_build || concurrent || partitioned)
1235 flags |= INDEX_CREATE_SKIP_BUILD;
1236 if (stmt->if_not_exists)
1238 if (concurrent)
1239 flags |= INDEX_CREATE_CONCURRENT;
1240 if (partitioned)
1241 flags |= INDEX_CREATE_PARTITIONED;
1242 if (stmt->primary)
1243 flags |= INDEX_CREATE_IS_PRIMARY;
1244
1245 /*
1246 * If the table is partitioned, and recursion was declined but partitions
1247 * exist, mark the index as invalid.
1248 */
1249 if (partitioned && stmt->relation && !stmt->relation->inh)
1250 {
1252
1253 if (pd->nparts != 0)
1254 flags |= INDEX_CREATE_INVALID;
1255 }
1256
1257 if (stmt->deferrable)
1259 if (stmt->initdeferred)
1261 if (stmt->iswithoutoverlaps)
1263
1267 stmt->oldNumber, indexInfo, indexColNames,
1270 coloptions, NULL, reloptions,
1271 flags, constr_flags,
1274
1276
1278 {
1279 /*
1280 * Roll back any GUC changes executed by index functions. Also revert
1281 * to original default_tablespace if we changed it above.
1282 */
1284
1285 /* Restore userid and security context */
1287
1288 table_close(rel, NoLock);
1289
1290 /* If this is the top-level index, we're done */
1293
1294 return address;
1295 }
1296
1297 /*
1298 * Roll back any GUC changes executed by index functions, and keep
1299 * subsequent changes local to this command. This is essential if some
1300 * index function changed a behavior-affecting GUC, e.g. search_path.
1301 */
1305
1306 /* Add any requested comment */
1307 if (stmt->idxcomment != NULL)
1309 stmt->idxcomment);
1310
1311 if (partitioned)
1312 {
1313 PartitionDesc partdesc;
1314
1315 /*
1316 * Unless caller specified to skip this step (via ONLY), process each
1317 * partition to make sure they all contain a corresponding index.
1318 *
1319 * If we're called internally (no stmt->relation), recurse always.
1320 */
1321 partdesc = RelationGetPartitionDesc(rel, true);
1322 if ((!stmt->relation || stmt->relation->inh) && partdesc->nparts > 0)
1323 {
1324 int nparts = partdesc->nparts;
1325 Oid *part_oids = palloc_array(Oid, nparts);
1326 bool invalidate_parent = false;
1329
1330 /*
1331 * Report the total number of partitions at the start of the
1332 * command; don't update it when being called recursively.
1333 */
1335 {
1336 /*
1337 * When called by ProcessUtilitySlow, the number of partitions
1338 * is passed in as an optimization; but other callers pass -1
1339 * since they don't have the value handy. This should count
1340 * partitions the same way, ie one less than the number of
1341 * relations find_all_inheritors reports.
1342 *
1343 * We assume we needn't ask find_all_inheritors to take locks,
1344 * because that should have happened already for all callers.
1345 * Even if it did not, this is safe as long as we don't try to
1346 * touch the partitions here; the worst consequence would be a
1347 * bogus progress-reporting total.
1348 */
1349 if (total_parts < 0)
1350 {
1352
1353 total_parts = list_length(children) - 1;
1354 list_free(children);
1355 }
1356
1358 total_parts);
1359 }
1360
1361 /* Make a local copy of partdesc->oids[], just for safety */
1362 memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
1363
1364 /*
1365 * We'll need an IndexInfo describing the parent index. The one
1366 * built above is almost good enough, but not quite, because (for
1367 * example) its predicate expression if any hasn't been through
1368 * expression preprocessing. The most reliable way to get an
1369 * IndexInfo that will match those for child indexes is to build
1370 * it the same way, using BuildIndexInfo().
1371 */
1373 indexInfo = BuildIndexInfo(parentIndex);
1374
1376
1377 /*
1378 * For each partition, scan all existing indexes; if one matches
1379 * our index definition and is not already attached to some other
1380 * parent index, attach it to the one we just created.
1381 *
1382 * If none matches, build a new index by calling ourselves
1383 * recursively with the same options (except for the index name).
1384 */
1385 for (int i = 0; i < nparts; i++)
1386 {
1392 List *childidxs;
1393 ListCell *cell;
1394 AttrMap *attmap;
1395 bool found = false;
1396
1397 childrel = table_open(childRelid, lockmode);
1398
1401 SetUserIdAndSecContext(childrel->rd_rel->relowner,
1405
1406 /*
1407 * Don't try to create indexes on foreign tables, though. Skip
1408 * those if a regular index, or fail if trying to create a
1409 * constraint index.
1410 */
1411 if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1412 {
1413 if (stmt->unique || stmt->primary)
1414 ereport(ERROR,
1416 errmsg("cannot create unique index on partitioned table \"%s\"",
1418 errdetail("Table \"%s\" contains partitions that are foreign tables.",
1420
1424 table_close(childrel, lockmode);
1425 continue;
1426 }
1427
1429 attmap =
1431 parentDesc,
1432 false);
1433
1434 foreach(cell, childidxs)
1435 {
1436 Oid cldidxid = lfirst_oid(cell);
1439
1440 /* this index is already partition of another one */
1442 continue;
1443
1444 cldidx = index_open(cldidxid, lockmode);
1446 if (CompareIndexInfo(cldIdxInfo, indexInfo,
1447 cldidx->rd_indcollation,
1448 parentIndex->rd_indcollation,
1449 cldidx->rd_opfamily,
1450 parentIndex->rd_opfamily,
1451 attmap))
1452 {
1454
1455 /*
1456 * Found a match.
1457 *
1458 * If this index is being created in the parent
1459 * because of a constraint, then the child needs to
1460 * have a constraint also, so look for one. If there
1461 * is no such constraint, this index is no good, so
1462 * keep looking.
1463 */
1465 {
1466 cldConstrOid =
1468 cldidxid);
1469 if (cldConstrOid == InvalidOid)
1470 {
1471 index_close(cldidx, lockmode);
1472 continue;
1473 }
1474 }
1475
1476 /* Attach index to parent and we're done. */
1481 childRelid);
1482
1483 if (!cldidx->rd_index->indisvalid)
1484 invalidate_parent = true;
1485
1486 found = true;
1487
1488 /*
1489 * Report this partition as processed. Note that if
1490 * the partition has children itself, we'd ideally
1491 * count the children and update the progress report
1492 * for all of them; but that seems unduly expensive.
1493 * Instead, the progress report will act like all such
1494 * indirect children were processed in zero time at
1495 * the end of the command.
1496 */
1498
1499 /* keep lock till commit */
1501 break;
1502 }
1503
1504 index_close(cldidx, lockmode);
1505 }
1506
1512
1513 /*
1514 * If no matching index was found, create our own.
1515 */
1516 if (!found)
1517 {
1520
1521 /*
1522 * Build an IndexStmt describing the desired child index
1523 * in the same way that we do during ATTACH PARTITION.
1524 * Notably, we rely on generateClonedIndexStmt to produce
1525 * a search-path-independent representation, which the
1526 * original IndexStmt might not be.
1527 */
1530 attmap,
1531 NULL);
1532
1533 /*
1534 * Recurse as the starting user ID. Callee will use that
1535 * for permission checks, then switch again.
1536 */
1540 childAddr =
1541 DefineIndex(NULL, /* original pstate not applicable */
1543 InvalidOid, /* no predefined OID */
1544 indexRelationId, /* this is our child */
1546 -1,
1549 skip_build, quiet);
1552
1553 /*
1554 * Check if the index just created is valid or not, as it
1555 * could be possible that it has been switched as invalid
1556 * when recursing across multiple partition levels.
1557 */
1558 if (!get_index_isvalid(childAddr.objectId))
1559 invalidate_parent = true;
1560 }
1561
1563 }
1564
1565 index_close(parentIndex, lockmode);
1566
1567 /*
1568 * The pg_index row we inserted for this index was marked
1569 * indisvalid=true. But if we attached an existing index that is
1570 * invalid, this is incorrect, so update our row to invalid too.
1571 */
1573 {
1575 HeapTuple tup,
1576 newtup;
1577
1580 if (!HeapTupleIsValid(tup))
1581 elog(ERROR, "cache lookup failed for index %u",
1589
1590 /*
1591 * CCI here to make this update visible, in case this recurses
1592 * across multiple partition levels.
1593 */
1595 }
1596 }
1597
1598 /*
1599 * Indexes on partitioned tables are not themselves built, so we're
1600 * done here.
1601 */
1604 table_close(rel, NoLock);
1607 else
1608 {
1609 /* Update progress for an intermediate partitioned index itself */
1611 }
1612
1613 return address;
1614 }
1615
1618
1619 if (!concurrent)
1620 {
1621 /* Close the heap and we're done, in the non-concurrent case */
1622 table_close(rel, NoLock);
1623
1624 /*
1625 * If this is the top-level index, the command is done overall;
1626 * otherwise, increment progress to report one child index is done.
1627 */
1630 else
1632
1633 return address;
1634 }
1635
1636 /* save lockrelid and locktag for below, then close rel */
1637 heaprelid = rel->rd_lockInfo.lockRelId;
1638 SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
1639 table_close(rel, NoLock);
1640
1641 /*
1642 * For a concurrent build, it's important to make the catalog entries
1643 * visible to other transactions before we start to build the index. That
1644 * will prevent them from making incompatible HOT updates. The new index
1645 * will be marked not indisready and not indisvalid, so that no one else
1646 * tries to either insert into it or use it for queries.
1647 *
1648 * We must commit our current transaction so that the index becomes
1649 * visible; then start another. Note that all the data structures we just
1650 * built are lost in the commit. The only data we keep past here are the
1651 * relation IDs.
1652 *
1653 * Before committing, get a session-level lock on the table, to ensure
1654 * that neither it nor the index can be dropped before we finish. This
1655 * cannot block, even if someone else is waiting for access, because we
1656 * already have the same lock within our transaction.
1657 *
1658 * Note: we don't currently bother with a session lock on the index,
1659 * because there are no operations that could change its state while we
1660 * hold lock on the parent table. This might need to change later.
1661 */
1663
1667
1668 /* Tell concurrent index builds to ignore us, if index qualifies */
1669 if (safe_index)
1671
1672 /*
1673 * The index is now visible, so we can report the OID. While on it,
1674 * include the report for the beginning of phase 2.
1675 */
1676 {
1677 const int progress_cols[] = {
1680 };
1681 const int64 progress_vals[] = {
1684 };
1685
1687 }
1688
1689 /*
1690 * Phase 2 of concurrent index build (see comments for validate_index()
1691 * for an overview of how this works)
1692 *
1693 * Now we must wait until no running transaction could have the table open
1694 * with the old list of indexes. Use ShareLock to consider running
1695 * transactions that hold locks that permit writing to the table. Note we
1696 * do not need to worry about xacts that open the table for writing after
1697 * this point; they will see the new index when they open it.
1698 *
1699 * Note: the reason we use actual lock acquisition here, rather than just
1700 * checking the ProcArray and sleeping, is that deadlock is possible if
1701 * one of the transactions in question is blocked trying to acquire an
1702 * exclusive lock on our table. The lock code will detect deadlock and
1703 * error out properly.
1704 */
1706
1707 /*
1708 * At this moment we are sure that there are no transactions with the
1709 * table open for write that don't have this new index in their list of
1710 * indexes. We have waited out all the existing transactions and any new
1711 * transaction will have the new index in its list, but the index is still
1712 * marked as "not-ready-for-inserts". The index is consulted while
1713 * deciding HOT-safety though. This arrangement ensures that no new HOT
1714 * chains can be created where the new tuple and the old tuple in the
1715 * chain have different index keys.
1716 *
1717 * We now take a new snapshot, and build the index using all tuples that
1718 * are visible in this snapshot. We can be sure that any HOT updates to
1719 * these tuples will be compatible with the index, since any updates made
1720 * by transactions that didn't know about the index are now committed or
1721 * rolled back. Thus, each visible tuple is either the end of its
1722 * HOT-chain or the extension of the chain is HOT-safe for this index.
1723 */
1724
1725 /* Set ActiveSnapshot since functions in the indexes may need it */
1727
1728 /* Perform concurrent build of index */
1730
1731 /* we can do away with our snapshot */
1733
1734 /*
1735 * Commit this transaction to make the indisready update visible.
1736 */
1739
1740 /* Tell concurrent index builds to ignore us, if index qualifies */
1741 if (safe_index)
1743
1744 /*
1745 * Phase 3 of concurrent index build
1746 *
1747 * We once again wait until no transaction can have the table open with
1748 * the index marked as read-only for updates.
1749 */
1753
1754 /*
1755 * Now take the "reference snapshot" that will be used by validate_index()
1756 * to filter candidate tuples. Beware! There might still be snapshots in
1757 * use that treat some transaction as in-progress that our reference
1758 * snapshot treats as committed. If such a recently-committed transaction
1759 * deleted tuples in the table, we will not include them in the index; yet
1760 * those transactions which see the deleting one as still-in-progress will
1761 * expect such tuples to be there once we mark the index as valid.
1762 *
1763 * We solve this by waiting for all endangered transactions to exit before
1764 * we mark the index as valid.
1765 *
1766 * We also set ActiveSnapshot to this snap, since functions in indexes may
1767 * need a snapshot.
1768 */
1770 PushActiveSnapshot(snapshot);
1771
1772 /*
1773 * Scan the index and the heap, insert any missing index entries.
1774 */
1776
1777 /*
1778 * Drop the reference snapshot. We must do this before waiting out other
1779 * snapshot holders, else we will deadlock against other processes also
1780 * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
1781 * they must wait for. But first, save the snapshot's xmin to use as
1782 * limitXmin for GetCurrentVirtualXIDs().
1783 */
1784 limitXmin = snapshot->xmin;
1785
1787 UnregisterSnapshot(snapshot);
1788
1789 /*
1790 * The snapshot subsystem could still contain registered snapshots that
1791 * are holding back our process's advertised xmin; in particular, if
1792 * default_transaction_isolation = serializable, there is a transaction
1793 * snapshot that is still active. The CatalogSnapshot is likewise a
1794 * hazard. To ensure no deadlocks, we must commit and start yet another
1795 * transaction, and do our wait before any snapshot has been taken in it.
1796 */
1799
1800 /* Tell concurrent index builds to ignore us, if index qualifies */
1801 if (safe_index)
1803
1804 /* We should now definitely not be advertising any xmin. */
1806
1807 /*
1808 * The index is now valid in the sense that it contains all currently
1809 * interesting tuples. But since it might not contain tuples deleted just
1810 * before the reference snap was taken, we have to wait out any
1811 * transactions that might have older snapshots.
1812 */
1813 INJECTION_POINT("define-index-before-set-valid", NULL);
1817
1818 /*
1819 * Updating pg_index might involve TOAST table access, so ensure we have a
1820 * valid snapshot.
1821 */
1823
1824 /*
1825 * Index can now be marked valid -- update its pg_index entry
1826 */
1828
1830
1831 /*
1832 * The pg_index update will cause backends (including this one) to update
1833 * relcache entries for the index itself, but we should also send a
1834 * relcache inval on the parent table to force replanning of cached plans.
1835 * Otherwise existing sessions might fail to use the new index where it
1836 * would be useful. (Note that our earlier commits did not create reasons
1837 * to replan; so relcache flush on the index itself was sufficient.)
1838 */
1840
1841 /*
1842 * Last thing to do is release the session-level lock on the parent table.
1843 */
1845
1847
1848 return address;
1849}
bytea *(* amoptions_function)(Datum reloptions, bool validate)
Definition amapi.h:166
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)
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Oid GetDefaultTablespace(char relpersistence, bool partitioned)
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:645
uint32 TransactionId
Definition c.h:795
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
@ COMPARE_EQ
Definition cmptype.h:36
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define DEBUG1
Definition elog.h:31
Oid MyDatabaseTableSpace
Definition globals.c:98
int NewGUCNestLevel(void)
Definition guc.c:2142
void RestrictSearchPath(void)
Definition guc.c:2153
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition guc.c:2169
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:3248
@ 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:686
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, uint16 flags, uint16 constr_flags, bool allow_system_table_mods, bool is_internal, Oid *constraintId)
Definition index.c:730
void validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
Definition index.c:3371
void index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
Definition index.c:3524
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:2555
IndexInfo * BuildIndexInfo(Relation index)
Definition index.c:2446
void index_check_primary_key(Relation heapRel, const IndexInfo *indexInfo, bool is_alter_table, const IndexStmt *stmt)
Definition index.c:203
void index_concurrently_build(Oid heapRelationId, Oid indexRelationId)
Definition index.c:1503
#define INDEX_CREATE_IS_PRIMARY
Definition index.h:67
#define INDEX_CREATE_IF_NOT_EXISTS
Definition index.h:71
#define INDEX_CREATE_PARTITIONED
Definition index.h:72
#define INDEX_CREATE_INVALID
Definition index.h:73
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS
Definition index.h:103
#define INDEX_CREATE_ADD_CONSTRAINT
Definition index.h:68
#define INDEX_CREATE_SKIP_BUILD
Definition index.h:69
#define INDEX_CONSTR_CREATE_DEFERRABLE
Definition index.h:99
@ INDEX_CREATE_SET_VALID
Definition index.h:33
#define INDEX_CONSTR_CREATE_INIT_DEFERRED
Definition index.h:100
#define INDEX_CREATE_CONCURRENT
Definition index.h:70
static void set_indexsafe_procflags(void)
Definition indexcmds.c:4771
static List * ChooseIndexColumnNames(Relation rel, const List *indexElems)
Definition indexcmds.c:2802
void IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
Definition indexcmds.c:4601
void WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
Definition indexcmds.c:446
ObjectAddress DefineIndex(ParseState *pstate, Oid tableId, const 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:555
static void CheckPredicate(Expr *predicate)
Definition indexcmds.c:1864
static char * ChooseIndexName(const char *tabname, Oid namespaceId, const List *colnames, const List *exclusionOpNames, bool primary, bool isconstraint)
Definition indexcmds.c:2712
#define INJECTION_POINT(name, arg)
void CacheInvalidateRelcacheByRelid(Oid relid)
Definition inval.c:1688
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:989
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
Definition lmgr.c:404
int LOCKMODE
Definition lockdefs.h:26
#define ShareLock
Definition lockdefs.h:40
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition locktag.h:81
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2392
bool get_index_isvalid(Oid index_oid)
Definition lsyscache.c:3939
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:199
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1487
char * get_opname(Oid opno)
Definition lsyscache.c:1610
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition lsyscache.c:170
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1553
Oid get_opfamily_method(Oid opfid)
Definition lsyscache.c:1536
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
#define SECURITY_RESTRICTED_OPERATION
Definition miscadmin.h:322
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition miscinit.c:613
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition miscinit.c:620
IndexStmt * generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, const AttrMap *attmap, Oid *constraintOid)
@ PARTITION_STRATEGY_HASH
Definition parsenodes.h:922
@ OBJECT_TABLESPACE
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)
bool has_superclass(Oid relationId)
#define PROGRESS_CREATEIDX_PARTITIONS_DONE
Definition progress.h:118
#define PROGRESS_CREATEIDX_PHASE_WAIT_1
Definition progress.h:122
#define PROGRESS_CREATEIDX_COMMAND_CREATE_CONCURRENTLY
Definition progress.h:140
#define PROGRESS_CREATEIDX_ACCESS_METHOD_OID
Definition progress.h:112
#define PROGRESS_CREATEIDX_PHASE_WAIT_3
Definition progress.h:128
#define PROGRESS_CREATEIDX_COMMAND_CREATE
Definition progress.h:139
#define PROGRESS_CREATEIDX_PHASE_WAIT_2
Definition progress.h:124
#define PROGRESS_CREATEIDX_PHASE
Definition progress.h:113
#define PROGRESS_CREATEIDX_INDEX_OID
Definition progress.h:111
#define PROGRESS_CREATEIDX_PARTITIONS_TOTAL
Definition progress.h:117
#define PROGRESS_CREATEIDX_COMMAND
Definition progress.h:110
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:678
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4846
bytea * index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
Datum transformRelOptions(Datum oldOptions, List *defList, const char *nameSpace, const char *const validnsps[], bool acceptOidsOff, bool isReset)
#define RelFileNumberIsValid(relnumber)
Definition relpath.h:27
Snapshot GetTransactionSnapshot(void)
Definition snapmgr.c:272
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
void PushActiveSnapshot(Snapshot snapshot)
Definition snapmgr.c:682
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
void PopActiveSnapshot(void)
Definition snapmgr.c:775
PGPROC * MyProc
Definition proc.c:71
#define HTEqualStrategyNumber
Definition stratnum.h:41
int ii_NumIndexAttrs
Definition execnodes.h:181
int ii_NumIndexKeyAttrs
Definition execnodes.h:183
List * ii_Expressions
Definition execnodes.h:192
AttrNumber ii_IndexAttrNumbers[INDEX_MAX_KEYS]
Definition execnodes.h:189
List * ii_Predicate
Definition execnodes.h:197
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xmin
Definition proc.h:242
LockInfoData rd_lockInfo
Definition rel.h:114
TransactionId xmin
Definition snapshot.h:153
void CheckTableNotInUse(Relation rel, const char *stmt)
Definition tablecmds.c:4508
#define InvalidTransactionId
Definition transam.h:31
void StartTransactionCommand(void)
Definition xact.c:3112
void CommitTransactionCommand(void)
Definition xact.c:3210

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, 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, fb(), find_all_inheritors(), FirstLowInvalidHeapAttributeNumber, Form_pg_am, Form_pg_index, 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(), INJECTION_POINT, InvalidOid, InvalidTransactionId, IsBootstrapProcessingMode, j, lfirst_oid, list_concat_copy(), list_free(), list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeIndexInfo(), memcpy(), MyDatabaseTableSpace, MyProc, NameStr, NewGUCNestLevel(), NIL, NoLock, NOTICE, PartitionDescData::nparts, object_aclcheck(), OBJECT_SCHEMA, OBJECT_TABLESPACE, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, PartitionDescData::oids, palloc_array, PARTITION_STRATEGY_HASH, 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_lockInfo, 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, 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)
extern

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 bool isDefault = stmt->isDefault;
347 List *operators; /* OpFamilyMember list for operators */
348 List *procedures; /* OpFamilyMember list for support procs */
349 ListCell *l;
350 Relation rel;
355 bool nulls[Natts_pg_opclass];
360
361 /* Convert list of names to a name and namespace */
363 &opcname);
364
365 /* Check we have creation rights in target namespace */
367 if (aclresult != ACLCHECK_OK)
370
371 /* Get necessary info about access method */
373 if (!HeapTupleIsValid(tup))
376 errmsg("access method \"%s\" does not exist",
377 stmt->amname)));
378
380 amoid = amform->oid;
383
384 maxOpNumber = amroutine->amstrategies;
385 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
386 if (maxOpNumber <= 0)
388 maxProcNumber = amroutine->amsupport;
389 optsProcNumber = amroutine->amoptsprocnum;
390 amstorage = amroutine->amstorage;
391
392 /* XXX Should we make any privilege check against the AM? */
393
394 /*
395 * The question of appropriate permissions for CREATE OPERATOR CLASS is
396 * interesting. Creating an opclass is tantamount to granting public
397 * execute access on the functions involved, since the index machinery
398 * generally does not check access permission before using the functions.
399 * A minimum expectation therefore is that the caller have execute
400 * privilege with grant option. Since we don't have a way to make the
401 * opclass go away if the grant option is revoked, we choose instead to
402 * require ownership of the functions. It's also not entirely clear what
403 * permissions should be required on the datatype, but ownership seems
404 * like a safe choice.
405 *
406 * Currently, we require superuser privileges to create an opclass. This
407 * seems necessary because we have no way to validate that the offered set
408 * of operators and functions are consistent with the AM's expectations.
409 * It would be nice to provide such a check someday, if it can be done
410 * without solving the halting problem :-(
411 *
412 * XXX re-enable NOT_USED code sections below if you remove this test.
413 */
414 if (!superuser())
417 errmsg("must be superuser to create an operator class")));
418
419 /* Look up the datatype */
420 typeoid = typenameTypeId(NULL, stmt->datatype);
421
422#ifdef NOT_USED
423 /* XXX this is unnecessary given the superuser check above */
424 /* Check we have ownership of the datatype */
427#endif
428
429 /*
430 * Look up the containing operator family, or create one if FAMILY option
431 * was omitted and there's not a match already.
432 */
433 if (stmt->opfamilyname)
434 {
435 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
436 }
437 else
438 {
439 /* Lookup existing family of same name and namespace */
445 {
447
448 /*
449 * XXX given the superuser check above, there's no need for an
450 * ownership check here
451 */
453 }
454 else
455 {
458
460 opfstmt->opfamilyname = stmt->opclassname;
461 opfstmt->amname = stmt->amname;
462
463 /*
464 * Create it ... again no need for more permissions ...
465 */
467 opfamilyoid = tmpAddr.objectId;
468 }
469 }
470
471 operators = NIL;
472 procedures = NIL;
473
474 /* Storage datatype is optional */
476
477 /*
478 * Scan the "items" list to obtain additional info.
479 */
480 foreach(l, stmt->items)
481 {
483 Oid operOid;
484 Oid funcOid;
486 OpFamilyMember *member;
487
488 switch (item->itemtype)
489 {
491 if (item->number <= 0 || item->number > maxOpNumber)
494 errmsg("invalid operator number %d,"
495 " must be between 1 and %d",
496 item->number, maxOpNumber)));
497 if (item->name->objargs != NIL)
498 operOid = LookupOperWithArgs(item->name, false);
499 else
500 {
501 /* Default to binary op on input datatype */
503 typeoid, typeoid,
504 false, -1);
505 }
506
507 if (item->order_family)
509 item->order_family,
510 false);
511 else
513
514#ifdef NOT_USED
515 /* XXX this is unnecessary given the superuser check above */
516 /* Caller must own operator and its underlying function */
520 funcOid = get_opcode(operOid);
523 get_func_name(funcOid));
524#endif
525
526 /* Save the info */
528 member->is_func = false;
529 member->object = operOid;
530 member->number = item->number;
531 member->sortfamily = sortfamilyOid;
532 assignOperTypes(member, amoid, typeoid);
533 addFamilyMember(&operators, member);
534 break;
536 if (item->number <= 0 || item->number > maxProcNumber)
539 errmsg("invalid function number %d,"
540 " must be between 1 and %d",
541 item->number, maxProcNumber)));
542 funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
543#ifdef NOT_USED
544 /* XXX this is unnecessary given the superuser check above */
545 /* Caller must own function */
548 get_func_name(funcOid));
549#endif
550 /* Save the info */
552 member->is_func = true;
553 member->object = funcOid;
554 member->number = item->number;
555
556 /* allow overriding of the function's actual arg types */
557 if (item->class_args)
559 &member->lefttype, &member->righttype);
560
561 assignProcTypes(member, amoid, typeoid, optsProcNumber);
562 addFamilyMember(&procedures, member);
563 break;
568 errmsg("storage type specified more than once")));
570
571#ifdef NOT_USED
572 /* XXX this is unnecessary given the superuser check above */
573 /* Check we have ownership of the datatype */
576#endif
577 break;
578 default:
579 elog(ERROR, "unrecognized item type: %d", item->itemtype);
580 break;
581 }
582 }
583
584 /*
585 * If storagetype is specified, make sure it's legal.
586 */
588 {
589 /* Just drop the spec if same as column datatype */
590 if (storageoid == typeoid)
592 else if (!amstorage)
595 errmsg("storage type cannot be different from data type for access method \"%s\"",
596 stmt->amname)));
597 }
598
600
601 /*
602 * Make sure there is no existing opclass of this name (this is just to
603 * give a more friendly error message than "duplicate key").
604 */
611 errmsg("operator class \"%s\" for access method \"%s\" already exists",
612 opcname, stmt->amname)));
613
614 /*
615 * HACK: if we're trying to create btree_gist's gist_inet_ops or
616 * gist_cidr_ops during a binary upgrade, avoid failure in the next stanza
617 * by silently making the new opclass non-default. Without this kluge, we
618 * would fail to upgrade databases containing pre-1.9 versions of
619 * contrib/btree_gist. We can remove it sometime in the far future when
620 * we don't expect any such databases to exist. (The result of this hack
621 * is that the installed version of btree_gist will approximate btree_gist
622 * 1.9, how closely depending on whether it's 1.8 or something older.
623 * ALTER EXTENSION UPDATE can be used to bring it up to real 1.9.)
624 */
625 if (isDefault && IsBinaryUpgrade)
626 {
627 if (amoid == GIST_AM_OID &&
628 ((typeoid == INETOID && strcmp(opcname, "gist_inet_ops") == 0) ||
629 (typeoid == CIDROID && strcmp(opcname, "gist_cidr_ops") == 0)))
630 isDefault = false;
631 }
632
633 /*
634 * If we are creating a default opclass, check there isn't one already.
635 * (Note we do not restrict this test to visible opclasses; this ensures
636 * that typcache.c can find unique solutions to its questions.)
637 */
638 if (isDefault)
639 {
640 ScanKeyData skey[1];
641 SysScanDesc scan;
642
643 ScanKeyInit(&skey[0],
647
649 NULL, 1, skey);
650
651 while (HeapTupleIsValid(tup = systable_getnext(scan)))
652 {
654
655 if (opclass->opcintype == typeoid && opclass->opcdefault)
658 errmsg("could not make operator class \"%s\" be default for type %s",
659 opcname,
660 TypeNameToString(stmt->datatype)),
661 errdetail("Operator class \"%s\" already is the default.",
662 NameStr(opclass->opcname))));
663 }
664
665 systable_endscan(scan);
666 }
667
668 /*
669 * Okay, let's create the pg_opclass entry.
670 */
671 memset(values, 0, sizeof(values));
672 memset(nulls, false, sizeof(nulls));
673
674 opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
686
687 tup = heap_form_tuple(rel->rd_att, values, nulls);
688
690
692
693 /*
694 * Now that we have the opclass OID, set up default dependency info for
695 * the pg_amop and pg_amproc entries. Historically, CREATE OPERATOR CLASS
696 * has created hard dependencies on the opclass, so that's what we use.
697 */
698 foreach(l, operators)
699 {
701
702 op->ref_is_hard = true;
703 op->ref_is_family = false;
704 op->refobjid = opclassoid;
705 }
706 foreach(l, procedures)
707 {
708 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
709
710 proc->ref_is_hard = true;
711 proc->ref_is_family = false;
712 proc->refobjid = opclassoid;
713 }
714
715 /*
716 * Let the index AM editorialize on the dependency choices. It could also
717 * do further validation on the operators and functions, if it likes.
718 */
719 if (amroutine->amadjustmembers)
720 amroutine->amadjustmembers(opfamilyoid,
721 opclassoid,
722 operators,
723 procedures);
724
725 /*
726 * Now add tuples to pg_amop and pg_amproc tying in the operators and
727 * functions. Dependencies on them are inserted, too.
728 */
729 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
730 operators, false);
731 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
732 procedures, false);
733
734 /* let event triggers know what happened */
735 EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
736
737 /*
738 * Create dependencies for the opclass proper. Note: we do not need a
739 * dependency link to the AM, because that exists through the opfamily.
740 */
742 myself.objectId = opclassoid;
743 myself.objectSubId = 0;
744
745 /* dependency on namespace */
747 referenced.objectId = namespaceoid;
748 referenced.objectSubId = 0;
750
751 /* dependency on opfamily */
753 referenced.objectId = opfamilyoid;
754 referenced.objectSubId = 0;
756
757 /* dependency on indexed datatype */
758 referenced.classId = TypeRelationId;
759 referenced.objectId = typeoid;
760 referenced.objectSubId = 0;
762
763 /* dependency on storage datatype */
765 {
766 referenced.classId = TypeRelationId;
767 referenced.objectId = storageoid;
768 referenced.objectSubId = 0;
770 }
771
772 /* dependency on owner */
774
775 /* dependency on extension */
777
778 /* Post creation hook for new operator class */
780
782
783 return myself;
784}
void EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
#define palloc0_object(type)
Definition fe_memutils.h:90
bool IsBinaryUpgrade
Definition globals.c:123
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1585
#define makeNode(_type_)
Definition nodes.h:159
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
static ObjectAddress CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, Oid namespaceoid, Oid amoid)
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
static void addFamilyMember(List **list, OpFamilyMember *member)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition parse_oper.c:102
#define OPCLASS_ITEM_STORAGETYPE
#define OPCLASS_ITEM_OPERATOR
#define OPCLASS_ITEM_FUNCTION
END_CATALOG_STRUCT typedef FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:87
END_CATALOG_STRUCT typedef FormData_pg_opfamily * Form_pg_opfamily
Definition pg_opfamily.h:55
ObjectWithArgs * name
TypeName * storedtype
Oid refobjid
Definition amapi.h:98
Oid lefttype
Definition amapi.h:93
bool ref_is_family
Definition amapi.h:97
Oid righttype
Definition amapi.h:94
bool is_func
Definition amapi.h:90
bool ref_is_hard
Definition amapi.h:96
Oid sortfamily
Definition amapi.h:95
HeapTuple SearchSysCache3(SysCacheIdentifier cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:241
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition syscache.h:104

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), assignOperTypes(), assignProcTypes(), BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleInsert(), CreateOpClassItem::class_args, CreateOpFamily(), CStringGetDatum(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg, ERROR, EventTriggerCollectCreateOpClass(), fb(), Form_pg_am, Form_pg_opclass, Form_pg_opfamily, 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, IsBinaryUpgrade, 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, ObjectIdGetDatum(), ObjectWithArgs::objname, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, CreateOpClassItem::order_family, palloc0_object, 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 
)
extern

Definition at line 67 of file operatorcmds.c.

68{
69 char *oprName;
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 */
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 */
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 */
93
94 /* Check we have creation rights in target namespace */
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 {
110 if (typeName1->setof)
113 errmsg("SETOF type not allowed for operator argument")));
114 }
115 else if (strcmp(defel->defname, "rightarg") == 0)
116 {
118 if (typeName2->setof)
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)
126 else if (strcmp(defel->defname, "procedure") == 0)
128 else if (strcmp(defel->defname, "commutator") == 0)
130 else if (strcmp(defel->defname, "negator") == 0)
132 else if (strcmp(defel->defname, "restrict") == 0)
134 else if (strcmp(defel->defname, "join") == 0)
136 else if (strcmp(defel->defname, "hashes") == 0)
138 else if (strcmp(defel->defname, "merges") == 0)
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 */
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)
165 errmsg("operator function must be specified")));
166
167 /* Transform type names to type OIDs */
168 if (typeName1)
170 if (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 */
183 errmsg("operator argument types must be specified")));
184 if (!OidIsValid(typeId2))
187 errmsg("operator right argument type must be specified"),
188 errdetail("Postfix operators are not supported.")));
189
190 if (typeName1)
191 {
193 if (aclresult != ACLCHECK_OK)
195 }
196
197 if (typeName2)
198 {
200 if (aclresult != ACLCHECK_OK)
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 */
231 if (aclresult != ACLCHECK_OK)
234
235 rettype = get_func_rettype(functionOid);
237 if (aclresult != ACLCHECK_OK)
239
240 /*
241 * Look up restriction and join estimators if specified
242 */
243 if (restrictionName)
245 else
247 if (joinName)
249 else
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:1969
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
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)

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

Referenced by ProcessUtilitySlow().

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)
extern

Definition at line 792 of file opclasscmds.c.

793{
794 char *opfname; /* name of opfamily we're creating */
795 Oid amoid, /* our AM's oid */
796 namespaceoid; /* namespace to create opfamily in */
798
799 /* Convert list of names to a name and namespace */
801 &opfname);
802
803 /* Check we have creation rights in target namespace */
805 if (aclresult != ACLCHECK_OK)
808
809 /* Get access method OID, throwing an error if it doesn't exist. */
810 amoid = get_index_am_oid(stmt->amname, false);
811
812 /* XXX Should we make any privilege check against the AM? */
813
814 /*
815 * Currently, we require superuser privileges to create an opfamily. See
816 * comments in DefineOpClass.
817 */
818 if (!superuser())
821 errmsg("must be superuser to create an operator family")));
822
823 /* Insert pg_opfamily catalog entry */
825}
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, fb(), 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 
)
extern

Definition at line 899 of file tsearchcmds.c.

900{
905 bool nulls[Natts_pg_ts_config];
908 char *cfgname;
912 Oid cfgOid;
913 ListCell *pl;
914 ObjectAddress address;
915
916 /* Convert list of names to a name and namespace */
918
919 /* Check we have creation rights in target namespace */
921 if (aclresult != ACLCHECK_OK)
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)
934 else if (strcmp(defel->defname, "copy") == 0)
936 else
939 errmsg("text search configuration parameter \"%s\" not recognized",
940 defel->defname)));
941 }
942
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,
953 sourceOid);
954 }
955
956 /*
957 * Look up source config if given.
958 */
960 {
962
964 if (!HeapTupleIsValid(tup))
965 elog(ERROR, "cache lookup failed for text search configuration %u",
966 sourceOid);
967
969
970 /* use source's parser */
971 prsOid = cfg->cfgparser;
972
974 }
975
976 /*
977 * Validation
978 */
979 if (!OidIsValid(prsOid))
982 errmsg("text search parser is required")));
983
985
986 /*
987 * Looks good, build tuple and insert
988 */
989 memset(values, 0, sizeof(values));
990 memset(nulls, false, sizeof(nulls));
991
995 namestrcpy(&cname, cfgname);
1000
1001 tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
1002
1004
1005 if (OidIsValid(sourceOid))
1006 {
1007 /*
1008 * Copy token-dicts map from source config
1009 */
1011 SysScanDesc scan;
1014 TupleTableSlot **slot;
1016 int max_slots,
1019
1022
1024
1025 /*
1026 * Allocate the slots to use, but delay costly initialization until we
1027 * know that they will be used.
1028 */
1031
1036
1038 NULL, 1, &skey);
1039
1040 /* number of slots currently storing tuples */
1042 /* number of slots currently initialized */
1043 slot_init_count = 0;
1044
1045 while (HeapTupleIsValid((maptup = systable_getnext(scan))))
1046 {
1048
1050 {
1054 }
1055
1057
1058 memset(slot[slot_stored_count]->tts_isnull, false,
1059 slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
1060
1065
1068
1069 /* If slots are full, insert a batch of tuples */
1071 {
1073 indstate);
1075 }
1076 }
1077
1078 /* Insert any tuples left in the buffer */
1079 if (slot_stored_count > 0)
1081 indstate);
1082
1083 for (int i = 0; i < slot_init_count; i++)
1085
1086 systable_endscan(scan);
1088 }
1089
1090 address = makeConfigurationDependencies(tup, false, mapRel);
1091
1092 /* Post creation hook for new text search configuration */
1094
1096
1097 if (mapRel)
1100
1101 return address;
1102}
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
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:2788
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition namespace.c:3224
FormData_pg_ts_config_map
END_CATALOG_STRUCT typedef FormData_pg_ts_config_map * Form_pg_ts_config_map
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
Datum * tts_values
Definition tuptable.h:131
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, BTEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleInsert(), CatalogTuplesMultiInsertWithInfo(), defGetQualifiedName(), elog, ereport, errcode(), errmsg, ERROR, ExecClearTuple(), ExecDropSingleTupleTableSlot(), ExecStoreVirtualTuple(), fb(), Form_pg_ts_config, Form_pg_ts_config_map, 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, Int32GetDatum(), InvalidOid, InvokeObjectPostCreateHook, lfirst, makeConfigurationDependencies(), MakeSingleTupleTableSlot(), MAX_CATALOG_MULTI_INSERT_BYTES, NameGetDatum(), namestrcpy(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, palloc_array, QualifiedNameGetCreationNamespace(), 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 
)
extern

Definition at line 397 of file tsearchcmds.c.

398{
399 ListCell *pl;
403 bool nulls[Natts_pg_ts_dict];
407 Oid dictOid;
410 char *dictname;
411 ObjectAddress address;
412
413 /* Convert list of names to a name and namespace */
415
416 /* Check we have creation rights in target namespace */
418 if (aclresult != ACLCHECK_OK)
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 {
432 }
433 else
434 {
435 /* Assume it's an option for the dictionary itself */
437 }
438 }
439
440 /*
441 * Validation
442 */
443 if (!OidIsValid(templId))
446 errmsg("text search template is required")));
447
449
450
452
453 /*
454 * Looks good, insert
455 */
456 memset(values, 0, sizeof(values));
457 memset(nulls, false, sizeof(nulls));
458
462 namestrcpy(&dname, dictname);
467 if (dictoptions)
470 else
471 nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;
472
473 tup = heap_form_tuple(dictRel->rd_att, values, nulls);
474
476
478
479 /* Post creation hook for new text search dictionary */
481
483
485
486 return address;
487}
Oid get_ts_template_oid(List *names, bool missing_ok)
Definition namespace.c:3079
static ObjectAddress makeDictionaryDependencies(HeapTuple tuple)

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), defGetQualifiedName(), ereport, errcode(), errmsg, ERROR, fb(), 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(), RowExclusiveLock, serialize_deflist(), table_close(), table_open(), values, and verify_dictoptions().

Referenced by ProcessUtilitySlow().

◆ DefineTSParser()

ObjectAddress DefineTSParser ( List names,
List parameters 
)
extern

Definition at line 184 of file tsearchcmds.c.

185{
186 char *prsname;
187 ListCell *pl;
191 bool nulls[Natts_pg_ts_parser];
193 Oid prsOid;
195 ObjectAddress address;
196
197 if (!superuser())
200 errmsg("must be superuser to create text search parsers")));
201
203
204 /* Convert list of names to a name and namespace */
206
207 /* initialize tuple fields with name/namespace */
208 memset(values, 0, sizeof(values));
209 memset(nulls, false, sizeof(nulls));
210
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 {
229 }
230 else if (strcmp(defel->defname, "gettoken") == 0)
231 {
234 }
235 else if (strcmp(defel->defname, "end") == 0)
236 {
239 }
240 else if (strcmp(defel->defname, "headline") == 0)
241 {
244 }
245 else if (strcmp(defel->defname, "lextypes") == 0)
246 {
249 }
250 else
253 errmsg("text search parser parameter \"%s\" not recognized",
254 defel->defname)));
255 }
256
257 /*
258 * Validation
259 */
263 errmsg("text search parser start method is required")));
264
268 errmsg("text search parser gettoken method is required")));
269
273 errmsg("text search parser end method is required")));
274
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
286
287 address = makeParserDependencies(tup);
288
289 /* Post creation hook for new text search parser */
291
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)

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

Referenced by ProcessUtilitySlow().

◆ DefineTSTemplate()

ObjectAddress DefineTSTemplate ( List names,
List parameters 
)
extern

Definition at line 690 of file tsearchcmds.c.

691{
692 ListCell *pl;
696 bool nulls[Natts_pg_ts_template];
698 int i;
699 Oid tmplOid;
701 char *tmplname;
702 ObjectAddress address;
703
704 if (!superuser())
707 errmsg("must be superuser to create text search templates")));
708
709 /* Convert list of names to a name and namespace */
711
713
714 for (i = 0; i < Natts_pg_ts_template; i++)
715 {
716 nulls[i] = false;
718 }
719
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 {
738 nulls[Anum_pg_ts_template_tmplinit - 1] = false;
739 }
740 else if (strcmp(defel->defname, "lexize") == 0)
741 {
744 nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
745 }
746 else
749 errmsg("text search template parameter \"%s\" not recognized",
750 defel->defname)));
751 }
752
753 /*
754 * Validation
755 */
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
767
769
770 /* Post creation hook for new text search template */
772
774
776
777 return address;
778}
static ObjectAddress makeTSTemplateDependencies(HeapTuple tuple)
static Datum get_ts_template_func(DefElem *defel, int attnum)

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

Referenced by ProcessUtilitySlow().

◆ deserialize_deflist()

List * deserialize_deflist ( Datum  txt)
extern

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,
1641 } ds_state;
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';
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 == '=')
1704 else if (!isspace((unsigned char) *ptr))
1705 ereport(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;
1715 }
1716 else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
1717 {
1718 ptr++;
1719 startvalue = wsptr;
1721 }
1722 else if (*ptr == '"')
1723 {
1724 startvalue = wsptr;
1726 }
1727 else if (!isspace((unsigned char) *ptr))
1728 {
1729 startvalue = wsptr;
1730 *wsptr++ = *ptr;
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';
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';
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';
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';
1815 buildDefItem(workspace,
1816 startvalue,
1817 false));
1818 }
1819 else if (state != CS_WAITKEY)
1820 ereport(ERROR,
1822 errmsg("invalid parameter list format: \"%s\"",
1823 text_to_cstring(in))));
1824
1825 pfree(workspace);
1826
1827 return result;
1828}
uint32 result
#define DatumGetTextPP(X)
Definition fmgr.h:293
const void size_t len
Definition c.h:835
static DefElem * buildDefItem(const char *name, const char *val, bool was_quoted)
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
char * text_to_cstring(const text *t)
Definition varlena.c:217

References buildDefItem(), DatumGetTextPP, elog, ereport, errcode(), errmsg, ERROR, fb(), lappend(), len, NIL, palloc(), pfree(), result, 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 
)
extern

Definition at line 2977 of file indexcmds.c.

2978{
2979 ReindexParams params = {0};
2980 ListCell *lc;
2981 bool concurrently = false;
2982 bool verbose = false;
2983 char *tablespacename = NULL;
2984
2985 /* Parse option list */
2986 foreach(lc, stmt->params)
2987 {
2988 DefElem *opt = (DefElem *) lfirst(lc);
2989
2990 if (strcmp(opt->defname, "verbose") == 0)
2991 verbose = defGetBoolean(opt);
2992 else if (strcmp(opt->defname, "concurrently") == 0)
2994 else if (strcmp(opt->defname, "tablespace") == 0)
2995 tablespacename = defGetString(opt);
2996 else
2997 ereport(ERROR,
2999 errmsg("unrecognized %s option \"%s\"",
3000 "REINDEX", opt->defname),
3001 parser_errposition(pstate, opt->location)));
3002 }
3003
3004 if (concurrently)
3006 "REINDEX CONCURRENTLY");
3007
3008 params.options =
3009 (verbose ? REINDEXOPT_VERBOSE : 0) |
3011
3012 /*
3013 * Assign the tablespace OID to move indexes to, with InvalidOid to do
3014 * nothing.
3015 */
3016 if (tablespacename != NULL)
3017 {
3018 params.tablespaceOid = get_tablespace_oid(tablespacename, false);
3019
3020 /* Check permissions except when moving to database's default */
3021 if (OidIsValid(params.tablespaceOid) &&
3023 {
3025
3028 if (aclresult != ACLCHECK_OK)
3031 }
3032 }
3033 else
3034 params.tablespaceOid = InvalidOid;
3035
3036 switch (stmt->kind)
3037 {
3039 ReindexIndex(stmt, &params, isTopLevel);
3040 break;
3042 ReindexTable(stmt, &params, isTopLevel);
3043 break;
3047
3048 /*
3049 * This cannot run inside a user transaction block; if we were
3050 * inside a transaction, then its commit- and
3051 * start-transaction-command calls would not have the intended
3052 * effect!
3053 */
3055 (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
3056 (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
3057 "REINDEX DATABASE");
3058 ReindexMultipleTables(stmt, &params);
3059 break;
3060 default:
3061 elog(ERROR, "unrecognized object type: %d",
3062 (int) stmt->kind);
3063 break;
3064 }
3065}
#define REINDEXOPT_CONCURRENTLY
Definition index.h:50
#define REINDEXOPT_VERBOSE
Definition index.h:47
static void ReindexIndex(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3072
static void ReindexMultipleTables(const ReindexStmt *stmt, const ReindexParams *params)
Definition indexcmds.c:3261
static Oid ReindexTable(const ReindexStmt *stmt, const ReindexParams *params, bool isTopLevel)
Definition indexcmds.c:3202
@ REINDEX_OBJECT_DATABASE
@ REINDEX_OBJECT_INDEX
@ REINDEX_OBJECT_SCHEMA
@ REINDEX_OBJECT_SYSTEM
@ REINDEX_OBJECT_TABLE
static int verbose
ParseLoc location
Definition parsenodes.h:867
Oid tablespaceOid
Definition index.h:42
uint32 options
Definition index.h:41
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition xact.c:3701

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg, ERROR, fb(), 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 
)
extern

Definition at line 2209 of file functioncmds.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, Assert, begin_tup_output_tupdesc(), CreateExecutorState(), CreateExprContext(), DatumGetHeapTupleHeader, elog, end_tup_output(), EnsurePortalSnapshotExists(), ereport, errcode(), errmsg_plural(), ERROR, EState::es_param_list_info, ExecEvalExprSwitchContext(), ExecPrepareExpr(), ExecStoreHeapTuple(), fb(), fmgr_info(), fmgr_info_set_expr, Form_pg_proc, FreeExecutorState(), FUNC_MAX_ARGS, 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(), ReleaseSysCache(), ReleaseTupleDesc, SearchSysCache1(), stmt, TTSOpsHeapTuple, and val.

Referenced by standard_ProcessUtility().

◆ ExecuteDoStmt()

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

Definition at line 2087 of file functioncmds.c.

2088{
2090 ListCell *arg;
2091 DefElem *as_item = NULL;
2093 char *language;
2094 Oid laninline;
2097
2098 /* Process options we got from gram.y */
2099 foreach(arg, stmt->args)
2100 {
2101 DefElem *defel = (DefElem *) lfirst(arg);
2102
2103 if (strcmp(defel->defname, "as") == 0)
2104 {
2105 if (as_item)
2107 as_item = defel;
2108 }
2109 else if (strcmp(defel->defname, "language") == 0)
2110 {
2111 if (language_item)
2114 }
2115 else
2116 elog(ERROR, "option \"%s\" not recognized",
2117 defel->defname);
2118 }
2119
2120 if (as_item)
2121 codeblock->source_text = strVal(as_item->arg);
2122 else
2123 ereport(ERROR,
2125 errmsg("no inline code specified")));
2126
2127 /* if LANGUAGE option wasn't specified, use the default */
2128 if (language_item)
2130 else
2131 language = "plpgsql";
2132
2133 /* Look up the language and validate permissions */
2136 ereport(ERROR,
2138 errmsg("language \"%s\" does not exist", language),
2140 errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
2141
2143 codeblock->langOid = languageStruct->oid;
2144 codeblock->langIsTrusted = languageStruct->lanpltrusted;
2145 codeblock->atomic = atomic;
2146
2147 if (languageStruct->lanpltrusted)
2148 {
2149 /* if trusted language, need USAGE privilege */
2151
2153 ACL_USAGE);
2154 if (aclresult != ACLCHECK_OK)
2156 NameStr(languageStruct->lanname));
2157 }
2158 else
2159 {
2160 /* if untrusted language, must be superuser */
2161 if (!superuser())
2163 NameStr(languageStruct->lanname));
2164 }
2165
2166 /* get the handler function's OID */
2167 laninline = languageStruct->laninline;
2168 if (!OidIsValid(laninline))
2169 ereport(ERROR,
2171 errmsg("language \"%s\" does not support inline code execution",
2172 NameStr(languageStruct->lanname))));
2173
2175
2176 /* execute the inline handler */
2178}
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
Datum arg
Definition elog.c:1323
#define OidFunctionCall1(functionId, arg1)
Definition fmgr.h:726

References ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, arg, elog, ereport, errcode(), errhint(), errmsg, ERROR, errorConflictingDefElem(), extension_file_exists(), fb(), Form_pg_language, GETSTRUCT(), GetUserId(), HeapTupleIsValid, lfirst, makeNode, NameStr, object_aclcheck(), OBJECT_LANGUAGE, OidFunctionCall1, OidIsValid, PointerGetDatum, ReleaseSysCache(), SearchSysCache1(), stmt, strVal, and superuser().

Referenced by standard_ProcessUtility().

◆ get_am_name()

◆ get_am_oid()

Oid get_am_oid ( const char amname,
bool  missing_ok 
)
extern

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

Definition at line 163 of file amcmds.c.

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

References fb(), and 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 
)
extern

Definition at line 220 of file opclasscmds.c.

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

References fb(), Form_pg_opclass, 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 
)
extern

Definition at line 139 of file opclasscmds.c.

140{
141 HeapTuple htup;
143 Oid opfID;
144
145 htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
146 if (!HeapTupleIsValid(htup))
147 return InvalidOid;
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 fb(), Form_pg_opfamily, 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 
)
extern

Definition at line 173 of file amcmds.c.

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

References fb(), and 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 
)
extern

Definition at line 2040 of file functioncmds.c.

2041{
2042 Oid oid;
2043
2045 ObjectIdGetDatum(type_id),
2047 if (!OidIsValid(oid) && !missing_ok)
2048 ereport(ERROR,
2050 errmsg("transform for type %s language \"%s\" does not exist",
2051 format_type_be(type_id),
2052 get_language_name(lang_id, false))));
2053 return oid;
2054}
char * get_language_name(Oid langoid, bool missing_ok)
Definition lsyscache.c:1413

References ereport, errcode(), errmsg, ERROR, fb(), 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 
)
extern

Definition at line 2381 of file indexcmds.c.

2382{
2384 int nexact = 0;
2385 int ncompatible = 0;
2386 int ncompatiblepreferred = 0;
2387 Relation rel;
2388 ScanKeyData skey[1];
2389 SysScanDesc scan;
2390 HeapTuple tup;
2392
2393 /* If it's a domain, look at the base type instead */
2394 type_id = getBaseType(type_id);
2395
2396 tcategory = TypeCategory(type_id);
2397
2398 /*
2399 * We scan through all the opclasses available for the access method,
2400 * looking for one that is marked default and matches the target type
2401 * (either exactly or binary-compatibly, but prefer an exact match).
2402 *
2403 * We could find more than one binary-compatible match. If just one is
2404 * for a preferred type, use that one; otherwise we fail, forcing the user
2405 * to specify which one he wants. (The preferred-type special case is a
2406 * kluge for varchar: it's binary-compatible to both text and bpchar, so
2407 * we need a tiebreaker.) If we find more than one exact match, then
2408 * someone put bogus entries in pg_opclass.
2409 */
2411
2412 ScanKeyInit(&skey[0],
2416
2418 NULL, 1, skey);
2419
2420 while (HeapTupleIsValid(tup = systable_getnext(scan)))
2421 {
2423
2424 /* ignore altogether if not a default opclass */
2425 if (!opclass->opcdefault)
2426 continue;
2427 if (opclass->opcintype == type_id)
2428 {
2429 nexact++;
2430 result = opclass->oid;
2431 }
2432 else if (nexact == 0 &&
2433 IsBinaryCoercible(type_id, opclass->opcintype))
2434 {
2435 if (IsPreferredType(tcategory, opclass->opcintype))
2436 {
2438 result = opclass->oid;
2439 }
2440 else if (ncompatiblepreferred == 0)
2441 {
2442 ncompatible++;
2443 result = opclass->oid;
2444 }
2445 }
2446 }
2447
2448 systable_endscan(scan);
2449
2451
2452 /* raise error if pg_opclass contains inconsistent data */
2453 if (nexact > 1)
2454 ereport(ERROR,
2456 errmsg("there are multiple default operator classes for data type %s",
2457 format_type_be(type_id))));
2458
2459 if (nexact == 1 ||
2460 ncompatiblepreferred == 1 ||
2461 (ncompatiblepreferred == 0 && ncompatible == 1))
2462 return result;
2463
2464 return InvalidOid;
2465}
Oid getBaseType(Oid typid)
Definition lsyscache.c:2837
TYPCATEGORY TypeCategory(Oid type)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
bool IsPreferredType(TYPCATEGORY category, Oid type)
char TYPCATEGORY

References AccessShareLock, BTEqualStrategyNumber, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), Form_pg_opclass, format_type_be(), getBaseType(), GETSTRUCT(), HeapTupleIsValid, InvalidOid, IsBinaryCoercible(), IsPreferredType(), ObjectIdGetDatum(), result, 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(), propgraph_edge_get_ref_keys(), ResolveOpClass(), transformForPortionOfClause(), and transformIndexConstraint().

◆ GetOperatorFromCompareType()

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

Definition at line 2483 of file indexcmds.c.

2485{
2486 Oid amid;
2487 Oid opfamily;
2488 Oid opcintype;
2489
2490 Assert(cmptype == COMPARE_EQ || cmptype == COMPARE_OVERLAP || cmptype == COMPARE_CONTAINED_BY);
2491
2492 /*
2493 * Use the opclass to get the opfamily, opcintype, and access method. If
2494 * any of this fails, quit early.
2495 */
2496 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
2497 elog(ERROR, "cache lookup failed for opclass %u", opclass);
2498
2499 amid = get_opclass_method(opclass);
2500
2501 /*
2502 * Ask the index AM to translate to its internal stratnum
2503 */
2504 *strat = IndexAmTranslateCompareType(cmptype, amid, opfamily, true);
2505 if (*strat == InvalidStrategy)
2506 ereport(ERROR,
2508 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2509 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2510 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2511 errdetail("Could not translate compare type %d for operator family \"%s\" of access method \"%s\".",
2512 cmptype, get_opfamily_name(opfamily, false), get_am_name(amid)));
2513
2514 /*
2515 * We parameterize rhstype so foreign keys can ask for a <@ operator whose
2516 * rhs matches the aggregate function. For example range_agg returns
2517 * anymultirange.
2518 */
2519 if (!OidIsValid(rhstype))
2520 rhstype = opcintype;
2521 *opid = get_opfamily_member(opfamily, opcintype, rhstype, *strat);
2522
2523 if (!OidIsValid(*opid))
2524 ereport(ERROR,
2526 cmptype == COMPARE_EQ ? errmsg("could not identify an equality operator for type %s", format_type_be(opcintype)) :
2527 cmptype == COMPARE_OVERLAP ? errmsg("could not identify an overlaps operator for type %s", format_type_be(opcintype)) :
2528 cmptype == COMPARE_CONTAINED_BY ? errmsg("could not identify a contained-by operator for type %s", format_type_be(opcintype)) : 0,
2529 errdetail("There is no suitable operator in operator family \"%s\" for access method \"%s\".",
2530 get_opfamily_name(opfamily, false), get_am_name(amid)));
2531}
StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
Definition amapi.c:161
@ COMPARE_OVERLAP
Definition cmptype.h:40
@ COMPARE_CONTAINED_BY
Definition cmptype.h:41
#define false
Oid get_opclass_method(Oid opclass)
Definition lsyscache.c:1512
#define InvalidStrategy
Definition stratnum.h:24

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

Referenced by ComputeIndexAttrs(), FindFKPeriodOpers(), and transformForPortionOfClause().

◆ ImportForeignSchema()

void ImportForeignSchema ( ImportForeignSchemaStmt stmt)
extern

Definition at line 1590 of file foreigncmds.c.

1591{
1592 ForeignServer *server;
1596 List *cmd_list;
1597 ListCell *lc;
1598
1599 /* Check that the foreign server exists and that we have USAGE on it */
1600 server = GetForeignServerByName(stmt->server_name, false);
1602 if (aclresult != ACLCHECK_OK)
1604
1605 /* Check that the schema exists and we have CREATE permissions on it */
1606 (void) LookupCreationNamespace(stmt->local_schema);
1607
1608 /* Get the FDW and check it supports IMPORT */
1609 fdw = GetForeignDataWrapper(server->fdwid);
1610 if (!OidIsValid(fdw->fdwhandler))
1611 ereport(ERROR,
1613 errmsg("foreign-data wrapper \"%s\" has no handler",
1614 fdw->fdwname)));
1615 fdw_routine = GetFdwRoutine(fdw->fdwhandler);
1616 if (fdw_routine->ImportForeignSchema == NULL)
1617 ereport(ERROR,
1619 errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
1620 fdw->fdwname)));
1621
1622 /* Call FDW to get a list of commands */
1623 cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
1624
1625 /* Parse and execute each command */
1626 foreach(lc, cmd_list)
1627 {
1628 char *cmd = (char *) lfirst(lc);
1629 import_error_callback_arg callback_arg;
1632 ListCell *lc2;
1633
1634 /*
1635 * Setup error traceback support for ereport(). This is so that any
1636 * error in the generated SQL will be displayed nicely.
1637 */
1638 callback_arg.tablename = NULL; /* not known yet */
1639 callback_arg.cmd = cmd;
1641 sqlerrcontext.arg = &callback_arg;
1644
1645 /*
1646 * Parse the SQL string into a list of raw parse trees.
1647 */
1649
1650 /*
1651 * Process each parse tree (we allow the FDW to put more than one
1652 * command per string, though this isn't really advised).
1653 */
1654 foreach(lc2, raw_parsetree_list)
1655 {
1658 PlannedStmt *pstmt;
1659
1660 /*
1661 * Because we only allow CreateForeignTableStmt, we can skip parse
1662 * analysis, rewrite, and planning steps here.
1663 */
1665 elog(ERROR,
1666 "foreign-data wrapper \"%s\" returned incorrect statement type %d",
1667 fdw->fdwname, (int) nodeTag(cstmt));
1668
1669 /* Ignore commands for tables excluded by filter options */
1670 if (!IsImportableForeignTable(cstmt->base.relation->relname, stmt))
1671 continue;
1672
1673 /* Enable reporting of current table's name on error */
1674 callback_arg.tablename = cstmt->base.relation->relname;
1675
1676 /* Ensure creation schema is the one given in IMPORT statement */
1677 cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
1678
1679 /* No planning needed, just make a wrapper PlannedStmt */
1680 pstmt = makeNode(PlannedStmt);
1681 pstmt->commandType = CMD_UTILITY;
1682 pstmt->canSetTag = false;
1683 pstmt->utilityStmt = (Node *) cstmt;
1684 pstmt->stmt_location = rs->stmt_location;
1685 pstmt->stmt_len = rs->stmt_len;
1687
1688 /* Execute statement */
1689 ProcessUtility(pstmt, cmd, false,
1692
1693 /* Be sure to advance the command counter between subcommands */
1695
1696 callback_arg.tablename = NULL;
1697 }
1698
1700 }
1701}
DestReceiver * None_Receiver
Definition dest.c:96
ErrorContextCallback * error_context_stack
Definition elog.c:100
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition foreign.c:514
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition foreign.c:357
static void import_error_callback(void *arg)
Oid LookupCreationNamespace(const char *nspname)
Definition namespace.c:3500
@ CMD_UTILITY
Definition nodes.h:278
@ PLAN_STMT_INTERNAL
Definition plannodes.h:38
List * pg_parse_query(const char *query_string)
Definition postgres.c:617
struct ErrorContextCallback * previous
Definition elog.h:299
bool canSetTag
Definition plannodes.h:84
ParseLoc stmt_len
Definition plannodes.h:171
PlannedStmtOrigin planOrigin
Definition plannodes.h:75
ParseLoc stmt_location
Definition plannodes.h:169
CmdType commandType
Definition plannodes.h:66
Node * utilityStmt
Definition plannodes.h:153
Node * stmt
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition utility.c:504
@ PROCESS_UTILITY_SUBCOMMAND
Definition utility.h:26

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, PlannedStmt::canSetTag, import_error_callback_arg::cmd, CMD_UTILITY, CommandCounterIncrement(), PlannedStmt::commandType, elog, ereport, errcode(), errmsg, ERROR, error_context_stack, fb(), ForeignServer::fdwid, GetFdwRoutine(), GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), import_error_callback(), IsA, IsImportableForeignTable(), lfirst, lfirst_node, LookupCreationNamespace(), makeNode, nodeTag, None_Receiver, object_aclcheck(), OBJECT_FOREIGN_SERVER, OidIsValid, pg_parse_query(), PLAN_STMT_INTERNAL, PlannedStmt::planOrigin, ErrorContextCallback::previous, PROCESS_UTILITY_SUBCOMMAND, ProcessUtility(), pstrdup(), ForeignServer::serverid, ForeignServer::servername, RawStmt::stmt, stmt, RawStmt::stmt_len, PlannedStmt::stmt_len, RawStmt::stmt_location, PlannedStmt::stmt_location, import_error_callback_arg::tablename, and PlannedStmt::utilityStmt.

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

Definition at line 186 of file functioncmds.c.

199{
200 int parameterCount = list_length(parameters);
201 Oid *inTypes;
202 int inCount = 0;
206 int outCount = 0;
207 int varCount = 0;
208 bool have_names = false;
209 bool have_defaults = false;
210 ListCell *x;
211 int i;
212
213 *variadicArgType = InvalidOid; /* default result */
214 *requiredResultType = InvalidOid; /* default result */
215
216 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
217 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
218 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
221
222 /* Scan the list and extract data into work arrays */
223 i = 0;
224 foreach(x, parameters)
225 {
227 TypeName *t = fp->argType;
229 bool isinput = false;
230 Oid toid;
231 Type typtup;
233
234 /* For our purposes here, a defaulted mode spec is identical to IN */
237
238 typtup = LookupTypeName(pstate, t, NULL, false);
239 if (typtup)
240 {
242 {
243 /* As above, hard error if language is SQL */
247 errmsg("SQL function cannot accept shell type %s",
249 parser_errposition(pstate, t->location)));
250 /* We don't allow creating aggregates on shell types either */
251 else if (objtype == OBJECT_AGGREGATE)
254 errmsg("aggregate cannot accept shell type %s",
256 parser_errposition(pstate, t->location)));
257 else
260 errmsg("argument type %s is only a shell",
262 parser_errposition(pstate, t->location)));
263 }
266 }
267 else
268 {
271 errmsg("type %s does not exist",
273 parser_errposition(pstate, t->location)));
274 toid = InvalidOid; /* keep compiler quiet */
275 }
276
278 if (aclresult != ACLCHECK_OK)
280
281 if (t->setof)
282 {
283 if (objtype == OBJECT_AGGREGATE)
286 errmsg("aggregates cannot accept set arguments"),
287 parser_errposition(pstate, fp->location)));
288 else if (objtype == OBJECT_PROCEDURE)
291 errmsg("procedures cannot accept set arguments"),
292 parser_errposition(pstate, fp->location)));
293 else
296 errmsg("functions cannot accept set arguments"),
297 parser_errposition(pstate, fp->location)));
298 }
299
300 /* handle input parameters */
302 {
303 /* other input parameters can't follow a VARIADIC parameter */
304 if (varCount > 0)
307 errmsg("VARIADIC parameter must be the last input parameter"),
308 parser_errposition(pstate, fp->location)));
309 inTypes[inCount++] = toid;
310 isinput = true;
313 }
314
315 /* handle output parameters */
317 {
318 if (objtype == OBJECT_PROCEDURE)
319 {
320 /*
321 * We disallow OUT-after-VARIADIC only for procedures. While
322 * such a case causes no confusion in ordinary function calls,
323 * it would cause confusion in a CALL statement.
324 */
325 if (varCount > 0)
328 errmsg("VARIADIC parameter must be the last parameter"),
329 parser_errposition(pstate, fp->location)));
330 /* Procedures with output parameters always return RECORD */
332 }
333 else if (outCount == 0) /* save first output param's type */
335 outCount++;
336 }
337
339 {
341 varCount++;
342 /* validate variadic parameter type */
343 switch (toid)
344 {
345 case ANYARRAYOID:
347 case ANYOID:
348 /* okay */
349 break;
350 default:
354 errmsg("VARIADIC parameter must be an array"),
355 parser_errposition(pstate, fp->location)));
356 break;
357 }
358 }
359
361
363
364 if (fp->name && fp->name[0])
365 {
366 ListCell *px;
367
368 /*
369 * As of Postgres 9.0 we disallow using the same name for two
370 * input or two output function parameters. Depending on the
371 * function's language, conflicting input and output names might
372 * be bad too, but we leave it to the PL to complain if so.
373 */
374 foreach(px, parameters)
375 {
378
379 if (prevfp == fp)
380 break;
381 /* as above, default mode is IN */
385 /* pure in doesn't conflict with pure out */
386 if ((fpmode == FUNC_PARAM_IN ||
390 continue;
391 if ((prevfpmode == FUNC_PARAM_IN ||
395 continue;
396 if (prevfp->name && prevfp->name[0] &&
397 strcmp(prevfp->name, fp->name) == 0)
400 errmsg("parameter name \"%s\" used more than once",
401 fp->name),
402 parser_errposition(pstate, fp->location)));
403 }
404
406 have_names = true;
407 }
408
411
412 if (fp->defexpr)
413 {
414 Node *def;
415
416 if (!isinput)
419 errmsg("only input parameters can have default values"),
420 parser_errposition(pstate, fp->location)));
421
422 def = transformExpr(pstate, fp->defexpr,
424 def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
425 assign_expr_collations(pstate, def);
426
427 /*
428 * Make sure no variables are referred to (this is probably dead
429 * code now that add_missing_from is history).
430 */
431 if (pstate->p_rtable != NIL ||
435 errmsg("cannot use table references in parameter default value"),
436 parser_errposition(pstate, fp->location)));
437
438 /*
439 * transformExpr() should have already rejected subqueries,
440 * aggregates, and window functions, based on the EXPR_KIND_ for a
441 * default expression.
442 *
443 * It can't return a set either --- but coerce_to_specific_type
444 * already checked that for us.
445 *
446 * Note: the point of these restrictions is to ensure that an
447 * expression that, on its face, hasn't got subplans, aggregates,
448 * etc cannot suddenly have them after function default arguments
449 * are inserted.
450 */
451
453 have_defaults = true;
454 }
455 else
456 {
457 if (isinput && have_defaults)
460 errmsg("input parameters after one with a default value must also have defaults"),
461 parser_errposition(pstate, fp->location)));
462
463 /*
464 * For procedures, we also can't allow OUT parameters after one
465 * with a default, because the same sort of confusion arises in a
466 * CALL statement.
467 */
468 if (objtype == OBJECT_PROCEDURE && have_defaults)
471 errmsg("procedure OUT parameters cannot appear after one with a default value"),
472 parser_errposition(pstate, fp->location)));
473 }
474
475 i++;
476 }
477
478 /* Now construct the proper outputs as needed */
479 *parameterTypes = buildoidvector(inTypes, inCount);
480
481 if (outCount > 0 || varCount > 0)
482 {
485 if (outCount > 1)
487 /* otherwise we set requiredResultType correctly above */
488 }
489 else
490 {
493 }
494
495 if (have_names)
496 {
497 for (i = 0; i < parameterCount; i++)
498 {
501 }
503 }
504 else
506}
void px(PlannerInfo *root, Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
int x
Definition isn.c:75
void * palloc0(Size size)
Definition mcxt.c:1420
Node * coerce_to_specific_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
@ EXPR_KIND_FUNCTION_DEFAULT
Definition parse_node.h:72
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
@ FUNC_PARAM_IN
@ FUNC_PARAM_DEFAULT
@ FUNC_PARAM_OUT
@ FUNC_PARAM_TABLE
@ FUNC_PARAM_VARIADIC
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
TypeName * argType
FunctionParameterMode mode
List * p_rtable
Definition parse_node.h:215
bool setof
Definition parsenodes.h:292
ParseLoc location
Definition parsenodes.h:297
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, fb(), Form_pg_type, 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 
)
extern

Definition at line 2064 of file functioncmds.c.

2066{
2067 /* check for duplicate name (more friendly than unique-index failure) */
2072 ereport(ERROR,
2074 errmsg("function %s already exists in schema \"%s\"",
2076 NIL, proargtypes->values),
2078}
const char * funcname_signature_string(const char *funcname, int nargs, List *argnames, const Oid *argtypes)
int16 pronargs
Definition pg_proc.h:83
NameData proname
Definition pg_proc.h:37

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

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

◆ IsThereOpClassInNamespace()

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

Definition at line 1848 of file opclasscmds.c.

1850{
1851 /* make sure the new name doesn't exist */
1853 ObjectIdGetDatum(opcmethod),
1856 ereport(ERROR,
1858 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1859 opcname,
1860 get_am_name(opcmethod),
1862}

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), 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 
)
extern

Definition at line 1871 of file opclasscmds.c.

1873{
1874 /* make sure the new name doesn't exist */
1876 ObjectIdGetDatum(opfmethod),
1879 ereport(ERROR,
1881 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1882 opfname,
1883 get_am_name(opfmethod),
1885}

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), 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 
)
extern

Definition at line 2556 of file indexcmds.c.

2557{
2558 char *name;
2559 int overhead = 0; /* chars needed for label and underscores */
2560 int availchars; /* chars available for name(s) */
2561 int name1chars; /* chars allocated to name1 */
2562 int name2chars; /* chars allocated to name2 */
2563 int ndx;
2564
2566 if (name2)
2567 {
2569 overhead++; /* allow for separating underscore */
2570 }
2571 else
2572 name2chars = 0;
2573 if (label)
2574 overhead += strlen(label) + 1;
2575
2577 Assert(availchars > 0); /* else caller chose a bad label */
2578
2579 /*
2580 * If we must truncate, preferentially truncate the longer name. This
2581 * logic could be expressed without a loop, but it's simple and obvious as
2582 * a loop.
2583 */
2584 while (name1chars + name2chars > availchars)
2585 {
2586 if (name1chars > name2chars)
2587 name1chars--;
2588 else
2589 name2chars--;
2590 }
2591
2593 if (name2)
2595
2596 /* Now construct the string using the chosen lengths */
2599 ndx = name1chars;
2600 if (name2)
2601 {
2602 name[ndx++] = '_';
2604 ndx += name2chars;
2605 }
2606 if (label)
2607 {
2608 name[ndx++] = '_';
2609 strcpy(name + ndx, label);
2610 }
2611 else
2612 name[ndx] = '\0';
2613
2614 return name;
2615}
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1212

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

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

◆ RemoveFunctionById()

void RemoveFunctionById ( Oid  funcOid)
extern

Definition at line 1314 of file functioncmds.c.

1315{
1316 Relation relation;
1317 HeapTuple tup;
1318 char prokind;
1319
1320 /*
1321 * Delete the pg_proc tuple.
1322 */
1324
1326 if (!HeapTupleIsValid(tup)) /* should not happen */
1327 elog(ERROR, "cache lookup failed for function %u", funcOid);
1328
1329 prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
1330
1331 CatalogTupleDelete(relation, &tup->t_self);
1332
1334
1335 table_close(relation, RowExclusiveLock);
1336
1337 pgstat_drop_function(funcOid);
1338
1339 /*
1340 * If there's a pg_aggregate tuple, delete that too.
1341 */
1342 if (prokind == PROKIND_AGGREGATE)
1343 {
1345
1347 if (!HeapTupleIsValid(tup)) /* should not happen */
1348 elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);
1349
1350 CatalogTupleDelete(relation, &tup->t_self);
1351
1353
1354 table_close(relation, RowExclusiveLock);
1355 }
1356}
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
void pgstat_drop_function(Oid proid)

References CatalogTupleDelete(), elog, ERROR, fb(), Form_pg_proc, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), pgstat_drop_function(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveObjects()

void RemoveObjects ( DropStmt stmt)
extern

Definition at line 53 of file dropcmds.c.

54{
55 ObjectAddresses *objects;
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;
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 {
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. */
103 if (!OidIsValid(namespaceId) ||
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 */
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:388
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:2132
bool isTempNamespace(Oid namespaceId)
Definition namespace.c:3721
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:138
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition xact.h:103

References AccessExclusiveLock, add_exact_object_address(), Assert, castNode, check_object_ownership(), does_not_exist_skipping(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), 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)
extern

Definition at line 446 of file operatorcmds.c.

447{
448 Relation relation;
451
453
455 if (!HeapTupleIsValid(tup)) /* should not happen */
456 elog(ERROR, "cache lookup failed for operator %u", operOid);
458
459 /*
460 * Reset links from commutator and negator, if any. In case of a
461 * self-commutator or self-negator, this means we have to re-fetch the
462 * updated tuple. (We could optimize away updates on the tuple we're
463 * about to drop, but it doesn't seem worth convoluting the logic for.)
464 */
465 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
466 {
467 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
468 if (operOid == op->oprcom || operOid == op->oprnegate)
469 {
472 if (!HeapTupleIsValid(tup)) /* should not happen */
473 elog(ERROR, "cache lookup failed for operator %u", operOid);
474 }
475 }
476
477 CatalogTupleDelete(relation, &tup->t_self);
478
480
481 table_close(relation, RowExclusiveLock);
482}

References CatalogTupleDelete(), elog, ERROR, fb(), Form_pg_operator, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), OidIsValid, OperatorUpd(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveStatisticsById()

void RemoveStatisticsById ( Oid  statsOid)
extern

Definition at line 817 of file statscmds.c.

818{
819 Relation relation;
820 Relation rel;
823 Oid relid;
824
825 /*
826 * Delete the pg_statistic_ext tuple. Also send out a cache inval on the
827 * associated table, so that dependent plans will be rebuilt.
828 */
830
832
833 if (!HeapTupleIsValid(tup)) /* should not happen */
834 elog(ERROR, "cache lookup failed for statistics object %u", statsOid);
835
837 relid = statext->stxrelid;
838
839 /*
840 * Delete the pg_statistic_ext_data tuples holding the actual statistical
841 * data. There might be data with/without inheritance, so attempt deleting
842 * both. We lock the user table first, to prevent other processes (e.g.
843 * DROP STATISTICS) from removing the row concurrently.
844 */
846
849
851
852 CatalogTupleDelete(relation, &tup->t_self);
853
855
856 /* Keep lock until the end of the transaction. */
857 table_close(rel, NoLock);
858
859 table_close(relation, RowExclusiveLock);
860}
END_CATALOG_STRUCT typedef FormData_pg_statistic_ext * Form_pg_statistic_ext
void RemoveStatisticsDataById(Oid statsOid, bool inh)
Definition statscmds.c:792

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

Referenced by doDeletion().

◆ RemoveStatisticsDataById()

void RemoveStatisticsDataById ( Oid  statsOid,
bool  inh 
)
extern

Definition at line 792 of file statscmds.c.

793{
794 Relation relation;
796
798
800 BoolGetDatum(inh));
801
802 /* We don't know if the data row for inh value exists. */
804 {
805 CatalogTupleDelete(relation, &tup->t_self);
806
808 }
809
810 table_close(relation, RowExclusiveLock);
811}

References BoolGetDatum(), CatalogTupleDelete(), fb(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache2(), table_close(), and table_open().

Referenced by RemoveStatisticsById(), and statext_store().

◆ RemoveTSConfigurationById()

void RemoveTSConfigurationById ( Oid  cfgId)
extern

Definition at line 1108 of file tsearchcmds.c.

1109{
1111 relMap;
1112 HeapTuple tup;
1114 SysScanDesc scan;
1115
1116 /* Remove the pg_ts_config entry */
1118
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
1128
1130
1131 /* Remove any pg_ts_config_map entries */
1133
1137 ObjectIdGetDatum(cfgId));
1138
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, fb(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by doDeletion().

◆ RemoveUserMapping()

Oid RemoveUserMapping ( DropUserMappingStmt stmt)
extern

Definition at line 1430 of file foreigncmds.c.

1431{
1432 ObjectAddress object;
1433 Oid useId;
1434 Oid umId;
1436 RoleSpec *role = (RoleSpec *) stmt->user;
1437
1438 if (role->roletype == ROLESPEC_PUBLIC)
1440 else
1441 {
1442 useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1443 if (!OidIsValid(useId))
1444 {
1445 /*
1446 * IF EXISTS specified, role not found and not public. Notice this
1447 * and leave.
1448 */
1449 elog(NOTICE, "role \"%s\" does not exist, skipping",
1450 role->rolename);
1451 return InvalidOid;
1452 }
1453 }
1454
1455 srv = GetForeignServerByName(stmt->servername, true);
1456
1457 if (!srv)
1458 {
1459 if (!stmt->missing_ok)
1460 ereport(ERROR,
1462 errmsg("server \"%s\" does not exist",
1463 stmt->servername)));
1464 /* IF EXISTS, just note it */
1466 (errmsg("server \"%s\" does not exist, skipping",
1467 stmt->servername)));
1468 return InvalidOid;
1469 }
1470
1473 ObjectIdGetDatum(srv->serverid));
1474
1475 if (!OidIsValid(umId))
1476 {
1477 if (!stmt->missing_ok)
1478 ereport(ERROR,
1480 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1481 MappingUserName(useId), stmt->servername)));
1482
1483 /* IF EXISTS specified, just note it */
1485 (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1486 MappingUserName(useId), stmt->servername)));
1487 return InvalidOid;
1488 }
1489
1490 user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
1491
1492 /*
1493 * Do the deletion
1494 */
1495 object.classId = UserMappingRelationId;
1496 object.objectId = umId;
1497 object.objectSubId = 0;
1498
1499 performDeletion(&object, DROP_CASCADE, 0);
1500
1501 return umId;
1502}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:279
@ DROP_CASCADE

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

Referenced by ProcessUtilitySlow().

◆ ResolveOpClass()

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

Definition at line 2296 of file indexcmds.c.

2298{
2299 char *schemaname;
2300 char *opcname;
2301 HeapTuple tuple;
2303 Oid opClassId,
2305
2306 if (opclass == NIL)
2307 {
2308 /* no operator class specified, so find the default */
2310 if (!OidIsValid(opClassId))
2311 ereport(ERROR,
2313 errmsg("data type %s has no default operator class for access method \"%s\"",
2315 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
2316 return opClassId;
2317 }
2318
2319 /*
2320 * Specific opclass name given, so look up the opclass.
2321 */
2322
2323 /* deconstruct the name list */
2324 DeconstructQualifiedName(opclass, &schemaname, &opcname);
2325
2326 if (schemaname)
2327 {
2328 /* Look in specific schema only */
2330
2331 namespaceId = LookupExplicitNamespace(schemaname, false);
2336 }
2337 else
2338 {
2339 /* Unqualified opclass name, so search the search path */
2341 if (!OidIsValid(opClassId))
2342 ereport(ERROR,
2344 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2347 }
2348
2349 if (!HeapTupleIsValid(tuple))
2350 ereport(ERROR,
2352 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
2354
2355 /*
2356 * Verify that the index operator class accepts this datatype. Note we
2357 * will accept binary compatibility.
2358 */
2359 opform = (Form_pg_opclass) GETSTRUCT(tuple);
2360 opClassId = opform->oid;
2361 opInputType = opform->opcintype;
2362
2364 ereport(ERROR,
2366 errmsg("operator class \"%s\" does not accept data type %s",
2368
2369 ReleaseSysCache(tuple);
2370
2371 return opClassId;
2372}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2381
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition namespace.c:2190
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition namespace.c:3457

References DeconstructQualifiedName(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), Form_pg_opclass, 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)
extern

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
1609 pfree(buf.data);
1610 return result;
1611}
#define ESCAPE_STRING_SYNTAX
Definition c.h:1314
#define SQL_STR_DOUBLE(ch, escape_backslash)
Definition c.h:1311
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:375
static char buf[DEFAULT_XLOG_SEG_SIZE]
const char * quote_identifier(const char *ident)
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
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:196

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, cstring_to_text_with_len(), defGetString(), ESCAPE_STRING_SYNTAX, fb(), initStringInfo(), IsA, lfirst, lnext(), pfree(), quote_identifier(), result, SQL_STR_DOUBLE, and val.

Referenced by AlterTSDictionary(), and DefineTSDictionary().

◆ StatisticsGetRelation()

Oid StatisticsGetRelation ( Oid  statId,
bool  missing_ok 
)
extern

Definition at line 968 of file statscmds.c.

969{
970 HeapTuple tuple;
972 Oid result;
973
975 if (!HeapTupleIsValid(tuple))
976 {
977 if (missing_ok)
978 return InvalidOid;
979 elog(ERROR, "cache lookup failed for statistics object %u", statId);
980 }
982 Assert(stx->oid == statId);
983
984 result = stx->stxrelid;
985 ReleaseSysCache(tuple);
986 return result;
987}

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

Referenced by ATPostAlterTypeCleanup().

◆ transformGenericOptions()

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

Definition at line 121 of file foreigncmds.c.

125{
129
130 foreach(optcell, options)
131 {
133 ListCell *cell;
134
135 /*
136 * Find the element in resultOptions. We need this for validation in
137 * all cases.
138 */
139 foreach(cell, resultOptions)
140 {
141 DefElem *def = lfirst(cell);
142
143 if (strcmp(def->defname, od->defname) == 0)
144 break;
145 }
146
147 /*
148 * It is possible to perform multiple SET/DROP actions on the same
149 * option. The standard permits this, as long as the options to be
150 * added are unique. Note that an unspecified action is taken to be
151 * ADD.
152 */
153 switch (od->defaction)
154 {
155 case DEFELEM_DROP:
156 if (!cell)
159 errmsg("option \"%s\" not found",
160 od->defname)));
162 break;
163
164 case DEFELEM_SET:
165 if (!cell)
168 errmsg("option \"%s\" not found",
169 od->defname)));
170 lfirst(cell) = od;
171 break;
172
173 case DEFELEM_ADD:
174 case DEFELEM_UNSPEC:
175 if (cell)
178 errmsg("option \"%s\" provided more than once",
179 od->defname)));
181 break;
182
183 default:
184 elog(ERROR, "unrecognized action %d on option \"%s\"",
185 (int) od->defaction, od->defname);
186 break;
187 }
188 }
189
191
192 if (OidIsValid(fdwvalidator))
193 {
195
196 /*
197 * Pass a null options list as an empty array, so that validators
198 * don't have to be declared non-strict to handle the case.
199 */
202 OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
203 }
204
205 return result;
206}
ArrayType * construct_empty_array(Oid elmtype)
#define OidFunctionCall2(functionId, arg1, arg2)
Definition fmgr.h:728
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:853
@ DEFELEM_DROP
Definition parsenodes.h:856
@ DEFELEM_SET
Definition parsenodes.h:854
@ DEFELEM_ADD
Definition parsenodes.h:855
List * untransformRelOptions(Datum options)

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

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